scripts script resueltos programas paso pasar parametros hacer español ejercicios ejemplos como bash sh substitution

bash - programas - scripts linux ejercicios resueltos



¿Por qué mi código bash falla cuando lo ejecuto con sh? (2)

Tengo una línea de código que funciona bien en mi terminal:

for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done

Luego puse exactamente la misma línea de código en un script myscript.sh :

#!/bin/sh for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done

Sin embargo, ahora recibo un error al ejecutarlo:

$ sh myscript.sh myscript.sh: 2: myscript.sh: Bad substitution

Basado en otras preguntas intenté cambiar el shebang a #!/bin/bash , pero obtengo exactamente el mismo error. ¿Por qué no puedo ejecutar este script?


El constructo ${var/x/y/} no es POSIX. En su caso, donde simplemente elimina una cadena al final de una variable y pega otra cuerda, la solución portátil POSIX es usar

#!/bin/sh for i in *.mp4; do ffmpeg -i "$i" "${i%.mp4}.mp3" done

o incluso más corto, ffmpeg -i "$i" "${i%4}3" .

La droga definitiva para estas construcciones es el capítulo sobre Expansión de parámetros para el shell POSIX .


TL; DR: Como usas funciones específicas de bash , tu script debe ejecutarse con bash y no con sh :

$ sh myscript.sh myscript.sh: 2: myscript.sh: Bad substitution $ bash myscript.sh ffmpeg -i bar.mp4 bar.mp3 ffmpeg -i foo.mp4 foo.mp3

bash es básicamente sh qué C ++ es a C. Ver diferencia entre sh y bash .

La mejor forma de garantizar que un script específico de bash siempre se ejecute correctamente

Las mejores prácticas son para ambos :

  1. Reemplace #!/bin/sh con #!/bin/bash (o cualquier otro shell del que dependa su script).
  2. Ejecute este script (¡y todos los demás!) Con ./myscript.sh o /path/to/myscript.sh , sin un sh o bash /path/to/myscript.sh .

Aquí hay un ejemplo:

$ cat myscript.sh #!/bin/bash for i in *.mp4 do echo ffmpeg -i "$i" "${i/.mp4/.mp3}" done $ chmod +x myscript.sh # Ensure script is executable $ ./myscript.sh ffmpeg -i bar.mp4 bar.mp3 ffmpeg -i foo.mp4 foo.mp3

(Relacionado: ¿Por qué ./ delante de las secuencias de comandos? )

El significado de #!/bin/sh

El shebang sugiere qué shell debe usar el sistema para ejecutar un script. Esto le permite especificar #!/usr/bin/python o #!/bin/bash para que no tenga que recordar qué script está escrito en qué idioma.

Las personas usan #!/bin/sh cuando solo usan un conjunto limitado de características (definidas por el estándar POSIX) para una máxima portabilidad. #!/bin/bash está perfectamente bien para las secuencias de comandos del usuario que aprovechan las útiles extensiones de bash.

/bin/sh suele enlazarse simbólicamente con un shell mínimo compatible con POSIX o con un shell estándar (por ejemplo, bash). Incluso en el último caso, #!/bin/sh puede fallar porque bash ejecutará en modo de compatibilidad como se explica en la página de manpage :

Si bash se invoca con el nombre sh, intenta imitar el comportamiento de inicio de las versiones históricas de sh lo más cerca posible, al mismo tiempo que se ajusta al estándar POSIX.

El significado de sh myscript.sh

El shebang solo se usa cuando ejecuta ./myscript.sh , /path/to/myscript.sh , o cuando suelta la extensión, coloque el script en un directorio en su $PATH , y simplemente ejecute myscript .

Si especifica explícitamente un intérprete, se usará ese intérprete. sh myscript.sh lo forzará a funcionar con sh , no importa lo que diga el shebang. Esta es la razón por la cual cambiar el shebang no es suficiente por sí mismo.

Siempre debe ejecutar el script con su intérprete preferido, así que prefiera ./myscript.sh o similar cada vez que ejecute un script.

Otros cambios sugeridos a su secuencia de comandos:

  • Se considera una buena práctica citar variables ( "$i" lugar de $i ). Las variables citadas evitarán problemas si el nombre del archivo almacenado contiene caracteres de espacio en blanco.
  • Me gusta que uses la manpage avanzada de manpage . Sugiero usar "${i%.mp4}.mp3" (en lugar de "${i/.mp4/.mp3}" ), ya que ${parameter%word} solo sustituye al final (por ejemplo, un archivo llamado foo.mp4.backup ).