2013-03-02 12 views
27

Dlaczego„bash: Bad podstawienie” przy użyciu kodu w pliku .sh

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

pracy, jeśli mogę użyć go w konsoli, ale daje mi „Bad podstawienie” błąd, jeśli mogę użyć tego samego kodu w pliku .sh?

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

Czy używasz skryptu #!/Bin/sh lub #!/Bin/bash? –

+1

W konsoli polecenia zostały wykonane przez powłokę 'bash'. Jeśli używasz '#!/Bin/sh' w swoim skrypcie, to' sh' shell próbuje wykonać, a tym samym błąd. – jitendra

+0

Napisałem #!/Bin/sh w pierwszym wierszu ... – WhatIsName

Odpowiedz

51

Znaczenie #!/bin/sh

To dlatego, że używasz #!/bin/sh w skrypcie, jako poprawki powinna go zmienić na #!/bin/bash.

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

Ludzie korzystają #!/bin/sh przy użyciu jedynie ograniczony zestaw funkcji (zdefiniowaną przez standard POSIX) dla maksymalnej przenośności. #!/bin/bash jest całkowicie w porządku dla skryptów użytkownika. /bin/sh jest zwykle dowiązany do minimalnej powłoki zgodnej z POSIX lub do standardowej powłoki (np. Bash). W drugim przypadku bash prowadzony jest w trybie zgodności, co zostało wyjaśnione w manpage:

Jeżeli bash wywoływany jest pod nazwą sh, próbuje naśladować zachowanie startowe historycznych wersji sh tak ściśle, jak to możliwe, jednocześnie zgodny ze standardem POSIX.

Proponowane zmiany w skrypcie:

  • Uważa się dobra praktyka, aby korzystać w cudzysłowie zmiennych ("$i" zamiast $i). Zaprotokołowane zmienne zapobiegną problemom, jeśli zapisana nazwa pliku zawiera białe spacje.
  • Podoba mi się, że używasz zaawansowanego parameter expansion. Proponuję użyć "${i%.mp4}.mp3" (zamiast "${i/.mp4/.mp3}"), ponieważ tylko zastępuje na końcu (na przykład plik o nazwie foo.mp4.backup).
+0

+1 - zależy to również od sposobu, w jaki jest wykonywany, I.E. Nie możesz zadeklarować jako '#!/Bin/bash', a następnie wywołać' sh' lub zadeklarować jako '#!/Bin/sh' i wywołać' bash', przynajmniej na Debianie 7 zobaczysz błąd na obu . Deklaracja musi odpowiadać inwokacji. – webLacky3rdClass

+0

@CharlesDuffy To była literówka/zamieszanie, prawdopodobnie miałem na myśli cytaty. –

+0

Myślę, że użycie '#!/Usr/bin/env bash' byłoby lepszym sposobem. – Hozefa

9

Konstrukcja ${var/x/y/} nie jest POSIX. W przypadku, gdzie można po prostu usunąć ciąg na końcu zmiennej i przyczepność na inny ciąg, przenośne rozwiązanie POSIX jest użycie

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

lub nawet krócej, ffmpeg -i "$i" "${i%4}3".

Ostateczną dawką dla tych konstrukcji jest rozdział o Parameter Expansion for the POSIX shell.