it-swarm.com.de

Wie teile ich eine Zeichenfolge an einem Trennzeichen in Bash auf?

Ich habe diese Zeichenfolge in einer Variablen gespeichert:

IN="[email protected];[email protected]"

Jetzt möchte ich die Zeichenfolgen nach dem Trennzeichen ; aufteilen, sodass ich Folgendes habe:

ADDR1="[email protected]"
ADDR2="[email protected]"

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


Nach Vorschlägen aus den folgenden Antworten kam ich zu folgendem Ergebnis:

#!/usr/bin/env bash

IN="[email protected];[email protected]"

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

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

Ausgabe:

> [[email protected]]
> [[email protected]]

Es gab eine Lösung, bei der Internal_field_separator (IFS) auf ; gesetzt wurde. Ich bin nicht sicher, was mit dieser Antwort passiert ist. Wie können Sie IFS auf die Standardeinstellung zurücksetzen?

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

IN="[email protected];[email protected]"

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

IFS=$OIFS

Übrigens, als ich es versuchte

mails2=($IN)

Ich habe nur den ersten String erhalten, als ich ihn in einer Schleife gedruckt habe, ohne Klammern um $IN, es funktioniert.

1813
stefanB

Sie können die Variable internes Feldtrennzeichen (IFS) festlegen und dann in ein Array analysieren lassen. Wenn dies in einem Befehl geschieht, erfolgt die Zuordnung zu IFS nur zur Umgebung dieses einzelnen Befehls (zu read). Anschließend wird die Eingabe anhand des Variablenwerts IFS in ein Array analysiert, über das wir dann iterieren können.

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

Dabei wird eine durch ; getrennte Zeile von Elementen analysiert und in ein Array verschoben. Material für die Verarbeitung von $IN, jedes Mal eine durch ; getrennte Eingabezeile:

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

Entnommen aus Bash Shell Script Split Array:

IN="[email protected];[email protected]"
arrIN=(${IN//;/ })

Erläuterung:

Diese Konstruktion ersetzt alle Vorkommen von ';' (das anfängliche // bedeutet globales Ersetzen) in der Zeichenfolge IN durch ' ' (ein einzelnes Leerzeichen) und interpretiert dann die durch Leerzeichen getrennte Zeichenfolge als Array (das tun die umgebenden Klammern).

Die Syntax, die in geschweiften Klammern verwendet wird, um jedes ';' -Zeichen durch ein ' ' -Zeichen zu ersetzen, heißt Parametererweiterung .

Es gibt einige häufige Fallstricke:

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

Wenn es Ihnen nichts ausmacht, sie sofort zu verarbeiten, 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.

224
Chris Lutz

Kompatible Antwort

Zu dieser SO Frage gibt es bereits viele verschiedene Möglichkeiten, dies in bash zu tun. Aber bash hat viele spezielle Funktionen, so genannte bashism, die gut funktionieren, aber das wird nicht Arbeit in einem anderen Shell .

Insbesondere sind Arrays , assoziative Arrays und Mustersubstitution rein bashisms und funktionieren möglicherweise nicht unter anderen Shells .

Auf meinem Debian GNU/Linux gibt es eine Standard Shell mit dem Namen dash , aber ich kenne viele Leute, die gerne ksh verwenden.

Schließlich gibt es in sehr kleinen Situationen ein spezielles Tool namens busybox mit seinem eigenen Shell-Interpreter ( ash ).

Angeforderte Zeichenfolge

Das String-Beispiel in SO question lautet:

IN="[email protected];[email protected]"

Da dies bei Leerzeichen nützlich sein kann und bei Leerzeichen das Ergebnis der Routine ändern kann, bevorzuge ich die Verwendung dieser Beispielzeichenfolge:

 IN="[email protected];[email protected];Full Name <[email protected]>"

Geteilte Zeichenfolge basierend auf dem Trennzeichen in Bash (Version> = 4.2)

Unter pure bash können wir Arrays und IFS verwenden:

var="[email protected];[email protected];Full Name <[email protected]>"
oIFS="$IFS"
IFS=";"
declare -a fields=($var)
IFS="$oIFS"
unset oIFS
IFS=\; read -a fields <<<"$IN"

Wenn Sie diese Syntax in der letzten Bash verwenden, ändern Sie $IFS nicht für die aktuelle Sitzung, sondern nur für den aktuellen Befehl:

set | grep ^IFS=
IFS=$' \t\n'

Nun wird der String var aufgeteilt und in einem Array gespeichert (mit dem Namen fields):

set | grep ^fields=\\\|^var=
fields=([0]="[email protected]" [1]="[email protected]" [2]="Full Name <[email protected]>")
var='[email protected];[email protected];Full Name <[email protected]>'

Wir könnten mit declare -p einen variablen Inhalt anfordern:

declare -p IN fields
declare -- IN="[email protected];[email protected];Full Name <[email protected]>"
declare -a fields=([0]="[email protected]" [1]="[email protected]" [2]="Full Name <[email protected]>")

read ist die schnellste Methode, um die Aufteilung durchzuführen, da keine Gabeln und keine externen Ressourcen aufgerufen werden.

Von dort aus können Sie die Syntax verwenden, die Sie bereits für die Verarbeitung der einzelnen Felder kennen:

for x in "${fields[@]}";do
    echo "> [$x]"
    done
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]

oder lösche jedes Feld nach der Verarbeitung (ich mag diesen Shifting Ansatz):

while [ "$fields" ] ;do
    echo "> [$fields]"
    fields=("${fields[@]:1}")
    done
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]

oder auch für einfachen Ausdruck (kürzere Syntax):

printf "> [%s]\n" "${fields[@]}"
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]

