Frage Wie spalte ich eine Zeichenfolge auf einem Trennzeichen in Bash?


Ich habe diese Zeichenfolge in einer Variablen gespeichert:

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

Jetzt möchte ich die Saiten teilen ; Trennzeichen, damit ich:

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

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


Nach den Vorschlägen aus den Antworten unten habe ich folgendes gefunden, wonach ich gesucht habe:

#!/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 das Setzen beinhaltet Interner_Feldseparator (IFS) zu ;. Ich bin mir nicht sicher, was mit dieser Antwort passiert ist, wie wird sie zurückgesetzt? IFS Zurück zum Standard?

RE: IFS Lösung, ich habe das versucht und es funktioniert, ich behalte das alte IFS und dann stelle es wieder her:

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

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

IFS=$OIFS

BTW, als ich es versuchte

mails2=($IN)

Ich habe nur die erste Saite bekommen, wenn ich sie in einer Schleife ohne Klammern herumdrucke $IN Es klappt.


1507
2018-05-28 02:03


Ursprung


Antworten:


Sie können das einstellen interner Feldtrenner (IFS) Variable, und lassen Sie es dann in ein Array analysieren. Wenn dies in einem Befehl passiert, dann die Zuordnung zu IFS findet nur in der Umgebung dieses einzelnen Befehls statt (to read ). Es analysiert dann die Eingabe gemäß der IFS Variablenwert in ein Array, über den dann iteriert werden kann.

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
    # process "$i"
done

Es wird eine Zeile von Elementen analysieren, die durch ;, drück es in ein Array. Zeug für die Verarbeitung von ganzen $IN, jedes Mal, wenn eine Zeile der Eingabe durch getrennt wird ;:

 while IFS=';' read -ra ADDR; do
      for i in "${ADDR[@]}"; do
          # process "$i"
      done
 done <<< "$IN"

922
2018-05-28 02:23



Genommen von Bash-Shell-Skript-Split-Array:

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

Erläuterung:

Diese Konstruktion ersetzt alle Vorkommen von ';' (die Initiale // bedeutet global ersetzen) in der Zeichenfolge IN mit ' ' (ein einzelnes Leerzeichen), interpretiert dann die durch Leerzeichen getrennte Zeichenfolge als ein Array (das ist es, was die umgebenden Klammern tun).

Die in den geschweiften Klammern verwendete Syntax ersetzt jede ';' Charakter mit a ' ' Charakter wird aufgerufen Parametererweiterung.

Es gibt einige häufige Probleme:

  1. Wenn die ursprüngliche Zeichenfolge Leerzeichen enthält, müssen Sie sie verwenden IFS:
    • IFS=':'; arrIN=($IN); unset IFS;
  2. Wenn die ursprüngliche Zeichenfolge Leerzeichen enthält und Das Trennzeichen ist eine neue Zeile, die Sie festlegen können IFS mit:
    • IFS=$'\n'; arrIN=($IN); unset IFS;

743
2018-03-10 09:00



Wenn es Ihnen nichts ausmacht, sie sofort zu bearbeiten, mache ich das gerne:

for i in $(echo $IN | tr ";" "\n")
do
  # process
done

Sie könnten diese Art von Schleife verwenden, um ein Array zu initialisieren, aber es gibt wahrscheinlich einen einfacheren Weg, dies zu tun. Hoffe das hilft aber.


207
2018-05-28 02:09



Kompatible Antwort

Auf diese SO-Frage gibt es bereits viele verschiedene Möglichkeiten, dies zu tun . Aber Bash hat viele Besondere Funktionen, so genannt Bashismus das funktioniert gut, aber das wird in keinem anderen funktionieren .

Bestimmtes, Arrays, assoziatives Array, und Musterersetzung sind rein Bashismen und darf nicht unter anderen arbeiten Muscheln.

Auf meinem Debian GNU / Linux, da ist ein Standard Shell genannt , aber ich kenne viele Leute, die gerne benutzen .

Schließlich, in sehr kleiner Situation, gibt es ein spezielles Tool namens  mit seinem eigenen Shell-Interpreter ().

Angeforderte Zeichenfolge

Das String-Beispiel in SO-Frage ist:

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

Da dies nützlich sein könnte mit Leerzeichen und wie Leerzeichen könnte das Ergebnis der Routine ändern, bevorzuge ich diese Beispielzeichenfolge:

 IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

Auf String basierende Trennzeichenfolge in  (Version> = 4.2)

Unter rein Bash, können wir verwenden Arrays und IFS:

var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

oIFS="$IFS"
IFS=";"
declare -a fields=($var)
IFS="$oIFS"
unset oIFS


121
2018-04-13 14:20



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


80
2018-05-28 10:31



Ich habe ein paar Antworten auf das Thema gesehen cut Befehl, aber sie wurden alle gelöscht. Es ist ein wenig merkwürdig, dass sich niemand darum gekümmert hat, weil ich denke, dass es einer der nützlicheren Befehle für diese Art von Dingen ist, besonders für das Parsen von Log-Dateien mit Trennzeichen.

Im Falle der Aufteilung dieses spezifischen Beispiels in ein Bash-Skript-Array, tr ist wahrscheinlich effizienter, aber cut kann verwendet werden und ist effektiver, wenn Sie bestimmte Felder aus der Mitte ziehen möchten.

Beispiel:

$ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
bla@some.com
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
john@home.com

Sie können das natürlich in eine Schleife einfügen und den Parameter -f iterieren, um jedes Feld unabhängig zu ziehen.

Das wird nützlicher, wenn Sie eine getrennte Protokolldatei mit Zeilen wie folgt haben:

2015-04-27|12345|some action|an attribute|meta data

cut ist sehr praktisch in der Lage zu sein cat diese Datei und wählen Sie ein bestimmtes Feld für die weitere Verarbeitung.


74
2018-04-27 18:20



Das hat für mich funktioniert:

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

65
2017-08-11 20:45