如何在 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

我如何正确地传递audioargsmkvmerge以便它扩展到mkvmerge -o file --language ...等?

答案1

我不必mkvmerge进行测试,但我很确定问题在于构建数组时如何引用内容。当你做类似的事情时

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

双引号告诉 shell 将整个事情视为一个长字符串,因此它作为单个元素存储在数组中,因此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 默认情况下不会进行分词,因此从技术上讲,您根本不需要引用,但我更喜欢遵循与其他 shell 兼容的引用风格,因此我引用了所有变量扩展:

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

相关内容