Update: Letzte Bash > = 4.4

Sie könnten mit mapfile spielen:

mapfile -td \; fields < <(printf "%s\0" "$IN")

Diese Syntax bewahrt Sonderzeichen, Zeilenumbrüche und leere Felder!

Wenn Sie sich nicht für leere Felder interessieren, können Sie:

mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}")   # drop '\n' added by '<<<'

Aber Sie könnten Felder durch Funktion verwenden:

myPubliMail() {
    printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
    # mail -s "This is not a spam..." "$2" </path/to/body
    printf "\e[3D, done.\n"
}

mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail

(Anmerkung: \0 am Ende des Formatstrings sind nutzlos, während Sie sich nicht um leere Felder am Ende des Strings kümmern.)

mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail

Wird so etwas rendern wie:

Seq:      0: Sending mail to '[email protected]', done.
Seq:      1: Sending mail to '[email protected]', done.
Seq:      2: Sending mail to 'Full Name <[email protected]>', done.

Oder Neue Zeile durch <<< Bash-Syntax in Funktion einfügen:

myPubliMail() {
    local seq=$1 dest="${2%$'\n'}"
    printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
    # mail -s "This is not a spam..." "$dest" </path/to/body
    printf "\e[3D, done.\n"
}

mapfile <<<"$IN" -td \; -c 1 -C myPubliMail

Gibt die gleiche Ausgabe aus:

Seq:      0: Sending mail to '[email protected]', done.
Seq:      1: Sending mail to '[email protected]', done.
Seq:      2: Sending mail to 'Full Name <[email protected]>', done.

Geteilte Zeichenfolge basierend auf dem Trennzeichen in Shell

Wenn Sie jedoch etwas schreiben möchten, das unter vielen Shells verwendbar ist, müssen Sie keine Bashismen verwenden .

Es gibt eine Syntax, die in vielen Shells verwendet wird, um einen String über das erste oder letzte Vorkommen einer Teilzeichenfolge zu teilen:

