2016-09-20 8 views
0

Say I haben eine variable $ARGS welche enthält:bash erweitern Argumente mit Leerzeichen aus variablen

file1.txt "second file.txt" file3.txt 

Wie kann ich den Inhalt $ARGS als Argumente auf einen Befehl (sagen cat $ARGS, zB) übergeben, Behandeln "second file.txt" als ein Argument und nicht in "second und file.txt" teilen?

Im Idealfall würde ich gerne in der Lage sein, Argumente an jeden Befehl genau so zu übergeben, wie sie in einer Variablen gespeichert sind (gelesen aus einer Textdatei, aber ich denke nicht, dass das relevant ist).

Danke!

+6

Sie eine Variable nicht verwenden; Verwenden Sie ein Array: 'ARGS = (" file1.txt "" zweite Datei.txt "" file3.txt ") und übergeben Sie es dann:' "$ {ARGS [@]}" '. –

+0

Wenn die Einstellungen in einer Textdatei sind und das Trennzeichen zwischen Argumenten ein Leerzeichen ist, sehe ich nicht, warum Sie das Verhalten, das Sie sehen, als falsch ansehen. Ich meine, ich kann sehen, was Sie tun möchten, aber das Lesen von Leerzeichen getrennten Argumenten aus einer Textdatei ist wahrscheinlich die falsche Lösung. Vielleicht verwenden Sie ein strukturiertes Dateiformat, wenn Ihre Anforderungen komplex sind. – tripleee

Antwort

2

Es ist möglich, dies ohne entweder bash-Arrays zu tun oder eval: Dies ist eine der einige Orte, wo das Verhalten von xargs ohne entweder -0 oder -d Erweiterungen (ein Verhalten, das meist Bugs erstellt) tatsächlich nützlich ist.

# this will print each argument on a different line 
# ...note that it breaks with arguments containing literal newlines! 
xargs printf '%s\n' <<<"$ARGS" 

... oder ...

# this will emit arguments in a NUL-delimited stream 
xargs printf '%s\0' <<<"$ARGS" 

# in bash 4.4, you can read this into an array like so: 
readarray -t -d '' args < <(printf '%s\0' "$ARGS") 
yourprog "${args[@]}" # actually run your programs 

# in bash 3.x or newer, it's just a bit longer: 
args=(); 
while IFS= read -r -d '' arg; do 
    args+=("$args") 
done < <(xargs printf '%s\0' <<<"$ARGS") 
yourprog "${args[@]}" # actually run your program 

# in POSIX sh, you can't safely handle arguments with literal newlines 
# ...but, barring that, can do it like this: 
set -- 
while IFS= read -r arg; do 
    set -- "[email protected]" "$arg" 
done < <(printf '%s\n' "$ARGS" | xargs printf '%s\n') 
yourprog "[email protected]" # actually run your program 

... oder lassen xargs selbst den Aufruf tun:

# this will call yourprog with ARGS given 
# ...but -- beware! -- will cause bugs if there are more arguments than will fit on one 
# ...command line invocation. 
printf '%s\n' "$ARGS" | xargs yourprog 
1

Wie von Jonathan Leffler erwähnt, können Sie dies mit einem Array tun.

my_array=("file1.txt" "second file.txt" "file3.txt") 
cat "${my_array[1]}" 

Ein Index des Arrays beginnt bei 0. Wenn Sie also zu cat die erste Datei in Ihrem Array wollten Sie die Indexnummer 0. "${my_array[0]}" verwenden würde. Wenn Sie Ihren Befehl für alle Elemente ausführen möchten, ersetzen Sie die Indexnummer durch @ oder *. Zum Beispiel anstelle von "${my_arryay[0]}" würden Sie "${my_array[@]}" verwenden Stellen Sie sicher, dass Sie das Array zitieren, oder es wird jeden Dateinamen mit Leerzeichen als separate Dateien behandeln.

Alternativ, wenn das Array aus irgendeinem Grund ein Problem darstellt, können Sie IFS (das für Internal Field Separator steht) gleich einem Newline setzen. Wenn Sie dies tun, ist es eine gute Idee, das Standard-IFS vor dem Ändern in eine Variable zu speichern, damit Sie es auf die Art zurücksetzen können, die es nach Abschluss des Skripts war. Zum Beispiel:

Es ist wahrscheinlich besser, nicht mit IFS rumzualbern, es sei denn, Sie müssen. Wenn Sie das Array angeben können, damit Ihr Skript funktioniert, sollten Sie das tun.

Für eine viel mehr in die Tiefe Blick in Arrays sehen:

+0

Bitte verwenden Sie eine andere Quelle als das ABS - es ist [eher berüchtigt] (http://wooleden.org/~greybot/meta/abs), in seinen Beispielen schlechte Praktiken zu verwenden. Es gibt [die Bash-Hacker-Seite auf Arrays] (http://wiki.bash-hackers.org/syntax/arrays), [der BashGuide auf Arrays] (http://mywiki.wooledge.org/BashGuide/Arrays), und [BashFAQ # 5] (http://mywiki.wooledge.org/BashFAQ/005). –

+0

Wenn der ursprüngliche IFS-Wert nicht gesetzt ist, verhält sich der Shuffle "old_IFS", den Sie hier ausführen, nicht so, wie Sie es beabsichtigen. Betrachte 'old_IFS = $ {IFS- $ '\ t \ n'}', um den Standardwert in 'old_IFS' zu speichern, wenn der ursprüngliche Wert nicht gesetzt ist (im Gegensatz zu set-to-a-left-string). –

+0

Danke für die Information. Ich habe die Antwort aktualisiert. –

0

Ohne bashIsmen, plain Shell-Code könnte eine eval brauchen :

# make three temp files and list them. 
cd /tmp ; echo ho > ho ; echo ho ho > "ho ho" ; echo ha > ha ; 
A='ho "ho ho" ha' ; eval grep -n '.' $A 

Ausgang:

ho:1:ho 
ho ho:1:ho ho 
ha:1:ha 

Beachten Sie, dass eval mächtig ist, und if not used responsibly can lead to mischief ...

Verwandte Themen