Diamo un'occhiata alla pagina man di GNU awk:
FS— Il separatore del campo di input, uno spazio per impostazione predefinita. Vedi Campi , sopra.
Ai Campi sezione!
Man mano che ogni record di input viene letto, gawk suddivide il record in campi, utilizzando il valore di
FSvariabile come separatore di campo. SeFSè un singolo carattere, i campi sono separati da tale carattere. SeFSè la stringa nulla, quindi ogni singolo carattere diventa un campo separato. Altrimenti,FSdovrebbe essere un'espressione regolare completa. Nel caso speciale cheFSè uno spazio singolo, i campi sono separati da sequenze di spazi e/o tabulazioni e/o newline.
Ecco un riassunto pragmatico questo si applica a tutte le principali implementazioni di Awk :
- GNU Awk (
gawk) - ilawkpredefinito in alcuni distribuzioni Linux - Mawk (
mawk) - ilawkpredefinito in alcuni Distribuzioni Linux (ad es. versioni precedenti di Ubuntu ) - BWK Awk - il
awkpredefinito su piattaforme simili a BSD, incluso macOS
Versioni recenti di tutte queste implementazioni seguono lo standard POSIX rispetto a field separatori (ma non registra separatori).
Glossario:
-
RSè il input-record separatore , che descrive come l'input viene suddiviso in record :- Il valore predefinito imposto da POSIX è una nuova riga , indicato anche come
\nsotto; ovvero, l'input è suddiviso in righe per impostazione predefinita . - Su
awkriga di comando di ,RSpuò essere specificato come-v RS=<sep>. - POSIX limita
RSa un letterale, a un solo carattere value, ma GNU Awk e Mawk supportano multi-carattere valori che possono essere espressioni regolari estese (BWK Awk non supportalo).
- Il valore predefinito imposto da POSIX è una nuova riga , indicato anche come
-
FSè il campo di input separatore , che descrive come ogni record è suddiviso in campi ; potrebbe essere un'espressione regolare estesa .- Su
awkriga di comando di ,FSpuò essere specificato come-F <sep>(o-v FS=<sep>). - Il valore predefinito imposto da POSIX è formalmente uno spazio (
0x20), ma quello spazio non è letteralmente interpretato come (l'unico) separatore, ma ha un significato speciale ; vedi sotto.
- Su
Per impostazione predefinita :
- qualsiasi esecuzione di spazi e/o schede e/o newline viene trattato come un separatore di campo
- con sequenze iniziali e finali ignorate .
Tieni presente che con il separatore di record di input predefinito (RS ), \n , newline tipicamente non inserire l'immagine come separatore di campo , perché nessun record stesso contiene \n in tal caso.
Le nuove righe come separatori di campo fare entrano in gioco , tuttavia:
- Quando
RSè impostato su un valore che genera i record stessi contenente\nistanze (come quandoRSè impostato sulla stringa vuota; vedi sotto). - Generalmente , quando
split()La funzione viene utilizzata per suddividere una stringa in elementi dell'array senza un argomento separatore di campo esplicito.- Anche se i record di input non conterrà
\nistanze nel caso in cui il valore predefinitoRSè in vigore, ilsplit()funzione quando viene richiamata senza un argomento separatore di campo esplicito su una stringa multilinea da una fonte diversa (ad esempio, una variabile passata tramite il-vopzione o come pseudo-nome file) sempre tratta\ncome separatore di campo.
- Anche se i record di input non conterrà
Considerazioni importanti NON predefinite :
-
Assegnazione del vuoto stringa a
RSha un significato speciale :legge l'input in modalità paragrafo , il che significa che l'input viene suddiviso in record mediante sequenze di righe non vuote , con sequenze iniziali e finali di righe vuote ignorate . -
Quando assegni qualcosa other piuttosto che un letterale spazio a
FS, l'interpretazione diFScambia radicalmente :- Un singolo carattere o ogni carattere da un set di caratteri specificato è riconosciuto individualmente come separatore di campo - non funziona di esso, come con il default.
- Ad esempio, impostando
FSa[ ]- anche se efficacemente equivale a un singolo spazio - causa ogni individuo istanza di spazio in ogni record da trattare come separatore di campo. - Per riconoscere le corse , il quantificatore regex (simbolo di duplicazione)
+deve essere usato; ad esempio,[\t]+riconoscerebbe le corse di schede come separatore singolo.
- Ad esempio, impostando
- In testa e in coda i separatori NON vengono ignorati e, invece, separato vuoto campi.
- Impostazione
FSalla stringa vuota significa che ogni carattere di un record è il proprio campo .
- Un singolo carattere o ogni carattere da un set di caratteri specificato è riconosciuto individualmente come separatore di campo - non funziona di esso, come con il default.
-
Come richiesto da POSIX, se
RSè impostato sulla stringa vuota (modalità paragrafo), newline (\n) sono anche considerati separatori di campo , indipendentemente dal valore diFS.
- Con
-Pin vigore eRSimpostato sulla stringa vuota ,\nè ancora trattato come un separatore di campo:
gawk -P -F' ' -v RS='' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb' - Con
-Pin vigore e un non vuotoRS,\nNON viene trattato come un separatore di campo - questo è il comportamento obsoleto:
gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
È in arrivo una correzione , secondo i manutentori di GNU Awk; aspettalo nella versione 4.2 (nessun periodo di tempo indicato).
(Suggerimento del cappello a @JohnKugelman e @EdMorton per il loro aiuto.)
'[ ]+' funziona per me. Esegui awk -W version per ottenere la versione awk. Il mio è GNU Awk 4.0.2 .
# cat a.txt
tcp 0 0 10.192.25.199:65002 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:26895 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:18422 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8888 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50010 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50075 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8093 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8670 0.0.0.0:* LISTEN
Ad esempio, voglio ottenere la porta di ascolto. Quindi ho bisogno di usare il delimitatore predefinito awk aggiunto con ':'
# cat a.txt | awk -F '[ ]+|:' '{print $5}'
65002
26895
111
18422
22
8888
50010
50075
8093
8670
Se vuoi solo testare il delimitatore predefinito, puoi eseguire
# cat a.txt | awk -F '[ ]+' '{print $4}'
10.192.25.199:65002
127.0.0.1:26895
0.0.0.0:111
0.0.0.0:18422
0.0.0.0:22
10.192.25.199:8888
0.0.0.0:50010
0.0.0.0:50075
10.192.25.199:8093
0.0.0.0:8670
Il risultato è come previsto.
La domanda the default delimiter is only space for awk? è ambiguo, ma cercherò di rispondere a entrambe le domande che potresti porre.
Il valore predefinito di FS variabile (che contiene il separatore di campo che dice ad awk come separare i record nei campi mentre li legge) è un singolo carattere di spazio.
La cosa che awk usa per separare i record in campi è un "separatore di campo" che è un'espressione regolare con alcune funzionalità aggiuntive che si applicano solo quando il separatore di campo è un singolo carattere vuoto. Quella funzionalità aggiuntiva è che:
- Gli spazi bianchi iniziali e finali vengono ignorati durante la divisione del campo.
- I campi sono separati da catene di spazi contigui che includono spazi vuoti, tabulazioni e nuove righe.
- Se desideri utilizzare un carattere vuoto letterale come separatore di campo, devi specificarlo come
[ ]invece di solo un carattere vuoto letterale autonomo come potresti fare in una regexp.
Oltre ai separatori di campo utilizzati per suddividere i record in campi durante la lettura dell'input, vengono utilizzati in altri contesti, ad es. il 3° argomento per split() , quindi è importante sapere quali contesti richiedono una stringa o una regexp o un fieldsep e la pagina man specifica chiaramente ciascuno di essi.
Tra le altre cose, quanto sopra spiega questo:
$ echo ' a b c ' | awk '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F' ' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F'[ ]' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
5: <> <a> <b>
quindi se non capisci perché i primi 2 producono lo stesso output ma l'ultimo è diverso, chiedi pure.