Die bash ändert ihr Verhalten in Abhängigkeit vom Wert der Variablen „IFS“

18

Wenn ich die IFSVariable auf ein Leerzeichen setze , werden bashmehrere Leerzeichen als ein Leerzeichen behandelt ( myprogramein Programm, das die empfangenen Befehlszeilenargumente ausgibt):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

Wenn ich die IFSVariable jedoch auf ein Komma setze bash, werden mehrere Kommas nicht als ein Komma behandelt:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world

Warum das?

user267935
quelle
Nur als Referenz bedeutet "IFS" internes Feldtrennzeichen .
pr1268

Antworten:

21

Dies ist dokumentiert in man bash. Ein einzelnes Vorkommen eines Zeichens in IFS, das kein Leerzeichen ist, begrenzt ein Feld.

Von man bash:

Die Shell behandelt jedes IFS-Zeichen als Trennzeichen und teilt die Ergebnisse der anderen Erweiterungen in Wörter auf, wobei diese Zeichen als Feldterminatoren verwendet werden. Wenn IFS nicht gesetzt ist, oder der Wert genau <space><tab><newline>der Standard, dann Sequenzen <space>, <tab>und <newline>am Anfang und Ende der Ergebnisse der vorangegangenen Erweiterungen ignoriert werden, und jede Folge von IFS Zeichen , die nicht am Anfang oder Ende dient abgrenzen Wörter. Wenn IFS einen anderen Wert als den Standardwert hat, werden die Folgen der Leerzeichen, Tabulatoren und Zeilenumbrüche am Anfang und Ende des Wortes ignoriert, solange sich das Leerzeichen im Wert von IFS befindet (ein IFS-Leerzeichen) ). Jedes Zeichen in IFS, das kein IFS-Whitespace ist, begrenzt zusammen mit benachbarten IFS-Whitespace-Zeichen ein Feld. Eine Folge von IFS-Whitespace-Zeichen wird ebenfalls als Begrenzer behandelt. Wenn der Wert von IFS null ist, erfolgt keine Wortteilung. [Betonung hinzugefügt.]

Beispiele: Feldaufteilung

Wenn IFS keine Leerzeichen enthält, werden die Felder mit Leerzeichen versehen:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>

Wenn IFS sowohl Leerzeichen als auch ein Komma enthält, werden Folgen von Leerzeichen, gefolgt von einem Komma, gefolgt von Folgen von Leerzeichen als ein einzelnes Trennzeichen behandelt:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>

Folgen von Kommas werden als Folgen von leeren Feldern interpretiert:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>

Beispiele: führende und nachfolgende Leerzeichen

Wenn IFS kein Leerzeichen enthält, werden alle führenden und nachfolgenden Leerzeichen in den Feldern beibehalten:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >

Wenn IFS Leerzeichen enthält, werden alle führenden oder nachfolgenden Folgen von Leerzeichen entfernt:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>
John1024
quelle
Vielleicht ist auch hervorzuheben, dass "dann Sequenzen der Leerzeichen, Tabulatoren und Zeilenumbrüche am Anfang und Ende des Wortes ignoriert werden, solange das Leerzeichen den Wert von IFS hat"
Jeff Schaller
@ JeffSchaller Ausgezeichnete Idee: Ich habe gerade einen Abschnitt dazu hinzugefügt.
John1024
Was ist, wenn Sie eine durch Tabulatoren getrennte Datei mit fehlenden Werten haben? dh Sie möchten nicht, dass Registerkartenfolgen als einzelne Registerkarten behandelt werden. Außerdem enthalten die Felder Kommas, sodass dies nicht als Trennzeichen verwendet werden kann. Ist die einzige Lösung, um ein anderes Trennzeichen (nicht Tabulatoren) zu verwenden?
Davos
@Davos Für Daten, bei denen jedes Feld durch eine einzelne Registerkarte begrenzt ist, ist es möglicherweise natürlicher, andere Tools zu verwenden, die dies einfach handhaben, z. B. awkmit der -F'\t'Option oder cut. Wenn Sie über eine neuere Version von verfügen bash, können Sie die Felder möglicherweise auch mithilfe readarrayder -d$'\t'Option analysieren .
John1024