TL; DR:Bash固有の機能を使用しているため、スクリプトはsh
:ではなくBashで実行する必要があります。
$ 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
shとBashの違いを参照してください。使用しているshを見つけるには:readlink -f $(which sh)
。
bash固有のスクリプトが常に正しく実行されるようにするための最良の方法
ベストプラクティスは両方にあります:
- (またはスクリプトが依存する他のシェル)に
#!/bin/sh
置き換えます。#!/bin/bash
- このスクリプト(および他のすべてのスクリプト)を、
./myscript.sh
または/path/to/myscript.sh
で、先頭にsh
またはを付けずに実行しますbash
。
次に例を示します。
$ 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
(関連:なぜ./スクリプトの前にあるのですか?)
の意味#!/bin/sh
シバンは、システムがスクリプトを実行するために使用するシェルを提案します。これにより、#!/usr/bin/python
またはを指定できる#!/bin/bash
ため、どのスクリプトがどの言語で書かれているかを覚えておく必要がありません。
#!/bin/sh
移植性を最大化するために、限られた機能セット(POSIX標準で定義されている)のみを使用する場合に使用します。#!/bin/bash
便利なbash拡張機能を利用するユーザースクリプトにはまったく問題ありません。
/bin/sh
通常、最小限のPOSIX準拠シェルまたは標準シェル(bashなど)のいずれかにシンボリックリンクされます。後者の場合でも、マニュアルページで説明されているように互換モードで実行される#!/bin/sh
ため、失敗する可能性があります。bash
bashがshという名前で呼び出された場合、POSIX標準にも準拠しながら、shの履歴バージョンの起動動作を可能な限り模倣しようとします。
の意味sh myscript.sh
shebangは、、を実行する場合、または拡張機能を削除し、スクリプトをのディレクトリに配置して、を実行する場合にのみ使用./myscript.sh
さ/path/to/myscript.sh
れ$PATH
ますmyscript
。
インタプリタを明示的に指定すると、そのインタプリタが使用されます。シェバンが何を言おうと、sh myscript.sh
それを強制的に実行します。sh
これが、シェバンを変更するだけでは不十分な理由です。
スクリプトは常に優先インタープリターを使用して実行する必要があるため、スクリプトを実行するときは常に優先./myscript.sh
または同様の方法で実行してください。
スクリプトに対するその他の提案された変更:
"$i"
(の代わりに)変数を引用することをお勧めします$i
。保存されたファイル名に空白文字が含まれている場合、引用符で囲まれた変数は問題を防ぎます。
- 高度なパラメータ拡張を使用するのが好きです。最後に(たとえば、という名前のファイル)を置き換えるだけなので、
"${i%.mp4}.mp3"
(の代わりに"${i/.mp4/.mp3}"
)を使用することをお勧めします。${parameter%word}
foo.mp4.backup