${var#*SubStr}  # will drop begin of string up to first occur of `SubStr`
${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
${var%SubStr*}  # will drop part of string from last occur of `SubStr` to the end
${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end

(Das Fehlen davon ist der Hauptgrund für meine Antwortveröffentlichung;)

Wie von Score_Under hervorgehoben:

# und % löschen die kürzest mögliche übereinstimmende Zeichenfolge und

## und %% löschen so lange wie möglich.

dabei bedeuten # und ## von links (Anfang) der Zeichenfolge und

% und %% meand von rechts (Ende) der Zeichenfolge.

Dieses kleine Beispielskript funktioniert gut unter bash , dash , ksh , busybox und wurde unter Mac-OS bash getestet zu:

var="[email protected];[email protected];Full Name <[email protected]>"
while [ "$var" ] ;do
    iter=${var%%;*}
    echo "> [$iter]"
    [ "$var" = "$iter" ] && \
        var='' || \
        var="${var#*;}"
  done
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]

Habe Spaß!

167
F. Hauri

Ich habe einige Antworten gesehen, die auf den Befehl cut verweisen, aber alle wurden gelöscht. Es ist ein wenig seltsam, dass niemand darauf eingegangen ist, da es meiner Meinung nach einer der nützlicheren Befehle ist, um solche Dinge zu tun, insbesondere um begrenzte Protokolldateien zu analysieren.

Wenn Sie dieses spezielle Beispiel in ein Bash-Skript-Array aufteilen, ist tr wahrscheinlich effizienter, aber cut kann verwendet werden und ist effektiver, wenn Sie bestimmte Felder aus der Mitte ziehen möchten.

Beispiel:

$ echo "[email protected];[email protected]" | cut -d ";" -f 1
[email protected]
$ echo "[email protected];[email protected]" | cut -d ";" -f 2
[email protected]

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

Dies ist nützlicher, wenn Sie eine begrenzte Protokolldatei mit folgenden Zeilen haben:

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

cut ist sehr praktisch, um diese Datei cat und ein bestimmtes Feld für die weitere Verarbeitung auszuwählen.

139
DougW

Das hat bei mir funktioniert:

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

Wie wäre es mit diesem Ansatz:

IN="[email protected];[email protected]" 
set -- "$IN" 
IFS=";"; declare -a Array=($*) 
echo "${Array[@]}" 
echo "${Array[0]}" 
echo "${Array[1]}" 

Quelle

84
errator
62
lothar

Das funktioniert auch:

IN="[email protected];[email protected]"
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 "[email protected]" übergeben, wird es sowohl ADD1 als auch ADD2 zugewiesen.

62
Ashok

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

echo "[email protected];[email protected]" | awk -F';' '{print $1,$2}'

werde geben

[email protected] [email protected]

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

47
Tony

Eine andere Einstellung Darrons Antwort , so mache ich es:

IN="[email protected];[email protected]"
read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)
31
nickjb

In Bash funktioniert dies auch dann, wenn Ihre Variable Zeilenumbrüche enthält:

IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")

Aussehen:

$ in=$'one;two three;*;there is\na newline\nin this field'
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
a newline
in this field")'

Der Trick, damit dies funktioniert, besteht darin, die Option -d von read (Trennzeichen) mit einem leeren Trennzeichen zu verwenden, sodass read gezwungen wird, alles zu lesen, was eingegeben wird. Und wir füttern read genau mit dem Inhalt der Variablen in, ohne Zeilenumbruch dank printf. Beachten Sie, dass wir das Trennzeichen auch in printf einfügen, um sicherzustellen, dass die an read übergebene Zeichenfolge ein nachgestelltes Trennzeichen hat. Ohne dies würde read potenzielle nachgestellte leere Felder abschneiden:

$ in='one;two;three;'    # there's an empty field
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'

das nachgestellte leere Feld bleibt erhalten.


Update für Bash≥4.4

Seit Bash 4.4 unterstützt das eingebaute mapfile (aka readarray) die Option -d, um ein Trennzeichen anzugeben. Daher ist ein anderer kanonischer Weg:

mapfile -d ';' -t array < <(printf '%s;' "$in")
27
gniourf_gniourf

Wie wäre es mit diesem einen Liner, wenn Sie keine Arrays verwenden:

IFS=';' read ADDR1 ADDR2 <<<$IN
22
Darron

Hier ist ein sauberer 3-Liner:

in="[email protected];[email protected];[email protected];[email protected]"
IFS=';' list=($in)
for item in "${list[@]}"; do echo $item; done

wobei IFS Wörter basierend auf dem Trennzeichen abgrenzen und () verwendet wird, um ein Array zu erstellen. Dann wird [@] verwendet, um jedes Element als separates Wort zurückzugeben.

Wenn Sie danach Code haben, müssen Sie auch $IFS wiederherstellen, z. unset IFS.

19
kenorb

Ohne das IFS einzustellen

Wenn Sie nur einen Doppelpunkt haben, können Sie das tun:

a="foo:bar"
b=${a%:*}
c=${a##*:}

sie erhalten:

b = foo
c = bar
17
Emilien Brigand

Die folgende Bash/zsh-Funktion teilt das erste Argument auf das durch das zweite Argument angegebene Trennzeichen:

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 der Befehl

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

ausbeuten

a
b
c

Diese Ausgabe kann beispielsweise an andere Befehle weitergeleitet werden. Beispiel:

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

Gegenüber den anderen angegebenen Lösungen hat diese folgende Vorteile:

  • IFS wird nicht überschrieben: Durch das Überschreiben von IFS über eine Schleife wird der neue Wert aufgrund des dynamischen Bereichs selbst lokaler Variablen nicht in Funktionsaufrufe übernommen, die innerhalb der Schleife ausgeführt werden.

  • Arrays werden nicht verwendet: Das Einlesen eines Strings 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 "[email protected]"
10
Halle Knast

Es gibt einen einfachen und intelligenten Weg:

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

Sie müssen jedoch gnu xargs verwenden, BSD xargs kann -d delim nicht unterstützen. Wenn Sie Apple mac wie ich verwenden. Sie können gnu xargs installieren:

brew install findutils

dann

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

sie können awk auf viele Situationen anwenden

echo "[email protected];[email protected]"|awk -F';' '{printf "%s\n%s\n", $1, $2}'

auch Sie können dies verwenden

echo "[email protected];[email protected]"|awk -F';' '{print $1,$2}' OFS="\n"
7
shuaihanhungry

Dies ist der einfachste Weg, dies zu tun.

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

Hier gibt es einige coole Antworten (vor allem Fehler), aber für etwas Analoges, das in andere Sprachen aufgeteilt werden kann - was ich unter der ursprünglichen Frage verstanden habe - habe ich Folgendes entschieden:

IN="[email protected];[email protected]"
declare -a a="(${IN/;/ })";

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

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

WICHTIGE NOTIZ:

Dies funktioniert in Fällen, in denen sich keine Sorgen um Leerzeichen machen lassen, die mein Problem gelöst haben, Ihr Problem jedoch möglicherweise nicht lösen. Fahren Sie in diesem Fall mit den $IFS -Lösungen fort.

4
eukras
IN="[email protected];[email protected]"
IFS=';'
read -a IN_arr <<< "${IN}"
for entry in "${IN_arr[@]}"
do
    echo $entry
done

Ausgabe

[email protected]
[email protected]

System: Ubuntu 12.04.1

3
rashok

Zwei langweilige Alternativen, für die keines der beiden Bash-Arrays erforderlich ist:

Fall 1: Schön und einfach: Verwenden Sie eine NewLine als Record-Separator ... zB.

IN="[email protected]
[email protected]"

while read i; do
  # process "$i" ... eg.
    echo "[email:$i]"
done <<< "$IN"

Hinweis: In diesem ersten Fall wird kein Unterprozess zur Unterstützung der Listenbearbeitung aufgeteilt.

Idee: Vielleicht lohnt es sich, NL ausgiebig intern zu verwenden und nur dann in eine andere RS zu konvertieren, wenn das Endergebnis generiert wird . extern .

Fall 2: Verwenden eines ";" als Datensatztrenner ... zB.

NL="
" IRS=";" ORS=";"

conv_IRS() {
  exec tr "$1" "$NL"
}

conv_ORS() {
  exec tr "$NL" "$1"
}

IN="[email protected];[email protected]"
IN="$(conv_IRS ";" <<< "$IN")"

while read i; do
  # process "$i" ... eg.
    echo -n "[email:$i]$ORS"
done <<< "$IN"

In beiden Fällen kann eine Unterliste innerhalb der Schleife erstellt werden, die nach Beendigung der Schleife persistent ist. Dies ist nützlich, wenn Sie Listen im Speicher bearbeiten, statt Listen in Dateien zu speichern. {S. bleib ruhig und mach weiter B-)}

2
NevilleDNZ

Abgesehen von den fantastischen Antworten, die bereits gegeben wurden, müssen Sie nur die Daten ausdrucken, die Sie möglicherweise mit awk verwenden:

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

Dadurch wird das Feldtrennzeichen auf ; gesetzt, sodass die Felder mit einer for -Schleife durchlaufen und entsprechend gedruckt werden können.

Prüfung

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

Mit einem anderen Eingang:

$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "a;b;c   d;e_;f"
> [a]
> [b]
> [c   d]
> [e_]
> [f]
2
fedorqui
IN='[email protected];[email protected];Charlie Brown <[email protected];!"#$%&/()[]{}*? 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:

[email protected]
[email protected]
Charlie Brown <[email protected]
!"#$%&/()[]{}*? are no problem
simple is beautiful :-)

