Was bedeutet IFS = $ '\ n' in Bash-Skripten?

163

Am Anfang eines Bash-Shell-Skripts steht die folgende Zeile:

IFS=$'\n'

Welche Bedeutung hat diese Symbolsammlung?

Abdul Al Hazred
quelle
3
Siehe auch unix.stackexchange.com/questions/26784/understanding-ifs und die darin genannten Fragen.
Gilles
Die vim-Syntax hebt dies für mich als Fehler hervor. Fix?
theonlygusti
IFS=$'\n'ist ein bashism (+ andere Schalen, verwenden ANSI-C Zitiert für Abhilfen siehe stackoverflow.com/questions/10748703/...
pevik

Antworten:

199

IFSsteht für "internes Feldtrennzeichen". Es wird von der Shell verwendet, um zu bestimmen, wie die Wortteilung durchgeführt wird, dh wie Wortgrenzen erkannt werden.

Versuchen Sie dies in einer Shell wie bash (andere Shells können dies anders handhaben, zum Beispiel zsh):

mystring="foo:bar baz rab"
for word in $mystring; do
  echo "Word: $word"
done

Der Standardwert für IFSbesteht aus Leerzeichen (um genau zu sein: Leerzeichen, Tabulator und Zeilenvorschub). Jedes Zeichen kann eine Wortgrenze sein. Daher wird mit dem Standardwert von IFSdie obige Schleife gedruckt:

Word: foo:bar
Word: baz
Word: rab

Mit anderen Worten, die Shell denkt, dass Leerzeichen eine Wortgrenze sind.

Versuchen Sie nun die Einstellung, IFS=:bevor Sie die Schleife ausführen. Dieses Mal lautet das Ergebnis:

Word: foo
Word: bar baz rab

Jetzt teilt sich die Shell auch mystringin Wörter auf - aber jetzt wird nur ein Doppelpunkt als Wortgrenze behandelt.

Das erste Zeichen von IFSist special: Es wird verwendet, um Wörter in der Ausgabe zu begrenzen, wenn die spezielle $*Variable verwendet wird (Beispiel aus dem Advanced Bash Scripting Guide , in dem Sie auch weitere Informationen zu speziellen Variablen wie dieser finden):

$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
w:x:y:z

Vergleichen mit:

$ bash -c 'set w x y z; IFS="-:;"; echo "$*"'
w-x-y-z

Beachten Sie, dass in beiden Beispielen wird die Schale noch alle Zeichen behandeln :, -und ;als Wortgrenzen. Das einzige, was sich ändert, ist das Verhalten von $*.

Ein weiterer wichtiger Aspekt ist die Behandlung des so genannten "IFS-Whitespace" . Grundsätzlich werden IFSführende und nachfolgende Leerzeichen , sobald sie Leerzeichen enthalten, von der zu teilenden Zeichenfolge entfernt, bevor sie verarbeitet werden. Eine Folge von aufeinanderfolgenden Leerzeichen begrenzt die Felder ebenfalls. Dies gilt jedoch nur für die Whitespace-Zeichen, die tatsächlich in vorhanden sind IFS.

Betrachten wir zum Beispiel die Zeichenfolge "a:b:: c d "(Leerzeichen am Ende und zwei Leerzeichen zwischen cund d).

  1. Mit IFS=:ihm würde in vier Felder aufgeteilt werden: "a", "b", ""(leere Zeichenkette) und " c d "(wieder zwei Räume zwischen cund d). Beachten Sie das führende und nachfolgende Leerzeichen im letzten Feld.
  2. Mit IFS=' :'wäre es in fünf Felder unterteilt werden: "a", "b", ""(leere Zeichenkette), "c"und "d". Kein führendes und nachfolgendes Leerzeichen.

Beachten Sie, wie im zweiten Beispiel mehrere aufeinanderfolgende Leerzeichen zwei Felder voneinander trennen, während dies bei mehreren aufeinanderfolgenden Doppelpunkten nicht der Fall ist (da es sich nicht um Leerzeichen handelt).

Was IFS=$'\n'ist , dass eine ksh93Syntax auch unterstützt bash, zsh, mkshund FreeBSD sh(mit Variationen zwischen allen Schalen). Zitieren der Bash-Manpage:

Wörter der Form $ 'string' werden speziell behandelt. Das Wort wird zu "Zeichenfolge" erweitert, wobei mit einem Backslash versehene Zeichen gemäß dem ANSI C-Standard ersetzt werden.

\nist die Escape-Sequenz für eine neue Zeile und wird daher IFSauf ein einzelnes Zeichen für eine neue Zeile festgelegt.

Tblue
quelle
3
Das ist gut, aber meiner Meinung nach tun Sie viel besser, um die POSIX-Spezifikation zu lesen und zu verstehen, als die bashSkriptanleitung oder was auch immer. In der Hauptsache fehlen die Informationen, die auf solchen Links verfügbar sind, in wichtigen Punkten. Auf jeden Fall fehlen also zwei wichtige Punkte beim Aufteilen der Shell - Globbing und IFS-Whitespace.
mikeserv
@mikeserv Danke, ich habe einige Informationen zu IFS-Whitespace hinzugefügt. Wusste nichts davon. :)
Tblue
4
Nicht so relevant, aber wenn Sie neugierig sind, möchten Sie vielleicht wissen, wie sich unset IFSeine Shell ganz anders verhält als IFS=. Auch das erste Byte in IFS ist etwas Besonderes "${named_array[*]}"- aber es spielt keine
Rolle
Noch ein paar Punkte: Die 1-Wort-Aufteilung, die von geregelt wird, $IFSist eine der beiden Hauptaufgaben, die beim Erweitern einer Variablen ohne Anführungszeichen im Listenkontext ausgeführt wird (dies ist der splitTeil des split+globOperators). Der andere ist am Fressen. Wenn Sie die Arbeitsteilung verwenden, müssen Sie im Allgemeinen ein Problem set -flösen, um das globTeil zu deaktivieren .
Stéphane Chazelas
3
3- $IFSwird auch vom readeingebauten Befehl verwendet
Stéphane Chazelas
22

