Wie füge ich Argumente in einer ZSH-Schleife an und übergebe sie dann an einen Befehl?

Wie füge ich Argumente in einer ZSH-Schleife an und übergebe sie dann an einen Befehl?

Mit mkvmergemöchte ich Audiospuren zu mehreren MKV-Clips hinzufügen, die wie folgt angeordnet sind

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

Das ist das Skript, das ich habe (basierend auf „Argument an Argumentliste anhängen“):

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

Das ist die Ausgabe:

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

Aber wenn ich es ändere, mkvmerge ${audioargs[@]}bekomme ich

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

Wie übergebe ich richtig audioargsan mkvmerge, sodass es zu mkvmerge -o file --language ...usw. erweitert wird?

Antwort1

Ich muss es nicht mkvmergetesten, aber ich bin mir ziemlich sicher, dass das Problem darin liegt, wie Sie Dinge in Anführungszeichen setzen, wenn Sie das Array erstellen. Wenn Sie so etwas tun wie

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

Die Anführungszeichen weisen die Shell an, das Ganze als einen langen String zu behandeln, sodass es als einzelnes Element im Array gespeichert und daher mkvmergeals einzelnes Argument mit Leerzeichen und nicht als Reihe von Argumenten übergeben wird.

Beachten Sie, dass echoder Unterschied zwischen einem Leerzeichen innerhalb eines Arguments und einem Leerzeichen ausgeblendet wird.zwischenArgumente, was es für solche Dinge höchst irreführend macht. Wenn man es set -xvor den Befehl setzt, sollte klar sein, was tatsächlich passiert. Mit Ihren Beispieldateinamen set -xzeigt es, was ausgeführt wird:

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

Sehen Sie die langen Abschnitte in einfachen Anführungszeichen? Dadurch wird angezeigt, dass es sich um lange Argumente mit Leerzeichen handelt und nicht um Folgen einzelner Argumente.

Um das Problem zu lösen, verwenden Sie beim Erstellen des Arrays einfach normale Anführungszeichen (also dieselben Anführungszeichen, die Sie verwenden würden, wenn Sie Argumente direkt an den Befehl übergeben). zsh führt standardmäßig keine Worttrennung durch, daher müssen Sie technisch gesehen überhaupt keine Anführungszeichen verwenden, aber ich bevorzuge den mit anderen Shells kompatiblen Anführungsstil und setze daher alle Variablenerweiterungen in Anführungszeichen:

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

Das ergibt dieses Ergebnis mit set -x:

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

verwandte Informationen