Erläuterung: Eine einfache Zuweisung mit Klammern () konvertiert eine durch Semikolons getrennte Liste in ein Array, vorausgesetzt, Sie haben dabei das richtige IFS. Die Standard-FOR-Schleife behandelt wie gewohnt einzelne Elemente in diesem Array. Beachten Sie, dass die für die IN-Variable angegebene Liste in Anführungszeichen gesetzt werden muss, dh mit einzelnen Häkchen.

IFS muss gespeichert und wiederhergestellt werden, da Bash eine Zuweisung nicht wie einen Befehl behandelt. Eine alternative Problemumgehung besteht darin, die Zuweisung in eine Funktion zu packen und diese Funktion mit einem geänderten IFS aufzurufen. In diesem Fall ist ein separates Speichern/Wiederherstellen von IFS nicht erforderlich. Vielen Dank für "Bize", dass Sie darauf hingewiesen haben.

2
ajaaskel

Wenn kein Leerzeichen, warum nicht?

IN="[email protected];[email protected]"
arr=(`echo $IN | tr ';' ' '`)

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

Okay Leute!

Hier ist meine Antwort!

DELIMITER_VAL='='

read -d '' F_ABOUT_DISTRO_R <<"EOF"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
NAME="Ubuntu"
VERSION="14.04.4 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.4 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
EOF

SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%s\n", $i}}' <<<"${F_ABOUT_DISTRO_R}")
while read -r line; do
   SPLIT+=("$line")
done <<< "$SPLIT_NOW"
for i in "${SPLIT[@]}"; do
    echo "$i"
done

Warum ist dieser Ansatz "das Beste" für mich?

Aus zwei Gründen:

  1. Sie tun müssen nicht entkommen das Trennzeichen;
  2. Sie haben kein Problem mit Leerzeichen. Der Wert wird im Array korrekt getrennt!

[] 's

1
Eduardo Lucio

In der Android Shell funktionieren die meisten 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

dabei bedeutet // globales Ersetzen.

Verwenden Sie das integrierte set, um das Array [email protected] zu laden:

IN="[email protected];[email protected]"
IFS=';'; set $IN; IFS=$' \t\n'

Dann lass die Party beginnen:

echo $#
for a; do echo $a; done
ADDR1=$1 ADDR2=$2
1
jeberle

Vielleicht nicht die eleganteste Lösung, funktioniert aber mit * und Leerzeichen:

IN="[email protected] me.com;*;[email protected]"
for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
do
   echo "> [`echo $IN | cut -d';' -f$i`]"
done

Ausgänge

> [[email protected] me.com]
> [*]
> [[email protected]]

Anderes Beispiel (Trennzeichen am Anfang und Ende):

IN=";[email protected] me.com;*;[email protected];"
> []
> [[email protected] me.com]
> [*]
> [[email protected]]
> []

Grundsätzlich werden alle Zeichen außer ; entfernt, wodurch delims erzeugt wird, z. ;;;. Dann durchläuft es eine for Schleife von 1 zu number-of-delimiters, gezählt von ${#delims}. Der letzte Schritt besteht darin, den $i -ten Teil mit cut sicher abzurufen.

0
Petr Újezdský

Einzeilig, um einen durch ';' getrennten String zu teilen in ein Array ist:

IN="[email protected];[email protected]"
ADDRS=( $(IFS=";" echo "$IN") )
echo ${ADDRS[0]}
echo ${ADDRS[1]}

Dadurch wird IFS nur in eine Subshell unterteilt, sodass Sie sich nicht um das Speichern und Wiederherstellen seines Werts kümmern müssen.

0
Michael Hale

Dies wird sogar mit Leerzeichen umgehen:

IFS=';' read ADDR1 ADDR2 <<< $(echo ${IN})
0
Mat Bess