shellcheck recomienda no utilizar nombre base: ¿por qué?

shellcheck recomienda no utilizar nombre base: ¿por qué?

estoy probandochequeo de concha.

tengo algo asi

basename "${OPENSSL}" 

y me sale la siguiente sugerencia

Use parameter expansion instead, such as ${var##*/}.

Desde el punto de vista práctico no veo ninguna diferencia.

$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl

ya que basenameesta en elEspecificaciones POSIX, No tengo ninguna razón por la que deba ser una mejor práctica. ¿Alguna pista?

Respuesta1

No se trata de eficiencia, sino de corrección. basenameutiliza nuevas líneas para delimitar los nombres de archivos 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 archivos pueden contener nuevas líneas, esto dificulta el manejo correcto de estos nombres de archivos.

Se complica aún más por el hecho de que la gente suele utilizar basenamealgo así: "$(basename "$file")". Esto complica aún más las cosas, porque $(command)las tirastodonuevas líneas finales de command. Considere el caso improbable que $filetermina con una nueva línea. Luego basenameagregará una nueva línea adicional, pero "$(basename "$file")"la eliminará.ambosnuevas líneas, dejándote con un nombre de archivo incorrecto.

Otro problema basenamees que si $filecomienza con un -(guión también conocido como menos), se interpretará como una opción. Este es fácil de arreglar:$(basename -- "$file")

La forma robusta de uso 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 usar ${file##*/}, que es más fácil pero tiene sus propios errores. En particular, está mal en los casos en los que $fileis /o foo/.

Respuesta2

Las líneas relevantes en shellcheck'scódigo fuenteson:

checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "dirname" =
    style id "Use parameter expansion instead, such as ${var%/*}."
checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "basename" =
    style id "Use parameter expansion instead, such as ${var##*/}."
checkNeedlessCommands _ = return ()

No se da ninguna explicación explícita, 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.

Respuesta3

dirname, basenameetc. readlink(gracias @Marco, esto está corregido) pueden crear problemas de portabilidad cuando la seguridad se vuelve importante (lo que requiere seguridad de la ruta). Muchos sistemas (como Fedora Linux) lo colocan en /binmientras que otros (como Mac OSX) lo colocan en /usr/bin. Luego está Bash en Windows, por ejemplo, cygwin, msys y otros. Siempre es mejor permanecer puro Bash, cuando sea posible.(según el comentario de @Marco)

Por cierto, gracias por el puntero a Shellcheck, no lo había visto antes.

información relacionada