Ich habe ein Beispielskript geschrieben, um die Zeichenfolge zu teilen, aber es funktioniert nicht wie erwartet
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
Ausgabe
One
XX
X
17.0.0
17 0 0
aber ich erwartete die Ausgabe zu sein:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
user112232
quelle
quelle
Antworten:
Fix (siehe auch S. Chazelas 'Antwort für den Hintergrund) mit vernünftiger Ausgabe:
Ausgabe:
Anmerkungen:
Es ist besser, die bedingte 2. Schleife in die 1. Schleife zu setzen.
bash
pattern substitution ("${i//.}"
) prüft, ob.
ein Element ein enthält. (Einecase
Anweisung könnte einfacher sein, wenn auch dem OP -Code weniger ähnlich .)read
ing$array
durch Eingabe<<< "${ADDR[3]}"
weniger allgemein als<<< "$i"
. Sie müssen nicht wissen, welches Element das.
s hat.Der Code geht davon aus, dass das Drucken von " Element: 17.0.0 " nicht beabsichtigt ist. Wenn dieses Verhalten ist beabsichtigt, ersetzen Sie die Hauptschleife mit:
quelle
case $i in (*.*) ...
wäre ein kanonischer Weg , dies zu überprüfen ,$i
enthält.
(und auch tragbarsh
). Wenn Sie in Kshismen sind, sehen Sie auch:[[ $i = *.* ]]
case
in den Anmerkungen am Ende erwähnt, aber wir sind uns einig. (Da das OP sowohl<<<
als auch Arrays verwendet , ist dies keine großesh
Frage.)In alten Versionen mussten
bash
Sie danach Variablen zitieren<<<
. Das wurde in 4.4 behoben. In älteren Versionen wurde die Variable in IFS aufgeteilt und die resultierenden Wörter im Leerzeichen verbunden, bevor sie in der temporären Datei gespeichert wurden, aus der diese<<<
Umleitung besteht.In Version 4.2 und früher, wenn Buildins wie
read
oder umgeleitet werdencommand
, würde diese Aufteilung sogar das IFS für dieses Builtin erfordern (4.3 hat das behoben):Das in 4.3 festgelegte:
Aber
$a
unterliegt dort immer noch der Wortspaltung:In 4.4:
Geben Sie für die Portabilität auf ältere Versionen Ihre Variable an (oder verwenden Sie,
zsh
woher das<<<
kommt und wo dieses Problem nicht auftritt).Beachten Sie, dass dieser Ansatz zum Teilen einer Zeichenfolge nur für Zeichenfolgen funktioniert, die keine Zeilenumbrüche enthalten. Beachten Sie auch , dass
a..b.c.
wäre aufgeteilt in"a"
,""
,"b"
,"c"
(kein letztes Element leer).Um beliebige Zeichenfolgen zu teilen, können Sie stattdessen den Operator split + glob verwenden (was ihn zum Standard macht und das Speichern des Inhalts einer Variablen in einer temporären Datei wie
<<<
folgt vermeidet ):oder:
Das
''
soll ein nachfolgendes leeres Element beibehalten, falls vorhanden. Das würde auch ein leeres$var
in ein leeres Element aufteilen .Oder verwenden Sie eine Shell mit einem geeigneten Aufteilungsoperator:
zsh
::rc
::fish
quelle
Mit awk würde es dich eine Zeile kosten:
-F'[-.]'
- Feldtrennzeichen basierend auf mehreren Zeichen, in unserem Fall-
und.
Die Ausgabe:
quelle
IFS=-. read -r a array <<< "$IN"
Hier mein Weg:
Ergebnis wie erwartet:
quelle
$IN
ruft den Operator split + glob auf. Hier möchten Sie den Glob-Teil nicht (IN=*-*-/*-17.0.0
zum Beispiel anprobieren ), also möchten Sie dies tun,set -o noglob
bevor Sie ihn aufrufen. Siehe meine Antwort für Details.IFS
und das globale Festlegen. Sie möchten wirklich nur den Wert vonIFS
für ändern, wenn$IN
erweitert wird, und Sie möchten auch nicht, dass die Erweiterung mit dem Pfadnamen für die Erweiterung ausgeführt wird. AußerdemOIFS=$IFS
wird nicht zwischen den Fällen unterschiedenIFS
, in denen eine leere Zeichenfolge festgelegt wurde und in denen sieIFS
vollständig deaktiviert wurden.