Shell-Skript: Erstellen einer Variablen mit darin enthaltenen Optionen

11

Ich habe einen rsync-Befehl mit folgenden Parametern:

rsync -avz --{partial,stats,delete,exclude=".*"}

Ich möchte diese Parameter in eine Variable einfügen, um sie anschließend im Skript wiederzuverwenden. Etwas wie das:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

Ich habe es mit Anführungszeichen, einfachen Anführungszeichen und Klammern versucht, ohne Erfolg.

Kellyson
quelle
Ähnliche Frage auf SO: stackoverflow.com/questions/13365553/…
Barmar
Nachdem Sie diesen Weg schon einmal gegangen sind: Stellen Sie sicher, dass Ihre endgültige Befehlszeichenfolge keine leeren Zeichenfolgen enthält. In diesem Fall verwendet rsync sie möglicherweise als Parameter. Da sie unsichtbar sind, ist das Debuggen ziemlich schwierig. Ich hatte einen leeren ersten Parameter und rsync interpretierte ihn so, dass er das aktuelle Verzeichnis in die Quellen der zu kopierenden Dinge einbezog.
Joe

Antworten:

12

Das Einfügen eines komplexen Befehls in eine Variable wird niemals empfohlen. Siehe BashFAQ / 050 - Ich versuche, einen Befehl in eine Variable einzufügen, aber die komplexen Fälle schlagen immer fehl!

Ihre Anforderung wird sehr einfach, wenn Sie nur eine Funktion anstelle einer Variablen verwenden und ihr Argumente übergeben.

Etwas wie

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

und übergeben Sie nun die erforderlichen Argumente als

rsync_custom /dir1 /dir2

Die Funktionsdefinition ist in gewisser Weise recht einfach. Wir überprüfen zunächst die Anzahl der Eingabeargumente anhand der Variablen, $#die nicht Null sein sollte. Wir geben eine Fehlermeldung aus, dass keine Argumente angegeben werden. Wenn gültige Argumente vorhanden sind, werden "$@"die tatsächlichen Argumente dargestellt, die an die Funktion übergeben wurden.

Wenn dies eine Funktion ist , würde man ziemlich häufig in scripts / Befehlszeile auch mit IE werden, füge sie an die Shell - Startup-Dateien, .bashrc, .bash_profilezum Beispiel.

Oder wie bereits erwähnt, kann es sinnvoll sein, die Klammererweiterung zu erweitern, um Argumente für eine bessere Lesbarkeit als zu trennen

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}
Inian
quelle
5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Diese versuchen , den Befehl auszuführen -avzmit Argumenten --partial, --statsetc .. und mit VARSet rsyncin der Umwelt.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

Das Anführungszeichen funktioniert nicht, da geschweifte Klammern nicht in Anführungszeichen und nicht in Zuweisungen erweitert werden und auch nicht, nachdem eine Variable erweitert wurde.

Wenn Sie Befehlszeilenargumente in einer Variablen speichern müssen, verwenden Sie ein Array:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Nun "${args[@]}"wird erweitern rsync, -avz, --partialusw. als deutliche Worte.

Mit Arrays können Sie bei Bedarf auch bedingt Optionen an die Liste anhängen, sodass Sie z.

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"
ilkkachu
quelle
1

Sie können die Optionen zumindest teilweise in einer Variablen speichern:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

Testen ist wichtig, da das Maskieren schwierig sein kann:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Da es mehrere Alternativen gibt, wie die Verwendung des Verlaufs, die Verwendung eines Alias ​​oder die Verwendung einer Funktion, gibt es keinen offensichtlichen Anwendungsfall, den ich mir vorstellen kann. Es gibt selten eine komplexe gemeinsame Nutzung von Optionen zwischen verschiedenen Programmen. Für eine Ad-hoc-Lösung für die interaktive Shell scheint Aliasing ein besserer Weg zu sein:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Ihre Probe

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

kann nicht funktionieren, da die Zuordnung beim ersten Leerzeichen endet. Sie müssen die Leerzeichen maskieren:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

Eine ziemlich gefährliche Sache zum Testen mit dieser Option --delete, nicht wahr? Da Optionen wieder "," und einfache Anführungszeichen enthalten können, kann die Maskierung sehr bald schwierig werden. Ich würde mich für einen Alias ​​entscheiden oder mich auf die Geschichte verlassen.

Ein Alias ​​kann in der Datei ~ / .bashrc gespeichert werden, um ihn über mehrere Sitzungen hinweg kontinuierlich zu verwenden. Funktionen können auch im bashrc gespeichert werden, aber Sie benötigen sie nur, wenn Sie Parameter verarbeiten möchten, die an die darin auszuwertende Funktion übergeben werden.

Benutzer unbekannt
quelle