Potrei avere qualcosa di assolutamente sbagliato, ma mi sembra convincente che impostare IFS come uno dei comandi nell'elenco pre-do/done non ha assolutamente alcun effetto.
L'IFS esterno (al di fuori del while
build) prevale in tutti gli esempi mostrati nello script seguente.
Cosa sta succedendo qui? Ho un'idea sbagliata di cosa fa IFS in questa situazione? Mi aspettavo che i risultati della divisione dell'array fossero come mostrato nella colonna "previsto".
#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS
show() { x=($1)
echo -ne " (${#x[@]})t |"
for ((j=0;j<${#x[@]};j++)); do
echo -n "${x[j]}|"
done
echo -ne "t"
xifs "$IFS"; echo
}
data="a b c"
echo -e "----- -- -- t --------tactual"
echo -e "outside t IFS tinside"
echo -e "loop t Field tloop"
echo -e "IFS NR NF t Split tIFS (actual)"
echo -e "----- -- -- t --------t-----"
IFS=$' tn'; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 1'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 2'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 3'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 4'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 5'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 6'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 7'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't 8'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 9'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't10'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't11'; show "$REPLY"; done
echo -e "----- -- -- t --------t-----"
Uscita:
----- -- -- -------- actual
outside IFS inside assigned
loop Field loop # inner
IFS NR NF Split IFS # expected IFS
----- -- -- -------- ----- # --------- --------
20090a 1 (3) |a|b|c| 20090a #
20090a 2 (3) |a|b|c| 20090a # |a b c| IFS=
20090a 3 (3) |a|b|c| 20090a # |a | c| IFS=b
20 4 (3) |a|b|c| 20 #
20 5 (3) |a|b|c| 20 # |a b c IFS=
20 6 (3) |a|b|c| 20 # |a | c| IFS=b
7 (1) |a b c| #
8 (1) |a b c| # |a|b|c| IFS=" "
9 (1) |a b c| # |a | c| IFS=b
62 10 (2) |a | c| 62 # |a b c| IFS=
62 11 (2) |a | c| 62 # |a|b|c| IFS=" "
----- -- -- -------- ----- --------- -------
Risposta accettata:
(Scusa, lunga spiegazione)
Sì, l'IFS
variabile in while IFS=" " read; do …
non ha effetto sul resto del codice.
Precisiamo innanzitutto che la riga di comando della shell presenta due diversi tipi di variabili:
- Variabili della shell (che esistono solo all'interno di una shell e sono locali alla shell)
- variabili di ambiente, che esistono per ogni processo. Di solito vengono conservati su
fork()
eexec()
, quindi i processi figlio li ereditano.
Quando chiami un comando con:
A=foo B=bar command
il comando viene eseguito all'interno di un ambiente in cui (ambiente) variabile A
è impostato su foo
e B
è impostato su bar
. Ma con questa riga di comando, le attuali variabili della shell A
e B
sono rimasti invariati .
Questo è diverso da:
A=foo; B=bar; command
Qui, le variabili della shell A
e B
sono definiti e il comando viene eseguito senza variabili di ambiente A
e B
definito. Valori di A
e B
non sono accessibili da command
.
Tuttavia, se alcune variabili della shell sono export
-ed, le variabili di ambiente corrispondenti sono sincronizzate con le rispettive variabili di shell. Esempio:
export A
export B
A=foo; B=bar; command
Con questo codice, entrambi shell variabili e l'ambiente della shell le variabili sono impostate su foo
e bar
. Poiché le variabili di ambiente vengono ereditate dai sottoprocessi, command
potranno accedere ai loro valori.
Per tornare alla tua domanda originale, in:
IFS='a' read
solo read
è affetto. E infatti, in questo caso, read
non si preoccupa del valore di IFS
variabile. Utilizza IFS
solo quando chiedi che la linea venga divisa (e memorizzata in più variabili), come in:
echo "a : b : c" | IFS=":" read i j k;
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
IFS
non è utilizzato da read
a meno che non venga chiamato con argomenti. (Modifica: Questo non è esattamente vero:gli spazi bianchi, ovvero spazio e tabulazione, presenti in IFS
vengono sempre ignorati all'inizio/alla fine della riga di input. )