Stavo leggendo questo thread: come passare in rassegna le righe di un file?
Che cosa è IFS
? E qual è il suo utilizzo nel contesto di for
-loops?
Stavo leggendo questo thread: come passare in rassegna le righe di un file?
Che cosa è IFS
? E qual è il suo utilizzo nel contesto di for
-loops?
Risposte:
IFS
sta per - è un personaggio che separa i campi. Nell'esempio che hai pubblicato, è impostato su new line character ( ); quindi dopo averlo impostato, elaborerà il testo riga per riga. In quell'esempio, potresti cambiare il valore di (in qualche lettera che hai nel tuo file di input) e controllare come il testo verrà diviso.Input
Internal Field Separator
\n
for
IFS
A proposito, dalla risposta che hai pubblicato la seconda soluzione è quella consigliata ...
Come notato da @jasonwryan , non lo è Input
ma Internal
. Il nome è Input
venuto da awk
cui c'è anche OFS
- Output Field Separator
.
S
era per separatore nella shell Bourne da cui proviene. Nella shell Korn e nella maggior parte delle altre shell tipo Bourne, come è stato ora specificato da POSIX
, S
è per Delimitatore (allunga un po 'la tua immaginazione) come A::B:
ad esempio è diviso in "A", "" e "B" (nessun extra ""). È diverso da awk
' FS
o dal s
flag di espansione dei parametri di zsh
.
IFS
non è direttamente correlato al looping, è legato alla suddivisione delle parole. IFS
determina indirettamente come l'output del comando viene suddiviso in parti su cui il loop scorre.
Quando si ha una sostituzione variabile non protetta $foo
o una sostituzione comando $(foo)
, ci sono due casi:
"$foo"
o in un'assegnazione variabile x=$foo
, la stringa risultante dalla sostituzione viene utilizzata così com'è.$IFS
è considerato un separatore di parole. Ad esempio IFS=":"; foo="12:34::78"; echo $foo
stampe 12 34 78
(con due spazi tra 34
e 78
, poiché c'è una parola vuota).foo="*"; echo $foo
stampa l'elenco dei file nella directory corrente.Per i loop, come molti altri contesti, si aspetta un elenco di parole. Così
for x in $(foo); do …
si spezza $(foo)
in parole e tratta ogni parola come un modello glob. Il valore predefinito IFS
è spazio, tab e newline , quindi se foo
stampa due righe hello world
e howdy
il corpo del loop viene eseguito con x=hello
, quindi x=world
e x=howdy
. Se IFS
viene esplicitamente modificato per contenere solo una nuova riga, il ciclo viene eseguito per hello world
e howdy
. Se IFS
viene modificato per essere o
, poi il ciclo viene eseguito per hell
, w
, rldh
(dove 
è un carattere nuova riga) e wdy
.
"IFS indirectly determines how ..."
?
IFS
(direttamente) determina il modo in cui viene suddivisa l'output della sostituzione del comando, che quindi (indirettamente) determina su cosa passa il loop.
A partire dal man bash
IFS Il separatore di campo interno utilizzato per la divisione delle parole dopo l'espansione e per dividere le linee in parole con il comando incorporato read. Il valore predefinito è "<spazio> <tab> <nuova>>.
Questa è una delle variabili interne di Bash. Determina il modo in cui Bash riconosce i campi, o i confini delle parole, quando interpreta le stringhe di caratteri.
Mentre l'impostazione predefinita è uno spazio bianco (spazio, tabulazione e nuova riga), ad esempio, può essere modificato per analizzare un file di dati separato da virgole.
Oltre alle ottime risposte precedenti, vorrei solo aggiungere che IFS è molto utile per l'analisi efficiente e portatile in casi semplici in combinazione con set . Efficiente, perché evita l'uso di subshells e strumenti di generazione come grep o sed:
resolutions="640x480,320x240"
xIFS=$IFS
IFS=','
for res in $resolutions; do
xxIFS=$IFS
IFS='x'
set -- $res
width=$1
height=$2
# handle width and height
IFS=$xxIFS
done;
IFS=$xIFS
Si noti che è necessario archiviare e ripristinare il valore precedente di IFS per evitare rotture indesiderate in altre parti dello script.