Shell-Script

如何在 ZSH 循環中附加參數,然後將它們傳遞給命令?

  • April 9, 2020

使用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 ...等?

我不必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 預設情況下不分詞,所以從技術上講你根本不需要引用,但我更喜歡遵循 compatible-with-other-shells 引用風格,所以我引用所有變數擴展:

#!/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

引用自:https://unix.stackexchange.com/questions/578545