Como acrescentar argumentos em um loop ZSH e depois passá-los para um comando?

Como acrescentar argumentos em um loop ZSH e depois passá-los para um comando?

Usando mkvmerge, quero adicionar faixas de áudio a vários clipes MKV organizados assim

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

Esse é o script que eu tenho (baseado em 'Anexar argumento à lista de argumentos'):

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

Essa é a saída:

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

Mas quando eu mudo para mkvmerge ${audioargs[@]}eu fico

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

Como passo corretamente audioargspara mkvmergeque seja expandido para mkvmerge -o file --language ...etc?

Responder1

Não preciso mkvmergetestar, mas tenho certeza de que o problema é como você cita as coisas ao construir o array. Quando você faz algo como

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

As aspas duplas dizem ao shell para tratar tudo como uma longa string, então ela é armazenada como um único elemento no array e, portanto, passada mkvmergecomo um único argumento contendo espaços, em vez de uma série de argumentos.

Observe que isso echoesconde a distinção entre um espaço dentro de um argumento e um espaçoentreargumentos, tornando-o altamente enganoso para coisas como esta. Colocar set -xantes do comando deve esclarecer o que realmente está acontecendo. Com seus nomes de arquivos de exemplo, set -xmostra o que está sendo executado:

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

Veja as longas seções entre aspas simples? É assim que indica que são argumentos longos contendo espaços, em vez de sequências de argumentos separados.

Para resolver isso, basta usar aspas normais ao construir o array (ou seja, as mesmas aspas que você usaria ao passar argumentos diretamente para o comando). zsh não divide palavras por padrão, então tecnicamente você não precisa citar nada, mas eu prefiro seguir o estilo de cotação compatível com outros shells, então cito todas as expansões de variáveis:

#!/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 que dá esse resultado com set -x:

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

informação relacionada