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
FS
variabile 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,FS
dovrebbe 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
) - ilawk
predefinito in alcuni distribuzioni Linux - Mawk (
mawk
) - ilawk
predefinito in alcuni Distribuzioni Linux (ad es. versioni precedenti di Ubuntu ) - BWK Awk - il
awk
predefinito 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
\n
sotto; ovvero, l'input è suddiviso in righe per impostazione predefinita . - Su
awk
riga di comando di ,RS
può essere specificato come-v RS=<sep>
. - POSIX limita
RS
a 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
awk
riga di comando di ,FS
può 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\n
istanze (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à
\n
istanze 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-v
opzione o come pseudo-nome file) sempre tratta\n
come separatore di campo.
- Anche se i record di input non conterrà
Considerazioni importanti NON predefinite :
-
Assegnazione del vuoto stringa a
RS
ha 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 diFS
cambia 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
FS
a[ ]
- 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
FS
alla 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
-P
in vigore eRS
impostato 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
-P
in vigore e un non vuotoRS
,\n
NON 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.