The next script
str=/aaa/bbb/ccc.txt echo "str: $str" echo ${str##*/} == $(basename $str) echo ${str%/*} == $(dirname $str)
produces:
str: /aaa/bbb/ccc.txt ccc.txt == ccc.txt /aaa/bbb == /aaa/bbb
The question is:
dirname
and basename
and when the variable substitutions and why?Asking mainly because:
str="/aaa/bbb/ccc.txt" count=10000 s_cmdbase() { let i=0 while(( i++ < $count )) do a=$(basename $str) done } s_varbase() { let i=0 while(( i++ < $count )) do a=${str##*/} done } s_cmddir() { let i=0 while(( i++ < $count )) do a=$(dirname $str) done } s_vardir() { let i=0 while(( i++ < $count )) do a=${str%/*} done } time s_cmdbase echo command basename echo =================================== time s_varbase echo varsub basename echo =================================== time s_cmddir echo command dirname echo =================================== time s_vardir echo varsub dirname
on my system produces:
real 0m33.455s user 0m10.194s sys 0m18.106s command basename =================================== real 0m0.246s user 0m0.237s sys 0m0.007s varsub basename =================================== real 0m30.562s user 0m10.115s sys 0m17.764s command dirname =================================== real 0m0.237s user 0m0.226s sys 0m0.007s varsub dirname
Calling external programs (forking) costs time. The main point of the question is:
The external commands make some logical corrections. Check the result of the next script:
doit() { str=$1 echo -e "string $str" cmd=basename [[ "${str##*/}" == "$($cmd $str)" ]] && echo "$cmd same: ${str##*/}" || echo -e "$cmd different \${str##*/}\t>${str##*/}<\tvs command:\t>$($cmd $str)<" cmd=dirname [[ "${str%/*}" == "$($cmd $str)" ]] && echo "$cmd same: ${str%/*}" || echo -e "$cmd different \${str%/*}\t>${str%/*}<\tvs command:\t>$($cmd $str)<" echo } doit /aaa/bbb/ doit / doit /aaa doit aaa doit aaa/ doit aaa/xxx
with the result
string /aaa/bbb/ basename different ${str##*/} >< vs command: >bbb< dirname different ${str%/*} >/aaa/bbb< vs command: >/aaa< string / basename different ${str##*/} >< vs command: >/< dirname different ${str%/*} >< vs command: >/< string /aaa basename same: aaa dirname different ${str%/*} >< vs command: >/< string aaa basename same: aaa dirname different ${str%/*} >aaa< vs command: >.< string aaa/ basename different ${str##*/} >< vs command: >aaa< dirname different ${str%/*} >aaa< vs command: >.< string aaa/xxx basename same: xxx dirname same: aaa
One of most interesting results is the $(dirname "aaa")
. The external command dirname
correctly returns .
but the variable expansion ${str%/*}
returns the incorrect value aaa
.
Script:
doit() { strings=( "[[$1]]" "[[$(basename "$1")]]" "[[${1##*/}]]" "[[$(dirname "$1")]]" "[[${1%/*}]]" ) printf "%-15s %-15s %-15s %-15s %-15s\n" "${strings[@]}" } printf "%-15s %-15s %-15s %-15s %-15s\n" \ 'file' 'basename $file' '${file##*/}' 'dirname $file' '${file%/*}' doit /aaa/bbb/ doit / doit /aaa doit aaa doit aaa/ doit aaa/xxx doit aaa//
Output:
file basename $file ${file##*/} dirname $file ${file%/*} [[/aaa/bbb/]] [[bbb]] [[]] [[/aaa]] [[/aaa/bbb]] [[/]] [[/]] [[]] [[/]] [[]] [[/aaa]] [[aaa]] [[aaa]] [[/]] [[]] [[aaa]] [[aaa]] [[aaa]] [[.]] [[aaa]] [[aaa/]] [[aaa]] [[]] [[.]] [[aaa]] [[aaa/xxx]] [[xxx]] [[xxx]] [[aaa]] [[aaa]] [[aaa//]] [[aaa]] [[]] [[.]] [[aaa/]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With