Estoy probando shellcheck .
Tengo algo asi
basename "${OPENSSL}"
y recibo la siguiente sugerencia
Use parameter expansion instead, such as ${var##*/}.
Desde el punto de vista práctico no veo diferencia
$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl
Como basename
está en las especificaciones POSIX , no sé por qué debería ser la mejor práctica. Alguna pista?
csh
. Supongocsh
que no es POSIX entonces.Respuestas:
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 decommand
. Considere el caso poco probable que$file
termina con una nueva línea. Luegobasename
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: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/
ofoo/
.fuente
$file
es asífoo/
? ¿Y si es así/
?basename
enfoque es mejor, después de todo, tan hacky como es. Las mejores alternativas que se me ocurren son${${${file}%%/#}##*/}
y[[ $file =~ "([^/]*)/*$" ]] && printf "%s" $match[1]
, las cuales son específicas de zsh y ninguna de las cuales se maneja/
correctamente.Las líneas relevantes en
shellcheck
el código fuente son:No se proporciona ninguna explicación explícitamente, pero según el nombre de la función (
checkNeedlessCommands
) parece que @jordanm tiene toda la razón y sugiere que evite bifurcar un nuevo proceso.fuente
dirname
,basename
,readlink
Etc (gracias @Marco - esto se corrige) pueden crear problemas de portabilidad cuando la seguridad se vuelve importante (que requiere la seguridad de la ruta). Muchos sistemas (como Fedora Linux) lo ubican/bin
mientras que otros (como Mac OSX) lo ubican/usr/bin
. Luego está Bash en Windows, por ejemplo, cygwin, msys y otros.Siempre es mejor mantenerse puro Bash, cuando sea posible.(por comentario de @Marco)Por cierto, gracias por el puntero para comprobar, no he visto eso antes.
fuente
dirname
en absoluto. 3) Las utilidades básicas básicas deben estar en la RUTA, donde sea que estén almacenadas. Todavía no he visto un sistema dondebasename
no estaba en la RUTA. 4) Asumir que bash está disponible es un problema de portabilidad. Siempre es mejor mantenerse alejado de bash y usar un shell POSIX cuando se requiere portabilidad.posix
y nobash
. No encuentro ningún indicador de que el OP requiera una solución bash. Su afirmación "Siempre es mejor mantenerse puro Bash" es simplemente incorrecta, lo siento.