Ich habe eine Zeichenfolge wie diese:
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
Ich möchte es folgendermaßen aufteilen können:
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Wie mache ich das? (am besten mit einem Einzeiler)
Antwort1
Als ich die Antwort von David Postill sah, dachte ich: „Es muss eine einfachere Lösung geben.“ Nach einigem Experimentieren fand ich Folgendes heraus:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo $string
eval 'for word in '$string'; do echo $word; done'
Dies funktioniert, weil eval
die Zeile erweitert wird (indem die Anführungszeichen entfernt und erweitert werden string
), bevor die resultierende Zeile (die die Inline-Antwort ist) ausgeführt wird:
for word in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $word; done
Eine Alternative, die sich auf dieselbe Zeile erweitert, ist:
eval "for word in $string; do echo \$word; done"
Hier string
wird innerhalb der Anführungszeichen erweitert, aber es $
muss maskiert werden, damit word
es nicht erweitert wird, bevor die Zeile ausgeführt wird (in der anderen Form hat die Verwendung von einfachen Anführungszeichen den gleichen Effekt). Die Ergebnisse sind:
[~/]$ string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
[~/]$ echo $string
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
[~/]$ eval 'for word in '$string'; do echo $word; done'
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
[~/]$ eval "for word in $string; do echo \$word; done"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Antwort2
Die einfachste Lösung besteht darin, ein Array der zitierten Argumente zu erstellen, über das Sie dann bei Bedarf eine Schleife ausführen oder das Sie direkt an einen Befehl übergeben können.
eval "array=($string)"
for arg in "${array[@]}"; do echo "$arg"; done
PS: Bitte kommentieren Sie, wenn Sie einen einfacheren Weg ohne finden eval
.
Bearbeiten:
Aufbauend auf der Antwort von @Hubbitus haben wir eine vollständig bereinigte und korrekt zitierte Version. Hinweis: Dies ist übertrieben und hinterlässt tatsächlich zusätzliche Backslashes in doppelten oder einfachen Anführungszeichen vor den meisten Satzzeichen, ist aber gegen Angriffe immun.
declare -a "array=($( echo "$string" | sed 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
Ich überlasse es dem interessierten Leser, nach eigenem Ermessen Änderungen vorzunehmen.http://ideone.com/FUTHhj
Antwort3
Es sieht so aus, als ob xargs das ziemlich gut kann:
$ a='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
$ printf "%s" "$a" | xargs -n 1 printf "%s\n"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
Antwort4
Sie können es mit declare
anstelle von tun eval
, zum Beispiel:
Anstatt:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo "Initial string: $string"
eval 'for word in '$string'; do echo $word; done'
Tun:
declare -a "array=($string)"
for item in "${array[@]}"; do echo "[$item]"; done
Beachten Sie jedoch, dass es nicht viel sicherer ist, wenn die Eingabe vom Benutzer kommt!
Versuchen Sie es beispielsweise mit einer Zeichenfolge wie der folgenden:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
Du wirst hostname
bewertet (da kann es natürlich auch so etwas geben rm -rf /
)!
Ein sehr, sehr einfacher Versuch, es zu schützen, ersetzen Sie einfach Zeichen wie Backtrick ` und $:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
declare -a "array=( $(echo $string | tr '`$<>' '????') )"
for item in "${array[@]}"; do echo "[$item]"; done
Jetzt erhalten Sie eine Ausgabe wie:
[aString that may haveSpaces IN IT]
[bar]
[foo]
[bamboo]
[bam boo]
[?hostname?]
Weitere Einzelheiten zu Methoden sowie Vor- und Nachteilen finden Sie möglicherweise in dieser guten Antwort:https://stackoverflow.com/questions/17529220/warum-sollte-eval-in-bash-vermieden-werden-und-was-sollte-ich-stattdessen-verwenden/17529221#17529221
Es blieb jedoch noch immer eine Angriffsmöglichkeit. Ich möchte in der Bash-Methode unbedingt Anführungszeichen wie in doppelten Anführungszeichen (") haben, aber ohne den Inhalt zu interpretieren.