Как добавить аргументы в цикл ZSH, а затем передать их команде?

Как добавить аргументы в цикл ZSH, а затем передать их команде?

Используя mkvmerge, я хочу добавить аудиодорожки к нескольким клипам MKV, которые расположены следующим образом

Clips_folder
/spa/clip1.mka
/spa/clip2.mka
/ger/clip1.mka
/ger/clip2.mka
/clip1.mkv
/clip2.mkv

Вот такой у меня сценарий (на основе «Добавить аргумент в список аргументов»):

#!/bin/zsh

mkdir -p output

for video in *.mkv
do
    audioargs=("-o ./output/${video} --language 0:eng ${video}")
    for audiodir in *(/)
        do
            audioargs+=("--language 0:${audiodir} ./${audiodir}/${video:r}.mka")
        done
    echo ${audioargs[@]}
done

Вот что получилось:

-o ./output/clip1.mkv --language 0:eng clip1.mkv --language 0:spa ./spa/clip1.mka --language 0:ger ./ger/clip1.mka

Но когда я меняю его на mkvmerge ${audioargs[@]}я получаю

mkvmerge v45.0.0 ('Heaven in Pennies') 64-bit
Error: no destination file name was given

Как правильно передать audioargs, mkvmergeчтобы он был расширен до mkvmerge -o file --language ...и т. д.?

решение1

Мне не нужно mkvmergeтестировать, но я почти уверен, что проблема в том, как вы заключаете в кавычки, когда создаете массив. Когда вы делаете что-то вроде

audioargs=("-o ./output/${video} --language 0:eng ${video}")

Двойные кавычки сообщают оболочке, что все это нужно обрабатывать как одну длинную строку, поэтому она сохраняется как один элемент в массиве и, следовательно, передается mkvmergeкак один аргумент, содержащий пробелы, а не как ряд аргументов.

Обратите внимание, что echoскрывает различие между пробелом внутри аргумента и пробеломмеждуаргументы, что делает его крайне вводящим в заблуждение для таких вещей. Размещение set -xперед командой должно прояснить, что на самом деле происходит. С вашими примерами имен файлов, set -xпоказывает, что запускается:

echo '-o ./output/clip2.mkv --language 0:eng clip2.mkv' '--language 0:ger ./ger/clip2.mka' '--language 0:spa ./spa/clip2.mka'

Видите длинные разделы в одинарных кавычках? Так они указывают на то, что это длинные аргументы, содержащие пробелы, а не последовательности отдельных аргументов.

Чтобы решить эту проблему, просто используйте обычные кавычки при построении массива (т. е. те же самые кавычки, которые вы использовали бы при передаче аргументов непосредственно команде). По умолчанию zsh не разбивает слова на части, так что технически вам вообще не нужно заключать их в кавычки, но я предпочитаю следовать стилю кавычек, совместимому с другими оболочками, поэтому я заключаю в кавычки все расширения переменных:

#!/bin/zsh

mkdir -p output

for video in *.mkv
do
    audioargs=(-o "./output/${video}" --language 0:eng "./${video}")
    for audiodir in *(/)
        do
            audioargs+=(--language "0:${audiodir}" "./${audiodir}/${video:r}.mka")
        done
    echo "${audioargs[@]}"
done

Что дает такой результат set -x:

echo -o ./output/clip2.mkv --language 0:eng ./clip2.mkv --language 0:ger ./ger/clip2.mka --language 0:spa ./spa/clip2.mka

Связанный контент