GNU/Linux >> Linux Esercitazione >  >> Linux

In `mentre Ifs=Leggi..`, perché Ifs non ha alcun effetto?

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.

Correlati:leggere le informazioni all'interno del PDF?

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() e exec() , 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. )


Linux
  1. Perché Printf è meglio di Echo?

  2. Perché `while Ifs=Read` viene usato così spesso, invece di `ifs=; Durante la lettura..`?

  3. Capire se?

  4. Il curl ha un timeout?

  5. Cosa fa Eco $? Fare??

Python ha un argomento argc?

Perché il fork del mio processo fa sì che il file venga letto all'infinito

Cos'è una GPU Matrox e perché il server UNIX della mia università ne ha una?

Perché il mio sistema mostra solo 3,2 GiB di RAM quando ho sicuramente 4,0 GiB

Perché pvremove ha una forza duplicata nella pagina man?

Cosa significa echo $? fare?