Qual è il significato di IFS = $ '\ n' negli script bash?


163

All'inizio di uno script di shell bash c'è la seguente riga:

IFS=$'\n'

Qual è il significato dietro questa raccolta di simboli?



la sintassi di VIM lo evidenzia come un errore per me; risolvere?
theonlygusti,

IFS=$'\n'è una da bash (+ altre shell, utilizzare ANSI-C Citando , per soluzioni alternative vedere stackoverflow.com/questions/10748703/...
pevik

Risposte:


199

IFSsta per "separatore di campo interno". Viene utilizzato dalla shell per determinare come eseguire la suddivisione delle parole, ovvero come riconoscere i confini delle parole.

Prova questo in una shell come bash (altre shell possono gestirlo in modo diverso, ad esempio zsh):

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

Il valore predefinito per è IFScostituito da caratteri spazi bianchi (per essere precisi: spazio, tabulazione e nuova riga). Ogni personaggio può essere un limite di parole. Quindi, con il valore predefinito di IFS, il ciclo sopra verrà stampato:

Word: foo:bar
Word: baz
Word: rab

In altre parole, la shell pensa che lo spazio bianco sia un limite di parole.

Ora prova a impostare IFS=:prima di eseguire il ciclo. Questa volta, il risultato è:

Word: foo
Word: bar baz rab

Ora, anche il guscio si divide mystringin parole, ma ora tratta solo i due punti come il limite delle parole.

Il primo carattere di IFSè speciale: viene utilizzato per delimitare le parole nell'output quando si utilizza la $*variabile speciale (esempio preso dalla Guida allo scripting Advanced Bash , dove è anche possibile trovare ulteriori informazioni su variabili speciali come quella):

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

Paragonare a:

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

Si noti che in entrambi gli esempi, il guscio sarà ancora trattare tutti i personaggi :, -e ;come i confini di parola. L'unica cosa che cambia è il comportamento di $*.

Un'altra cosa importante da sapere è come viene trattato il cosiddetto "spazio bianco IFS" . Fondamentalmente, non appena IFSinclude i caratteri degli spazi bianchi, lo spazio bianco iniziale e finale viene rimosso dalla stringa da dividere prima di elaborarlo e una sequenza di caratteri di spazi bianchi consecutivi delimita anche i campi. Tuttavia, questo vale solo per quei caratteri di spazi bianchi che sono effettivamente presenti in IFS.

Ad esempio, diamo un'occhiata alla stringa "a:b:: c d "(spazio finale e due caratteri spaziali tra ce d).

  1. Con IFS=:esso sarà suddiviso in quattro campi: "a", "b", ""(stringa vuota) e " c d "(di nuovo, due spazi tra ce d). Nota lo spazio bianco iniziale e finale nell'ultimo campo.
  2. Con IFS=' :', esso sarà suddiviso in cinque campi: "a", "b", ""(stringa vuota), "c"e "d". Nessuno spazio bianco iniziale e finale da nessuna parte.

Nota come più caratteri di spazi bianchi consecutivi delimitano due campi nel secondo esempio, mentre non lo fanno più due punti consecutivi consecutivi (poiché non sono caratteri di spazi bianchi).

Per quanto riguarda IFS=$'\n', cioè una ksh93sintassi supportata anche da bash, zsh, mkshe FreeBSD sh(con variazioni tra tutte le shell). Citando la manpage di bash:

Le parole del modulo $ 'stringa' sono trattate in modo speciale. La parola si espande in "stringa", con i caratteri con escape backslash sostituiti come specificato dallo standard ANSI C.

\nè la sequenza di escape per una nuova riga, quindi IFSfinisce per essere impostata su un singolo carattere di nuova riga.


3
Questo è buono, ma, secondo me, faresti molto meglio a leggere e comprendere le specifiche POSIX piuttosto che la bashguida agli script, o altro. In linea di massima, le informazioni disponibili su tali collegamenti mancano in modi importanti. Ad ogni modo, quindi, mancano due punti cruciali per quanto riguarda la suddivisione delle conchiglie: globbing e spazi bianchi IFS.
Mikeserv,

@mikeserv Grazie, ho aggiunto alcune informazioni sullo spazio bianco IFS. Non lo sapevo. :)
martedì

4
Non così rilevante, ma se sei curioso, potresti voler vedere come unset IFSfa una shell a comportarsi in modo molto diverso rispetto a IFS=. Anche il primo byte in IFS è speciale "${named_array[*]}", ma nessuno dei due conta quando l'espansione non è quotata ..
mikeserv

Alcuni altri punti: la suddivisione in 1 parola, governata da $IFSè una delle due cose principali eseguite durante l'espansione di una variabile non quotata nel contesto dell'elenco (è la splitparte split+globdell'operatore). L'altro è sconvolgente. Quando si utilizza la suddivisione del lavoro, in genere è necessario emettere set -fper disabilitare la globparte.
Stéphane Chazelas,

3
3- $IFSè anche usato dal readcomando incorporato
Stéphane Chazelas,

22

All'interno delle virgolette singole a bambola, alcuni personaggi vengono valutati appositamente. Ad esempio, \nviene tradotto in una nuova riga.

Quindi, questa particolare riga assegna la nuova riga alla variabile IFS. IFS, a sua volta, è una variabile speciale in bash: Separatore di campo interno. Come man bashdice, esso

è usato per la divisione delle parole dopo l'espansione e per dividere le linee in parole con il readcomando incorporato. Il valore predefinito è <space><tab><newline>.


5
+1 per menzionare dollared single quotesche è diverso dalle semplici virgolette singole.
Snowcrash,

2
@Snowcrash +1 per aver detto +1 per la menzione di virgolette singole a bambola che è diverso dalle semplici virgolette singole . Spiacente, non ho potuto farne a meno :) Ma in realtà è davvero una buona cosa sottolineare perché è importante!
Pryftan,

1
@Pryftan +1 per +1 per +1 ... sai ... è davvero importante.
0xc0de,

@ 0xc0de Decisamente d'accordo! Grazie per quello! :)
Pryftan,

15

In breve, IFS=$'\n'assegnare newline \nalla variabile IFS.

$'string'Il costrutto è un meccanismo di quotazione che utilizza per decodificare ANSI C come sequenze di escape. Questa sintassi viene da ksh93, ed era portatile per guscio moderno come bash, zsh, pdksh, busybox sh.

Questa sintassi non è definita da POSIX, ma è stata accettata per il numero 7 di SUS .


-1

Ho preferito spiegare $IFScon un esempio:
supponiamo che tu voglia cp o mv o un altro file che procede, IFS è vuoto per impostazione predefinita, quando i tuoi file hanno meta char o spazio come:
Linux Administration.pdfo Free Software Fundation.ogg, certo che avrai un problema, perché: Linux considera un param separato e Administartion considerano un parametro separato. Quindi bash ha built-in variable, Quindi è possibile inizializzare a IFS==$(echo -en "\n\b"), Quindi bash scartare qualsiasi meta char e spazio tra il nome del file, ad esempio:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.