Qual è il significato esatto di IFS = $ '\ n'?


125

Se il seguente esempio, che imposta la IFSvariabile di ambiente su un carattere di avanzamento riga ...

IFS=$'\n'
  • Cosa significa esattamente il segno del dollaro ?
  • Cosa fa in questo caso specifico?
  • Dove posso leggere di più su questo utilizzo specifico (Google non ammette caratteri speciali nelle ricerche e non so cosa cercare altrimenti)?

So cos'è la IFSvariabile d'ambiente e qual è il \ncarattere (avanzamento riga), ma perché non utilizzare semplicemente la seguente forma: IFS="\n"(che non funziona)?

Ad esempio, se voglio scorrere ogni riga di un file e voglio usare un ciclo for, potrei farlo:

for line in (< /path/to/file); do
    echo "Line: $line"
done

Tuttavia, questo non funzionerà correttamente a meno che non IFSsia impostato su un carattere di avanzamento riga. Per farlo funzionare, dovrei fare questo:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

Nota: non ho bisogno di un altro modo per fare la stessa cosa, ne conosco già molti altri ... Sono solo curioso di questo $'\n'e mi chiedevo se qualcuno potesse darmi una spiegazione al riguardo.

Risposte:


161

Normalmente bashnon interpreta le sequenze di escape in stringhe letterali. Quindi, se scrivi \no "\n"o '\n', non è un'interruzione di riga: è la lettera n(nel primo caso) o una barra rovesciata seguita dalla lettera n(negli altri due casi).

$'somestring'è una sintassi per i letterali stringa con sequenze di escape . Quindi '\n', a differenza , in $'\n'realtà è un'interruzione di riga.


2
Non esattamente così - \nè solo una lettera (con escape) n. Hai ragione '\n'e "\n"sei contraccolpo seguito dal n.
Roman Cheplyaka

15
Nota che $'\n'è specifico di bash - non funzionerà in una shell POSIX ( /bin/sh). Per ottenere lo stesso effetto in modo conforme a POSIX, puoi digitare IFS=', quindi premere Invio per digitare un vero carattere di nuova riga, quindi digitare la chiusura'
Richard Hansen

23
IFS=$(echo -e '\n')dovrebbe anche farlo in un modo compatibile con POSIX.
Vineet

12
@Vineet - mi ha fatto riflettere per contestare un commento con voto positivo. Anche se questo è corretto per Posix, non funziona: gli operatori di sostituzione dei comandi in bash rimuovono tutti i caratteri di nuova riga finali. Vedi questo per maggiori dettagli .
Digital Trauma

9
@DigitalTrauma penso che non sia nemmeno POSIX: -enon è definito e \nsenza -efunziona come estensione XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/… . printf '\n'rocce;)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

21

Solo per dare il costrutto il suo nome ufficiale : le stringhe del modulo $'...'sono chiamati stringhe ANSI C-citati .

Cioè, come nelle stringhe [ANSI] C, le sequenze di escape di backlash vengono riconosciute ed espanse al loro equivalente letterale (vedi sotto per l'elenco completo delle sequenze di escape supportate).

Dopo questa espansione, le $'...'stringhe si comportano allo stesso modo delle '...'stringhe - cioè, vengono trattate come letterali NON soggette ad alcuna [ulteriore] espansione della shell .

Ad esempio, si $'\n'espande in un carattere di nuova riga letterale, che è qualcosa che una stringa letterale bash regolare (se '...'o "...") non può fare. [1]

Un'altra caratteristica interessante è che le stringhe ANSI C-quotate possono sfuggire '(virgolette singole) come\' , che, '...'(stringhe regolari con virgolette singole) non possono:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

Elenco delle sequenze di escape supportate :

Le sequenze di escape backslash, se presenti, vengono decodificate come segue:

\ un avviso (campanello)

\ b backspace

\ e \ E un carattere di escape (non ANSI C)

\ f avanzamento modulo

\ n nuova riga

\ r ritorno a capo

\ t scheda orizzontale

\ v scheda verticale

\ backslash

virgoletta singola

\ "virgolette doppie

\ nnn il carattere a otto bit il cui valore è il valore ottale nnn (da una a tre cifre)

\ xHH il carattere a otto bit il cui valore è il valore esadecimale HH (una o due cifre esadecimali)

\ uHHHH il carattere Unicode (ISO / IEC 10646) il cui valore è il valore esadecimale HHHH (da uno a quattro cifre esadecimali)

\ UHHHHHHHH il carattere Unicode (ISO / IEC 10646) il cui valore è il valore esadecimale HHHHHHHH (da uno a otto cifre esadecimali)

\ cx un carattere control-x

Il risultato espanso è a virgolette singole, come se il segno del dollaro non fosse stato presente.


[1] Puoi, tuttavia, incorporare i nuovi caratteri nelle stringhe "..." e "..."; cioè, è possibile definire stringhe che si estendono su più righe.


16

Da http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

Le parole nella forma "$ 'STRING'" vengono trattate in modo speciale. La parola si espande in una stringa, con caratteri di escape backslash sostituiti come specificato dallo standard ANSI-C. Le sequenze di escape della barra rovesciata possono essere trovate nella documentazione di Bash

Immagino che stia costringendo lo script a sfuggire al line feed allo standard ANSI-C appropriato.


8

Recuperare l'IFS predefinito: OLDIFS=$IFSnon è necessario. Esegui un nuovo IFS nella subshell per evitare di sovrascrivere l'IFS predefinito:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

Inoltre non credo proprio che tu abbia recuperato completamente il vecchio IFS. Dovresti doppiarlo per evitare interruzioni di riga come OLDIFS="$IFS".


2
questa è una tecnica davvero utile. ho appena usato per un guscio pulitore join op: args=$(IFS='&'; echo "$*"). ripristino IFSa $' \t\n'in un modo amichevole Bourne shell è un'impresa da poco.
jeberle

Ri Besides I don't really believe you recover the old IFS fully: la suddivisione in parole non viene eseguita sull'RHS degli assegnamenti di variabili (ma la rimozione delle virgolette lo è), quindi OLDIFS=$IFSe si OLDIFS="$IFS"comportano allo stesso modo.
mklement0

3

Le stringhe ANSI con virgolette C sono un punto chiave. Grazie a @ mklement0.

Puoi testare stringhe ANSI con virgolette C con il comando od.

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

Uscite:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

Puoi conoscere chiaramente il significato dalle uscite.


-7

È come recuperare il valore da una variabile:

VAR='test'
echo VAR
echo $VAR

sono diversi, quindi il segno del dollaro valuta fondamentalmente il contenuto.


6
Questo non ha nulla a che fare con le variabili. $'FOO'(a differenza di $FOOciò che questa era la domanda non riguardava) è una stringa letterale. Se esegui echo $'VAR', vedrai che stampa la stringa VAR, no test.
sepp2k
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.