Erstellen Sie einen Befehl dynamisch

9

Ich arbeite an einem Skript und muss den tarBefehl dynamisch erstellen .

Hier sind zwei Beispiele, um zu veranschaulichen, was ich versuche:

#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "${EXCLUDE[@]}"`" -zcf tmp.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

echo -e "\n\nNEXT:\n\n"

EXCLUDE=("--exclude=/tmp/hello\ hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "${EXCLUDE[@]}"`" -zcf test.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

Ich möchte in der Lage sein, _tarals Befehl zu verwenden. Ich konnte ihn mit dem klassischen Pfad arbeiten lassen, aber ich brauche ihn, um mit Leerzeichen im Ordnernamen zu arbeiten. Und jedes Mal bekam ich Fehler, die aussehen wie:

COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*"  -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello\ hello --exclude=/tmp/systemd* --exclude=/tmp/Temp*  -zcf test.tar.gz 
tar: hello: Cannot stat: No such file or directory

Nur eine Sache, die Sie wissen müssen: Ich brauche mein Skript, um auf sehr alten Maschinen zu arbeiten, was bedeutet, dass ich die letzten Bash-Funktionen nicht verwenden kann.

ShellCode
quelle
Ich glaube, dass die Option --exclude nur eine einzelne Zeichenfolge danach akzeptieren kann. Sie können jedoch mehrere --exclude-Anweisungen verwenden. Vielleicht versuchen Sie "--exclude = / tmp / hello --exclude = hello". Keine Ursache. Ich habe es falsch verstanden.
Lewis M
@ LewisM Ich denke, OP möchte Verzeichnis "/ tmp / hallo hallo" ausschließen (ja, mit einem Leerzeichen.
Archemar
@ ShellCode was ist mit dem Zitieren aller Ausschlüsse, zB "--exclude = / tmp / hallo hallo"
Archemar
Ja. Deshalb habe ich die Oops-Erklärung später veröffentlicht. :)
Lewis M
Wie wäre es evalvor der Hinrichtung?
Jimmyij

Antworten:

11

Versuchen Sie nicht, eine ausführbare Zeichenfolge zu erstellen. Erstellen Sie stattdessen die Argumente in einem Array und verwenden Sie diese beim Aufruf tar(für die Sie bereits ein Array ordnungsgemäß verwenden EXCLUDE):

#!/bin/bash

directory=/tmp

exclude=( "hello hello" "systemd*" "Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "${exclude[@]}"; do
    exclude_opts+=( --exclude="$directory/$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "${exclude_opts[@]}" "$directory"

Mit /bin/sh:

#!/bin/sh

directory=/tmp

set -- "hello hello" "systemd*" "Temp*"

# Now build the list of "--exclude" options from the $@ array
# (overwriting the values in $@ while doing so)
for elem do
    set -- "$@" --exclude="$directory/$elem"
    shift
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"

Beachten Sie das Zitieren von $@im shCode und von beiden ${exclude[@]}und ${exclude_opts[@]}im bashCode. Dadurch wird sichergestellt, dass die Listen zu individuell zitierten Elementen erweitert werden.

Verbunden:

Kusalananda
quelle
2
mix(){
        p=$1; shift; q=$1; shift; c=
        i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
        eval "${p%\%*}$c${p#*\%}"
}
mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
mix 'tar % -zcf tmp.tar.gz' --exclude "${EXCLUDE[@]}"

Erweitern Sie die Antwort hier . Dies hängt nicht von irgendwelchen Bashismen ab, es wird auch gut mit Debians /bin/shund mit funktionieren busybox.

Mosvy
quelle
Vielen Dank für Ihre Hilfe, aber ich mag die Bewertung nicht wirklich, sie ist ziemlich gefährlich ... Außerdem ist dieser Code ziemlich schwer zu verstehen, haben Sie nicht etwas Einfacheres? : / Das Skript wird verteilt, also muss ich es so einfach wie möglich halten ...
ShellCode
Es ist nicht gefährlich. Führen Sie es mit set -x. Was genau verstehst du nicht?
Mosvy
Lesen Sie auch die ursprüngliche Antwort zum Stapelüberlauf. Es enthält eine Demo.
Mosvy
Es funktioniert aber ganz gut ... Ich warte darauf, ob jemand eine sauberere Antwort hat, sonst werde ich deine akzeptieren. Vielleicht ist an diesem Code nichts auszusetzen, aber jedes Mal, wenn ich eine Auswertung sehe, befürchte ich, dass der Code zu einer Befehlsinjektion führen könnte. Deshalb versuche ich, dies zu vermeiden
ShellCode
Ich habe die Antwort mit einem Fix für Indizes> 9 aktualisiert. Sie können die Auswertung durch ein Echo ersetzen, um zu sehen, was tatsächlich wird (die
Auswertung