Não se trata de eficiência, é sobre correção. basename
usa novas linhas para delimitar os nomes dos 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 manuseio correto desses nomes de arquivos.
É ainda mais complicado pelo fato de as pessoas geralmente usarem basename
assim: "$(basename "$file")
". Isso dificulta ainda mais as coisas, porque $(command)
retira todas as últimas linhas de command
Considere o caso improvável de que $file
termine com uma nova linha. Então, basename
adicionará uma nova linha extra, mas "$(basename "$file")"
removerá ambas novas linhas, deixando você com um nome de arquivo incorreto.
Outro problema com basename
é que, se $file
começar com -
(traço a.k.a. 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##*/}
, que é mais fácil, mas tem erros próprios. Em particular, está errado nos casos em que $file
é /
ou foo/
.