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.

178voto

Steven Lizarazo Punkte 5070

Das hat bei mir funktioniert:

string="1;2"
echo $string | cut -d';' -f1 # output is 1
echo $string | cut -d';' -f2 # output is 2

3 Stimmen

Es funktioniert zwar nur mit einem einstelligen Begrenzungszeichen, aber das ist es, wonach der Auftraggeber gesucht hat (durch ein Semikolon begrenzte Datensätze).

1 Stimmen

Beantwortet vor etwa vier Jahren von @Ashok sowie, vor mehr als einem Jahr, von @DougW , als Ihre Antwort, mit noch mehr Informationen. Bitte posten Sie eine andere Lösung als die der anderen.

0 Stimmen

Dies ist die prägnanteste und am besten nachvollziehbare cut Beispiel imo.

158voto

Tong Punkte 1847

Ich glaube AWK ist der beste und effizienteste Befehl, um Ihr Problem zu lösen. AWK ist standardmäßig in fast jeder Linux-Distribution enthalten.

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

wird geben

bla@some.com john@home.com

Natürlich können Sie jede E-Mail-Adresse speichern, indem Sie das awk-Druckfeld umdefinieren.

13 Stimmen

Oder noch einfacher: echo "bla@some.com;john@home.com" | awk 'BEGIN{RS=";"} {print}'

0 Stimmen

@Jaro Das hat bei mir perfekt funktioniert, als ich eine Zeichenfolge mit Kommas hatte und sie in Zeilen umformatieren musste. Danke.

0 Stimmen

Es funktionierte in diesem Szenario -> "echo "$SPLIT_0" | awk -F' inode=' '{print $1}'"! Ich hatte Probleme, als ich versuchte, Strings (" inode=") anstelle von Zeichen (";") zu verwenden. $ 1, $ 2, $ 3, $ 4 werden als Positionen in einem Array gesetzt! Wenn es eine Möglichkeit gibt, ein Array zu setzen... besser! Vielen Dank!

102voto

Wie wäre es mit diesem Ansatz?

IN="bla@some.com;john@home.com" 
set -- "$IN" 
IFS=";"; declare -a Array=($*) 
echo "${Array[@]}" 
echo "${Array[0]}" 
echo "${Array[1]}" 

Quelle

8 Stimmen

+1 ... aber ich würde die Variable nicht "Array" nennen ... pet peev ich denke. Gute Lösung.

14 Stimmen

+1 ... aber das "set" und declare -a sind unnötig. Sie hätten genauso gut einfach Folgendes verwenden können IFS";" && Array=($IN)

0 Stimmen

+1 Nur eine Randbemerkung: sollte es nicht empfehlenswert sein, das alte IFS zu behalten und es dann wiederherzustellen? (wie von stefanB in seinem edit3 gezeigt) Leute, die hier landen (manchmal einfach eine Lösung kopieren und einfügen) denken vielleicht nicht daran

94voto

lothar Punkte 19157
echo "bla@some.com;john@home.com" | sed -e 's/;/\n/g'
bla@some.com
john@home.com

4 Stimmen

-1 Was ist, wenn die Zeichenfolge Leerzeichen enthält? zum Beispiel IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) ) erzeugt in diesem Fall ein Array mit 8 Elementen (ein Element für jedes Wort, das durch Leerzeichen getrennt ist), anstatt 2 (ein Element für jede Zeile, die durch einen Doppelpunkt getrennt ist)

5 Stimmen

@Luca Nein, das sed-Skript erzeugt genau zwei Zeilen. Wenn Sie das Skript in ein Bash-Array einfügen (das standardmäßig an Leerzeichen geteilt wird), werden mehrere Einträge erstellt

0 Stimmen

Das ist genau der Punkt: der OP muss Einträge in einem Array speichern, um eine Schleife darüber zu ziehen, wie Sie in seinen Bearbeitungen sehen können. Ich denke, Ihre (gute) Antwort hat vergessen zu erwähnen, dass man arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) ) um dies zu erreichen, und den Rat, IFS zu ändern, um IFS=$'\n' für diejenigen, die in Zukunft hier landen und eine Zeichenkette mit Leerzeichen aufteilen müssen. (und sie anschließend wiederherstellen muss) :)

73voto

Ashok Punkte 729

Das funktioniert auch:

IN="bla@some.com;john@home.com"
echo ADD1=`echo $IN | cut -d \; -f 1`
echo ADD2=`echo $IN | cut -d \; -f 2`

Seien Sie vorsichtig, diese Lösung ist nicht immer korrekt. Wenn Sie nur "bla@some.com" übergeben, wird es sowohl ADD1 als auch ADD2 zugewiesen.

1 Stimmen

Sie können -s verwenden, um das genannte Problem zu vermeiden: superuser.com/questions/896800/ "-f, --fields=LIST wählt nur diese Felder aus; gibt auch jede Zeile aus, die kein Begrenzungszeichen enthält, es sei denn, die Option -s ist angegeben"

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