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.

4voto

James Andino Punkte 22663

Das ist der einfachste Weg.

spo='one;two;three'
OIFS=$IFS
IFS=';'
spo_array=($spo)
IFS=$OIFS
echo ${spo_array[*]}

3voto

fedorqui Punkte 249453

Abgesehen von den fantastischen Antworten, die bereits gegeben wurden, können Sie, wenn es nur darum geht, die Daten auszudrucken, Folgendes in Betracht ziehen awk :

awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"

Dies setzt das Feldtrennzeichen auf ; so dass es die Felder in einer Schleife mit einer for Schleife und drucken entsprechend.

Test

$ IN="bla@some.com;john@home.com"
$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"
> [bla@some.com]
> [john@home.com]

Mit einer weiteren Eingabe:

$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "a;b;c   d;e_;f"
> [a]
> [b]
> [c   d]
> [e_]
> [f]

3voto

rashok Punkte 11608
IN="bla@some.com;john@home.com"
IFS=';'
read -a IN_arr <<< "${IN}"
for entry in "${IN_arr[@]}"
do
    echo $entry
done

Ausgabe

bla@some.com
john@home.com

System: Ubuntu 12.04.1

0 Stimmen

Der IFS wird nicht in den spezifischen Kontext der read und kann daher den Rest des Codes durcheinanderbringen.

2voto

18446744073709551615 Punkte 15274

In der Android-Shell funktionieren die meisten der vorgeschlagenen Methoden einfach nicht:

$ IFS=':' read -ra ADDR <<<"$PATH"                             
/system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory

Was funktioniert, ist:

$ for i in ${PATH//:/ }; do echo $i; done
/sbin
/vendor/bin
/system/sbin
/system/bin
/system/xbin

wobei // bedeutet globalen Ersatz.

1 Stimmen

Schlägt fehl, wenn irgendein Teil von $PATH Leerzeichen (oder Zeilenumbrüche) enthält. Expandiert auch Platzhalter (Sternchen *, Fragezeichen ? und geschweifte Klammern [ ]).

2voto

ajaaskel Punkte 1559
IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'
set -f
oldifs="$IFS"
IFS=';'; arrayIN=($IN)
IFS="$oldifs"
for i in "${arrayIN[@]}"; do
echo "$i"
done
set +f

Ausgabe:

bla@some.com
john@home.com
Charlie Brown <cbrown@acme.com
!"#$%&/()[]{}*? are no problem
simple is beautiful :-)

Erläuterung: Eine einfache Zuweisung mit Hilfe von Klammern () wandelt eine durch Semikolon getrennte Liste in ein Array um, vorausgesetzt, Sie haben dabei das richtige IFS. Die Standard-FOR-Schleife behandelt die einzelnen Elemente in diesem Array wie üblich. Beachten Sie, dass die Liste, die für die IN-Variable angegeben wird, "hart" quotiert sein muss, d. h. mit einzelnen Häkchen.

IFS muss gespeichert und wiederhergestellt werden, da die Bash eine Zuweisung nicht wie einen Befehl behandelt. Eine alternative Abhilfe besteht darin, die Zuweisung in eine Funktion zu verpacken und diese Funktion mit einer geänderten IFS aufzurufen. In diesem Fall ist ein separates Sichern/Wiederherstellen der IFS nicht erforderlich. Vielen Dank an "Bize" für diesen Hinweis.

0 Stimmen

!"#$%&/()[]{}*? are no problem naja... nicht ganz: []*? sind globale Zeichen. Wie wäre es also, dieses Verzeichnis und diese Datei zu erstellen: `mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem' und führen Sie Ihren Befehl aus? simple may be beautiful, but when it's broken, it's broken.

0 Stimmen

@gniourf_gniourf Die Zeichenfolge wird in einer Variablen gespeichert. Bitte lesen Sie die ursprüngliche Frage.

1 Stimmen

@ajaaskel Sie haben meinen Kommentar nicht ganz verstanden. Gehen Sie in ein Scratch-Verzeichnis und geben Sie diese Befehle ein: mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem' . Sie erstellen nur ein Verzeichnis und eine Datei mit seltsam aussehenden Namen, wie ich zugeben muss. Führen Sie dann Ihre Befehle mit der genauen IN die Sie gegeben haben: IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)' . Sie werden sehen, dass Sie nicht die erwartete Ausgabe erhalten werden. Denn Sie verwenden eine Methode, die Pfadnamen-Erweiterungen unterliegt, um Ihre Zeichenkette zu zerlegen.

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