2013-03-02 8 views
27

Perché"bash: Bad sostituzione" quando si utilizza il codice nel file di .sh

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

lavoro, se lo uso in console, ma mi danno un errore "sostituzione", se uso lo stesso codice in un file .sh?

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

Stai utilizzando #!/Bin/sh o #!/Bin/bash dallo script? –

+1

Nella console, i comandi sono stati eseguiti dalla shell 'bash'. Se stai usando '#!/Bin/sh' nel tuo script, è la shell' sh' che sta cercando di eseguire e quindi l'errore. – jitendra

+0

Ho scritto #!/Bin/sh nella prima riga ... – WhatIsName

risposta

51

Il significato di #!/bin/sh

Questo perché si sta utilizzando #!/bin/sh nello script, come una correzione si dovrebbe cambiare a #!/bin/bash.

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

persone utilizzano #!/bin/sh quando il solo uso di un numero limitato di funzionalità (definita dallo standard POSIX) per la massima portabilità. #!/bin/bash è perfettamente adatto per gli script utente. /bin/sh è in genere un collegamento simbolico a una shell conforme a POSIX minima oa una shell standard (ad es. Bash). In quest'ultimo caso bash viene eseguito in modalità di compatibilità, che è spiegato nella manpage:

Se bash è invocata col nome sh, cerca di imitare il più fedelmente l'ambiente di avvio della versione storica di sh il più possibile, pur essendo conforme allo standard POSIX.

modifiche suggerite per lo script:

  • È considerata buona norma usare le virgolette attorno variabili ("$i" invece di $i). Le variabili citate prevengono problemi se il nome del file memorizzato contiene caratteri di spazio bianco.
  • Mi piace l'uso avanzato parameter expansion. Suggerisco di utilizzare "${i%.mp4}.mp3" (anziché "${i/.mp4/.mp3}"), dal ${parameter%word} solo sostituti alla fine (ad esempio un file denominato foo.mp4.backup).
+0

+1 - Dipende anche dal modo in cui viene eseguito, I.E. Non puoi dichiarare come '#!/Bin/bash', quindi invocare con' sh' o dichiarare come '#!/Bin/sh' e invocare con' bash', almeno su Debian 7 vedrai un errore su entrambi . La dichiarazione deve corrispondere all'invocazione. – webLacky3rdClass

+0

@CharlesDuffy Quello era un errore di battitura/confusione, probabilmente intendevo virgolette. –

+0

Penso che usare '#!/Usr/bin/env bash' sarebbe un modo migliore. – Hozefa

9

Il costrutto ${var/x/y/} non è POSIX. Nel tuo caso, in cui è sufficiente rimuovere una stringa alla fine di una variabile e virare su un'altra stringa, la soluzione portatile POSIX è quella di utilizzare

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

o anche più breve, ffmpeg -i "$i" "${i%4}3".

Il dope definitivo per questi costrutti è il capitolo Parameter Expansion for the POSIX shell.

Problemi correlati