Não se trata de eficiência - é de correção. basename
usa novas linhas para delimitar os nomes de arquivos impressos. No caso usual, quando você passa apenas um nome de arquivo, ele adiciona uma nova linha à sua saída. Como os nomes de arquivos podem conter novas linhas, isso dificulta o tratamento correto desses nomes de arquivo.
É ainda mais complicada pelo fato de que as pessoas geralmente usam basename
como este: "$(basename "$file")"
. Isso torna as coisas ainda mais difíceis, porque $(command)
retira todas as novas linhas finais command
. Considere o caso improvável que $file
termina com uma nova linha. Em seguida, basename
irá adicionar uma nova linha extra, mas "$(basename "$file")"
irá retirar as duas novas linhas, deixando-o com um nome de arquivo incorreto.
Outro problema basename
é que, se $file
começar com um -
(traço aka menos), ele será interpretado como uma opção. Este é fácil de corrigir:$(basename -- "$file")
A maneira robusta de usar basename
é esta:
# A file with three trailing newlines.
file=$'/tmp/evil\n\n\n'
# Add an 'x' so we can tell where $file's newlines end and basename's begin.
file_x="$(basename -- "$file"; printf x)"
# Strip off two trailing characters: the 'x' added by us and the newline added by basename.
base="${file_x%??}"
Uma alternativa é usar ${file##*/}
, o que é mais fácil, mas possui bugs próprios. Em particular, está errado nos casos em que $file
é /
ou foo/
.