I have this code:
get_base() { echo "${1##*/}"; }
And this works fine until we have 1 or more trailing slashes
I have found a solution on how to fix it, but the
problem is that we'll need extglob
enabled, and I don't
want that:
ari@ari-gentoo ~ % x='/home/ari///'
ari@ari-gentoo ~ % echo "${x%%+(/)}"
/home/ari
Then we can obv save it into a tmp var and run the basename substitution on it
Anyway, my question is, is there any proper way to do it and it still being fast (meaning no calls to external commands because this function gets called quite a lot) without needing any fancy features enabled?
Thanks for the answers in advance :)
no as all of those solutions either use commands or have a substitution expression that only strips the last slash, not multiples :) (e.g. /home/ari/// with expr ${x%/} would become only /home/ari// when it needs to be /home/ari)
By proper I mean 'achieved without enabling extglob or any other fancy features'
A fast and proper way to get ... in bash
In complement to oguz ismail's correct answer I would like to suggest use of -v
flag for this kind of function, in order to reduce forks:
get_base() {
if [[ $1 == -v ]] ;then
local -n _res=$2
shift 2
else
local _res
fi
set -- "${1%"${1##*[!/]}"}"
printf -v _res %s "${1##*/}"
[[ ${_res@A} == _res=* ]] && echo "$_res"
}
This let you try this function by
$ get_base /path/entry////
entry
But for storing result into some variable, you would avoid useless fork like
myvar=$(get_base /path/entry////)
and use prefered syntax:
$ get_base -v myvar /path/entry////
$ echo $myvar
entry
entry
and path
:get_base() {
if [[ $1 == -v ]] ;then
local -n _res=$2
shift 2
else
local _res
fi
set -- "${1%"${1##*[!/]}"}"
printf -v _res %s "${1##*/}"
[[ ${_res@A} == _res=* ]] &&
echo "$_res" "${1%/$_res}" && return
printf -v _res[1] %s "${1%/$_res}"
}
Then:
$ get_base /path/to/entry////
entry /path/to
and
$ get_base -v myvar /path/to/entry////
$ declare -p myvar
declare -a myvar=([0]="entry" [1]="/path/to")
$ echo ${myvar[0]}
entry
$ echo ${myvar[1]}
/path/to
With spaced unicode filenames:
$ get_base -v myvar '/path/to/some dir/some loved file ♥♥♥.xtns'
$ declare -p myvar
declare -a myvar=([0]="some loved file ♥♥♥.xtns" [1]="/path/to/some dir")