wake-up-neo.net

Wie kann man eine Zeichenfolge in mehrere Zeichenfolgen aufteilen, die durch mindestens ein Leerzeichen in der Bash-Shell voneinander getrennt sind?

Ich habe eine Zeichenfolge mit vielen Wörtern, zwischen denen mindestens ein Leerzeichen steht. Wie kann ich die Zeichenfolge in einzelne Wörter aufteilen, damit ich sie durchlaufen kann?

Die Zeichenfolge wird als Argument übergeben. Z.B. ${2} == "cat cat file". Wie kann ich es durchlaufen?

Wie kann ich auch überprüfen, ob eine Zeichenfolge Leerzeichen enthält?

199
derrdji

Haben Sie versucht, die Zeichenfolgenvariable einfach an eine for -Schleife zu übergeben? Zum einen wird Bash automatisch in Leerzeichen aufgeteilt.

sentence="This is   a sentence."
for Word in $sentence
do
    echo $Word
done

This
is
a
sentence.
254
mob

Ich mag die Konvertierung in ein Array, um auf einzelne Elemente zugreifen zu können:

sentence="this is a story"
stringarray=($sentence)

jetzt können Sie direkt auf einzelne Elemente zugreifen (es beginnt mit 0):

echo ${stringarray[0]}

oder konvertiere zurück in einen String, um eine Schleife zu erstellen:

for i in "${stringarray[@]}"
do
  :
  # do whatever on $i
done

Natürlich wurde das direkte Durchlaufen des Strings bereits beantwortet, aber diese Antwort hatte den Nachteil, die einzelnen Elemente für eine spätere Verwendung nicht im Auge zu behalten:

for i in $sentence
do
  :
  # do whatever on $i
done

Siehe auch Bash-Array-Referenz .

267
Highwind

Verwenden Sie einfach die Muscheln "Set" eingebaut. Zum Beispiel,

 setze $ text 

Danach werden einzelne Wörter in $ text in $ 1, $ 2, $ 3 usw. angegeben. Aus Gründen der Robustheit ist dies normalerweise der Fall

 set - junk $ text 
 shift 

um den Fall zu behandeln, dass $ text leer ist oder mit einem Bindestrich beginnt. Zum Beispiel:

 text = "Dies ist ein Test" 
 set - Junk $ text 
 shift 
 for Word; do 
 echo "[$ Word]" 
 done 

Dies wird gedruckt

[Das ist ein Test]
81
Idelic

Der wahrscheinlich einfachste und sicherste Weg in BASH 3 und höher ist:

var="string    to  split"
read -ra arr <<<"$var"

(wobei arr das Array ist, das die aufgeteilten Teile des Strings aufnimmt) oder, wenn die Eingabe möglicherweise Zeilenumbrüche enthält und Sie mehr als nur die erste Zeile wünschen:

var="string    to  split"
read -ra arr -d '' <<<"$var"

(Bitte beachten Sie das Leerzeichen in -d '', es kann nicht weggelassen werden), aber dies kann zu einem unerwarteten Zeilenumbruch von <<<"$var" führen (da dies implizit ein LF) hinzufügt = am Ende).

Beispiel:

touch NOPE
var="* a  *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done

Gibt das erwartete aus

[*]
[a]
[*]

da diese Lösung (im Gegensatz zu allen vorherigen Lösungen hier) nicht zu unerwarteten und oft unkontrollierbaren Shell-Globbing neigt.

Auch dies gibt Ihnen die volle Leistung von IFS, wie Sie wahrscheinlich wollen:

Beispiel:

IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done

Gibt so etwas aus wie:

[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]

Wie Sie sehen, können Leerzeichen auch so erhalten werden:

IFS=: read -ra arr <<<' split  :   this    '
for a in "${arr[@]}"; do echo "[$a]"; done

ausgänge

[ split  ]
[   this    ]

Bitte beachten Sie, dass der Umgang mit IFS in BASH ein eigenständiges Thema ist. Machen Sie also Ihre Tests, einige interessante Themen dazu:

  • unset IFS: Ignoriert SPC-, TAB-, NL- und Online-Starts und -Ende
  • IFS='': Keine Feldtrennung, liest einfach alles
  • IFS=' ': Läuft von SPC (und nur von SPC)

Ein letztes Beispiel

var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

ausgänge

1 [this is]
2 [a test]

während

unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done

ausgänge

1 [this]
2 [is]
3 [a]
4 [test]

Übrigens:

  • Wenn Sie es nicht gewohnt sind, sich an $'ANSI-ESCAPED-STRING' Zu gewöhnen, ist dies eine Zeitersparnis.

  • Wenn Sie -r Nicht einschließen (wie in read -a arr <<<"$var"), Wird beim Lesen ein umgekehrter Schrägstrich ausgegeben. Dies ist eine Übung für den Leser.


Für die zweite Frage:

Um nach etwas in einem String zu suchen, halte ich mich normalerweise an case, da dies nach mehreren Fällen gleichzeitig suchen kann (Hinweis: case führt nur die erste Übereinstimmung aus, wenn Sie einen Durchbruch benötigen, verwenden Sie multiplce case -Anweisungen ), und diese Notwendigkeit ist ziemlich oft der Fall (Wortspiel beabsichtigt):

case "$var" in
'')                empty_var;;                # variable is empty
*' '*)             have_space "$var";;        # have SPC
*[[:space:]]*)     have_whitespace "$var";;   # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";;    # non-alphanum-chars found
*[-+.,]*)          have_punctuation "$var";;  # some punctuation chars found
*)                 default_case "$var";;      # if all above does not match
esac

So können Sie den Rückgabewert so einstellen, dass nach SPC gesucht wird:

case "$var" in (*' '*) true;; (*) false;; esac

Warum case? Da es in der Regel etwas besser lesbar ist als Regex-Sequenzen und dank Shell-Metazeichen 99% aller Anforderungen sehr gut verarbeitet.

58
Tino
$ echo "This is   a sentence." | tr -s " " "\012"
This
is
a
sentence.

Verwenden Sie grep, um nach Leerzeichen zu suchen:

$ echo "This is   a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null     
$ echo $?
1
41
DVK

(A) Um einen Satz in seine Wörter aufzuteilen (durch Leerzeichen getrennt), können Sie einfach das Standard-IFS verwenden

array=( $string )


Beispiel Ausführen des folgenden Snippets

#!/bin/bash

sentence="this is the \"sentence\"   'you' want to split"
words=( $sentence )

len="${#words[@]}"
echo "words counted: $len"

printf "%s\n" "${words[@]}" ## print array

wird ausgegeben

words counted: 8
this
is
the
"sentence"
'you'
want
to
split

Wie Sie sehen, können Sie problemlos auch einfache oder doppelte Anführungszeichen verwenden

Anmerkungen:
- Dies ist im Grunde das Gleiche wie die Antwort von mob , aber auf diese Weise speichern Sie das Array für weitere Anforderungen. Wenn Sie nur eine einzelne Schleife benötigen, können Sie seine Antwort verwenden, die eine Zeile kürzer ist :)
- In diese Frage finden Sie alternative Methoden zum Teilen einer Zeichenfolge basierend auf dem Trennzeichen.


(B) Um nach einem Zeichen in einer Zeichenfolge zu suchen, können Sie auch einen regulären Ausdruck verwenden.
Beispiel, um zu überprüfen, ob ein Leerzeichen vorhanden ist, das Sie verwenden können:

regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
    then
        echo "Space here!";
fi
16
Luca Borrione

Um Leerzeichen nur mit bash zu überprüfen:

[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"
6
glenn jackman