Почему
for i in *.mp4; do ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
работать, если я использую его в консоли, но даю мне ошибку "Bad substitution", если я использую тот же код в файле .sh?
for i in *.mp4
do
ffmpeg -i "$i" "${i/.mp4/.mp3}"
done
Почему
for i in *.mp4; do ffmpeg -i "$i" "${i/.mp4/.mp3}"; done
работать, если я использую его в консоли, но даю мне ошибку "Bad substitution", если я использую тот же код в файле .sh?
for i in *.mp4
do
ffmpeg -i "$i" "${i/.mp4/.mp3}"
done
Значение #!/bin/sh
Это потому, что вы используете #!/bin/sh в своем script, в качестве исправления вы должны изменить его на #!/bin/bash.
#!/bin/bash
for i in *.mp4
do
ffmpeg -i "$i" "${i/.mp4/.mp3}"
done
Люди используют #!/bin/sh, когда используют только ограниченный набор функций (определенный стандартом POSIX) для максимальной переносимости. #!/bin/bash отлично подходит для пользовательских скриптов. /bin/sh обычно символически связывается с минимальной оболочкой, совместимой с POSIX, или с стандартной оболочкой (например, bash). В более позднем случае bash запускается в режиме совместимости, что объясняется в manpage:
Если bash вызывается с именем sh, он пытается как можно ближе имитировать поведение при запуске исторических версий sh, в то же время соответствующее стандарту POSIX.
Предлагаемые изменения в script:
"$i" вместо $i). Котируемые переменные будут предотвращать проблемы, если сохраненное имя файла содержит пробелы."${i%.mp4}.mp3" (вместо "${i/.mp4/.mp3}"), так как ${parameter%word} заменяет только в конце (например, файл с именем foo.mp4.backup).Конструкция ${var/x/y/} не POSIX. В вашем случае, когда вы просто удаляете строку в конце переменной и применяете другую строку, переносимое решение POSIX должно использовать
#!/bin/sh
for i in *.mp4; do
ffmpeg -i "$i" "${i%.mp4}.mp3"
done
или даже короче, ffmpeg -i "$i" "${i%4}3".
Определяющим допированием для этих конструкций является глава Расширение параметров для оболочки POSIX.