No se trata de eficiencia, se trata de corrección. basename
usa 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 basename
como 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 $file
termina con una nueva línea. Luego basename
agregará una nueva línea adicional, pero "$(basename "$file")"
eliminará ambas líneas nuevas, dejándolo con un nombre de archivo incorrecto.
Otro problema basename
es que si $file
comienza 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 basename
es 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 $file
es /
o foo/
.