bash cambia il suo comportamento in base al valore della variabile "IFS"


18

Quando imposto la IFSvariabile su uno spazio, bashtratta più spazi come uno spazio ( myprogramè un programma che stampa gli argomenti della riga di comando che riceve):

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

Ma quando imposto la IFSvariabile su una virgola, bashnon tratta più virgole come una virgola:

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

Perché?


Solo per riferimento, "IFS" significa separatore di campo interno .
pr1268,

Risposte:


21

Questo è documentato in man bash. Una singola occorrenza di qualsiasi carattere in IFS che non sia uno spazio bianco delimita un campo.

Da man bash:

La shell tratta ogni carattere di IFS come un delimitatore e divide i risultati delle altre espansioni in parole usando questi caratteri come terminatori di campo. Se IFS non è impostato o il suo valore è esattamente <space><tab><newline>, l'impostazione predefinita, quindi le sequenze di <space>, <tab>e <newline>all'inizio e alla fine dei risultati delle espansioni precedenti vengono ignorate e qualsiasi sequenza di caratteri IFS non all'inizio o alla fine serve a delimitare parole. Se IFS ha un valore diverso da quello predefinito, le sequenze dello spazio dei caratteri degli spazi bianchi, della scheda e della nuova riga vengono ignorate all'inizio e alla fine della parola, purché il carattere degli spazi bianchi sia nel valore dell'IFS (un carattere degli spazi bianchi IFS ). Qualsiasi carattere in IFS che non sia uno spazio bianco IFS, insieme a qualsiasi carattere di spazio bianco IFS adiacente, delimita un campo. Una sequenza di caratteri spazi bianchi IFS viene anche trattata come delimitatore. Se il valore di IFS è nullo, non si verifica la divisione di parole. [Enfasi aggiunta.]

Esempi: divisione del campo

Se IFS non ha caratteri di spazi bianchi, nei campi è incluso spazio bianco:

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

Se IFS ha sia spazi vuoti che una virgola, le sequenze di spazi vuoti, seguite da una virgola, seguite da sequenze di spazi vuoti vengono trattate come un delimitatore singolo:

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

Le sequenze di virgole vengono interpretate come sequenze di campi vuoti:

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

Esempi: spazi bianchi iniziali e finali

Se IFS non contiene spazi bianchi, nei campi viene mantenuto qualsiasi spazio bianco iniziale e finale:

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

Se IFS contiene spazi vuoti, vengono rimosse eventuali sequenze iniziali o finali di spazi vuoti:

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

forse vale anche la pena sottolineare che "le sequenze dello spazio dei caratteri degli spazi bianchi, della scheda e della nuova riga vengono ignorate all'inizio e alla fine della parola, purché il carattere dello spazio bianco sia nel valore di IFS"
Jeff Schaller

@JeffSchaller Ottima idea: ho appena aggiunto una sezione su questo.
Giovanni 1024


cosa succede se si dispone di un file separato da tabulazioni con alcuni valori mancanti? cioè non vuoi che le sequenze di schede siano trattate come una singola scheda. Inoltre, i campi contengono virgole quindi non è possibile utilizzarlo come delimitatore. L'unica soluzione è usare qualche altro delimitatore (non le schede)?
Davos,

@Davos Per i dati con ogni campo delimitato da una singola scheda, potrebbe essere più naturale utilizzare altri strumenti che gestiscono facilmente questo come awkcon l' -F'\t'opzione o cut. In alternativa, se hai una versione recente di bash, potresti essere in grado di analizzare i campi utilizzando readarraycon l' -d$'\t'opzione.
Giovanni 1024,
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.