In einfachen Anführungszeichen werden einige Zeichen speziell ausgewertet. Beispielsweise \nwird in eine neue Zeile übersetzt.

Diese bestimmte Zeile weist der Variablen IFS also eine neue Zeile zu. IFS wiederum ist eine spezielle Variable in bash: Internal Field Separator. Wie man bashgesagt es

wird zum Teilen von Wörtern nach der Erweiterung und zum Teilen von Zeilen in Wörter mit dem readeingebauten Befehl verwendet. Der Standardwert ist <space><tab><newline>.

Choroba
quelle
5
+1 für die Erwähnung, dollared single quotesdie sich von einfachen einfachen Anführungszeichen unterscheidet.
Snowcrash
2
@Snowcrash +1 zu sagen +1 für erwähnen dollared einfacher Anführungszeichen , die von den einfachen einfachen Anführungszeichen unterscheiden . Sorry, konnte nicht anders :) Aber eigentlich ist es eine wirklich gute Sache, darauf hinzuweisen, weil es wichtig ist!
Pryftan
1
@Pryftan +1 für +1 für +1 ... weißt du ... es ist wirklich wichtig.
0xc0de
@ 0xc0de Auf jeden Fall einverstanden! Dank dafür! :)
Pryftan
15

Kurz gesagt, IFS=$'\n'ordnen Sie \nder Variablen einen Zeilenvorschub zu IFS.

$'string'construct ist ein Zitiermechanismus, mit dem ANSI C-ähnliche Escape-Sequenzen dekodiert werden. Diese Syntax stammt aus ksh93und war tragbar moderne Shell wie bash, zsh, pdksh, busybox sh.

Diese Syntax wird von POSIX nicht definiert, wurde jedoch für SUS-Problem 7 akzeptiert .

cuonglm
quelle
-1

Ich zu erklären , bevorzugt $IFSüber Beispiel:
Suppsoe Sie wollen cp oder mv oder eine andere Datei verarbeitend, IFS leer von defualt ist, wenn Sie Ihre Dateien Meta - Zeichen oder Platz haben , wie zum Beispiel:
Linux Administration.pdfoder Free Software Fundation.ogg, sicher werden Sie probelm haben, denn: Linux ein betrachten Separater Parameter und Administartion betrachten einen separaten Parameter. So hat Bash built-in variable, dann können Sie initialisieren IFS==$(echo -en "\n\b"), dann Bash verwerfen alle Metazeichen und Leerzeichen zwischen Dateinamen, zum Beispiel:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS
Persischer Golf
quelle