Почему
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.