2924 Stimmen

Wie splitte ich eine Zeichenkette an einem Begrenzer in der Bash?

Ich habe diese Zeichenfolge in einer Variablen gespeichert:

IN="bla@some.com;john@home.com"

Nun möchte ich die Zeichenketten aufteilen nach ; Begrenzungszeichen, so dass ich habe:

ADDR1="bla@some.com"
ADDR2="john@home.com"

Ich brauche nicht unbedingt die ADDR1 y ADDR2 Variablen. Wenn sie Elemente eines Arrays sind, ist das sogar noch besser.


Nach den Vorschlägen aus den nachstehenden Antworten kam ich zu folgendem Ergebnis, das dem entspricht, was ich wollte:

#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "\n")

for addr in $mails
do
    echo "> [$addr]"
done

Ausgabe:

> [bla@some.com]
> [john@home.com]

Es gab eine Lösung, die die Einstellung Interner_Feld_Trenner (IFS) an ; . Ich bin mir nicht sicher, was mit dieser Antwort passiert ist, wie setzt man IFS zurück zum Standard?

RE: IFS Lösung, ich habe das ausprobiert und es funktioniert, ich behalte die alte IFS und dann wiederherstellen:

IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
    echo "> [$x]"
done

IFS=$OIFS

Übrigens, als ich versuchte

mails2=($IN)

Ich habe nur die erste Zeichenkette erhalten, wenn ich sie in einer Schleife ohne Klammern ausgedruckt habe $IN es funktioniert.

30 Stimmen

In Bezug auf Ihr "Edit2": Sie können einfach "IFS aufheben" und der Standardzustand wird wiederhergestellt. Es besteht keine Notwendigkeit, ihn explizit zu speichern und wiederherzustellen, es sei denn, Sie haben Grund zu der Annahme, dass er bereits auf einen anderen Wert als den Standardwert gesetzt wurde. Wenn Sie dies innerhalb einer Funktion tun (und wenn Sie es nicht tun, warum nicht?), können Sie IFS als lokale Variable setzen, die nach dem Verlassen der Funktion auf ihren vorherigen Wert zurückgesetzt wird.

33 Stimmen

@BrooksMoses: (a) +1 für die Verwendung local IFS=... wenn möglich; (b) -1 für unset IFS wird IFS nicht genau auf seinen Standardwert zurückgesetzt, obwohl ich glaube, dass sich ein nicht gesetzter IFS genauso verhält wie der Standardwert von IFS ($' \t\n '), aber es scheint eine schlechte Praxis zu sein, blind davon auszugehen, dass Ihr Code niemals mit einem benutzerdefinierten IFS-Wert aufgerufen werden wird; (c) eine andere Idee ist, eine Subshell aufzurufen: (IFS=$custom; ...) Wenn die Subshell beendet wird, kehrt IFS zu dem ursprünglichen Zustand zurück.

0 Stimmen

Ich möchte nur einen kurzen Blick auf die Pfade werfen, um zu entscheiden, wohin ich eine ausführbare Datei werfen soll, also habe ich auf die Ausführung von ruby -e "puts ENV.fetch('PATH').split(':')" . Wenn Sie reine Bash bleiben wollen, hilft es nicht, wenn Sie eine beliebige Skriptsprache die eine eingebaute Aufteilung hat, ist einfacher.

15voto

Halle Knast Punkte 3840

Die folgende Bash/zsh-Funktion teilt ihr erstes Argument an dem durch das zweite Argument gegebenen Begrenzungszeichen auf:

split() {
    local string="$1"
    local delimiter="$2"
    if [ -n "$string" ]; then
        local part
        while read -d "$delimiter" part; do
            echo $part
        done <<< "$string"
        echo $part
    fi
}

Zum Beispiel kann der Befehl

$ split 'a;b;c' ';'

ergibt

a
b
c

Diese Ausgabe kann z. B. an andere Befehle weitergeleitet werden. Beispiel:

$ split 'a;b;c' ';' | cat -n
1   a
2   b
3   c

Im Vergleich zu den anderen Lösungen hat diese die folgenden Vorteile:

  • IFS nicht überschrieben wird: Aufgrund des dynamischen Scopings auch lokaler Variablen ist das Überschreiben von IFS in einer Schleife führt dazu, dass der neue Wert in Funktionsaufrufe innerhalb der Schleife einfließt.

  • Arrays werden nicht verwendet: Lesen einer Zeichenkette in ein Array mit read erfordert das Flag -a in Bash und -A in zsh.

Falls gewünscht, kann die Funktion wie folgt in ein Skript eingefügt werden:

#!/usr/bin/env bash

split() {
    # ...
}

split "$@"

0 Stimmen

Scheint mit Trennzeichen, die länger als 1 Zeichen sind, nicht zu funktionieren: split=$(split "$content" "file://")

0 Stimmen

Wahr - von help read : -d delim continue until the first character of DELIM is read, rather than newline

12voto

shuaihanhungry Punkte 448

Sie können awk auf viele Situationen anwenden

echo "bla@some.com;john@home.com"|awk -F';' '{printf "%s\n%s\n", $1, $2}'

Sie können auch Folgendes verwenden

echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="\n"

12voto

Victor Choy Punkte 3670

Es gibt einen einfachen und intelligenten Weg, um dies zu erreichen:

echo "add:sfff" | xargs -d: -i  echo {}

Aber Sie müssen gnu xargs verwenden, BSD xargs unterstützt -d delim nicht. Wenn Sie wie ich einen Apple Mac benutzen. Sie können gnu xargs installieren:

brew install findutils

dann

echo "add:sfff" | gxargs -d: -i  echo {}

10voto

eukras Punkte 799

Es gibt einige coole Antworten hier (vor allem errator), aber für etwas, das analog zu Split in anderen Sprachen ist - was ich die ursprüngliche Frage verstanden habe - habe ich mich auf dies geeinigt:

IN="bla@some.com;john@home.com"
declare -a a="(${IN/;/ })";

Jetzt ${a[0]} , ${a[1]} usw. sind so, wie Sie es erwarten würden. Verwenden Sie ${#a[*]} für die Anzahl der Begriffe. Oder um zu iterieren, natürlich:

for i in ${a[*]}; do echo $i; done

WICHTIGER HINWEIS:

Das funktioniert in Fällen, in denen es keine Leerzeichen gibt, was mein Problem gelöst hat, aber vielleicht nicht das Ihre. Gehen Sie mit dem $IFS Lösung(en) in diesem Fall.

0 Stimmen

Funktioniert nicht, wenn IN mehr als zwei E-Mail-Adressen enthält. Bitte beziehen Sie sich auf dieselbe Idee (aber korrigiert) unter Palindroms Antwort

0 Stimmen

Bessere Nutzung ${IN//;/ } (doppelter Schrägstrich), damit es auch mit mehr als zwei Werten funktioniert. Beachten Sie, dass jeder Platzhalter ( *?[ ) wird erweitert. Und ein leeres Feld am Ende wird verworfen.

5voto

ghost Punkte 448

Wenn kein Platz, warum nicht so?

IN="bla@some.com;john@home.com"
arr=(`echo $IN | tr ';' ' '`)

echo ${arr[0]}
echo ${arr[1]}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X