Warum wird meine bash-code fail, wenn ich es mit sh?
Habe ich eine Zeile code, der funktioniert gut in meinem terminal:
for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
Dann legte ich den genau gleiche code-Zeile in ein Skript myscript.sh
:
#!/bin/sh
for i in *.mp4; do echo ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
Aber jetzt bekomme ich beim ausführen einen Fehler es:
$ sh myscript.sh
myscript.sh: 2: myscript.sh: Bad substitution
Basierend auf anderen Fragen, die ich versucht, die änderung der shebang zu #!/bin/bash
, aber ich bekomme den exakt gleichen Fehler. Warum kann ich nicht dieses Skript ausführen?
- Sind Sie mit #!/bin/sh oder #!/bin/bash aus dem Skript?
- In der Konsole werden die Befehle wurden ausgeführt, indem
bash
shell. Wenn Sie mit#!/bin/sh
im Skript, es istsh
shell versucht auszuführen, und daher der Fehler. - Ich schrieb #!/bin/sh in der ersten Zeile...
- ${foo/bar/baz} ist nicht POSIX, und daher funktionieren möglicherweise nicht mit Ihrem /bin/sh. Verwenden
#!/bin/bash
statt. @MichaWiedenmann sollte zeigen, dass so eine Antwort. - OK, wenn ich es ausführen mit bash statt sh es funktioniert.
- Finden Sie heraus, welche sh die Sie verwenden:
readlink -f $(which sh)
Du musst angemeldet sein, um einen Kommentar abzugeben.
TL;DR: Da Sie mit
bash
Besonderheiten, hat Ihr Skript die Ausführung mitbash
und nicht mitsh
:Sehen Unterschied zwischen sh und bash. Finden Sie heraus, welche sh die Sie verwenden:
readlink -f $(which sh)
.Der beste Weg, um sicherzustellen, eine bash-spezifische Skript läuft immer richtig
Die besten Methoden sind, um beide:
#!/bin/sh
mit#!/bin/bash
(oder welche andere shell Ihr script hängt)../myscript.sh
oder/path/to/myscript.sh
, ohne führendesh
oderbash
.Hier ein Beispiel:
(Bezug: Warum ./vor-Skripte?)
Die Bedeutung von
#!/bin/sh
Den Kram schlägt die shell sollte das system verwenden, um ein Skript auszuführen. Hiermit können Sie angeben
#!/usr/bin/python
oder#!/bin/bash
so dass Sie nicht haben, sich daran zu erinnern, das Skript ist geschrieben in welcher Sprache.Menschen nutzen
#!/bin/sh
wenn Sie nur eine begrenzte Anzahl von Funktionen (definiert durch den POSIX-standard) für maximale Portabilität.#!/bin/bash
ist perfekt für die user-Skripte, nutzen Sie nützliche bash-Erweiterungen./bin/sh
ist in der Regel symlinked entweder eine minimale POSIX-konforme shell-oder standard-shell (z.B. bash). Auch im letzteren Fall#!/bin/sh
fehlschlagen, weilbash
wil im Kompatibilitätsmodus ausführen, wie in der manpage:Die Bedeutung von
sh myscript.sh
Shebang wird nur verwendet, wenn Sie ausführen
./myscript.sh
,/path/to/myscript.sh
oder wenn Sie die drop-Erweiterung, legen Sie das Skript in ein Verzeichnis in Ihrem$PATH
, und führen Sie einfachmyscript
.Wenn Sie ausdrücklich angeben, dass eine Dolmetscherin, die Dolmetscherin verwendet werden.
sh myscript.sh
zwingen wird, es zu laufen, mitsh
, egal was das Programm sagt. Dies ist der Grund, warum die änderung der shebang ist nicht genug.Sollten Sie immer führen Sie das Skript mit seiner bevorzugten interpreter, also lieber
./myscript.sh
oder ähnliches, wenn Sie execute any script.Andere vorgeschlagene änderungen an Ihrem Skript:
"$i"
statt$i
). Zitiert Variablen verhindern, dass Probleme auftreten, wenn die gespeicherte Datei name enthält Leerzeichen."${i%.mp4}.mp3"
(statt"${i/.mp4/.mp3}"
), da${parameter%word}
nur ersetzt, am Ende (zum Beispiel eine Datei mit dem Namenfoo.mp4.backup
).#!/bin/bash
rufen Sie dann mitsh
Oder erklären, wie#!/bin/sh
und aufrufen, mitbash
zumindest auf Debian 7 sehen Sie eine Fehler auf beiden. Die Erklärung übereinstimmen muss der Aufruf.#!/usr/bin/env bash
wäre ein besserer Weg.readlink -f $(which sh)
Den
${var/x/y/}
Konstrukt ist nicht POSIX. In Ihrem Fall, wo Sie einfach entfernen Sie eine Zeichenfolge an das Ende einer Variablen und tack auf einem anderen string, portable POSIX-Lösung ist die Verwendungoder sogar kürzer,
ffmpeg -i "$i" "${i%4}3"
.Die endgültige dope für diese Konstrukte ist das Kapitel über Parameter-Erweiterung für die POSIX-shell.