No se trata de eficiencia, se trata de corrección. basenameusa líneas nuevas para delimitar los nombres de archivo que imprime. En el caso habitual, cuando solo pasa un nombre de archivo, agrega una nueva línea final a su salida. Dado que los nombres de archivo pueden contener nuevas líneas, esto dificulta el manejo correcto de estos nombres de archivo.
Se complica aún más por el hecho de que la gente utiliza generalmente basenamecomo esto: "$(basename "$file")". Esto hace que las cosas aún más difícil, porque $(command)tiras todos los saltos de línea finales de command. Considere el caso poco probable que $filetermina con una nueva línea. Luego basenameagregará una nueva línea adicional, pero "$(basename "$file")"eliminará ambas líneas nuevas, dejándolo con un nombre de archivo incorrecto.
Otro problema basenamees que si $filecomienza con un -(guión aka menos), se interpretará como una opción. Este es fácil de arreglar:$(basename -- "$file")
La forma robusta de usar basenamees 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%??}"
Una alternativa es usarla ${file##*/}, que es más fácil pero tiene errores propios. En particular, está mal en los casos donde $filees /o foo/.