Jetons un coup d'œil à la page de manuel GNU awk :
FS
— Le séparateur de champ de saisie, un espace par défaut. Voir Champs , ci-dessus.
Vers les Champs rubrique !
Au fur et à mesure que chaque enregistrement d'entrée est lu, gawk divise l'enregistrement en champs, en utilisant la valeur de
FS
variable comme séparateur de champ. SiFS
est un caractère unique, les champs sont séparés par ce caractère. SiFS
est la chaîne nulle, chaque caractère individuel devient un champ distinct. Sinon,FS
devrait être une expression régulière complète. Dans le cas particulier oùFS
est un espace unique, les champs sont séparés par des séries d'espaces et/ou de tabulations et/ou de nouvelles lignes.
Voici un résumé pragmatique qui s'applique à toutes les principales implémentations d'Awk :
- GNU Awk (
gawk
) - leawk
par défaut dans quelques Distributions Linux - Mawk (
mawk
) - leawk
par défaut dans quelques Distributions Linux (par exemple, les versions antérieures d'Ubuntu) - BWK Awk - le
awk
par défaut sur les plates-formes de type BSD, y compris macOS
Versions récentes de tous ces implémentations suivent la norme POSIX en ce qui concerne le champ séparateurs (mais pas enregistrer séparateurs).
Glossaire :
-
RS
est l'entrée-enregistrement séparateur , qui décrit comment l'entrée est divisée en enregistrements :- La valeur par défaut imposée par POSIX est une nouvelle ligne , également appelé
\n
dessous; c'est-à-dire que l'entrée est divisée en lignes par défaut . - Sur le
awk
la ligne de commande,RS
peut être spécifié comme-v RS=<sep>
. - POSIX limite
RS
à un littéral, un seul caractère valeur, mais GNU Awk et Mawk prennent en charge multi-caractère des valeurs qui peuvent être des expressions régulières étendues (BWK Awk ne fait pas soutenir cela).
- La valeur par défaut imposée par POSIX est une nouvelle ligne , également appelé
-
FS
est le champ d'entrée- séparateur , qui décrit comment chaque enregistrement est divisé en champs ; il peut s'agir d'une expression régulière étendue .- Sur le
awk
la ligne de commande,FS
peut être spécifié comme-F <sep>
(ou-v FS=<sep>
). - La valeur par défaut imposée par POSIX est formellement un espace (
0x20
), mais cet espace n'est pas littéralement interprété comme le (seul) séparateur, mais a une signification particulière ; voir ci-dessous.
- Sur le
Par défaut :
- n'importe quelle course d'espaces et/ou onglets et/ou nouvelles lignes est traité comme un séparateur de champs
- avec exécutions de début et de fin ignorées .
Notez que avec le séparateur d'enregistrement d'entrée par défaut (RS
), \n
, nouvelles lignes généralement ne saisissez pas l'image comme séparateur de champs , car aucun enregistrement lui-même contient \n
dans ce cas.
Les retours à la ligne comme séparateurs de champs le font entrer en jeu , cependant :
- Quand
RS
est défini sur une valeur qui se traduit par des enregistrements eux-mêmes contenant\n
cas (comme lorsqueRS
est défini sur la chaîne vide; voir ci-dessous). - Généralement , lorsque le
split()
La fonction est utilisée pour diviser une chaîne en éléments de tableau sans argument de séparateur de champ explicite.- Même si les enregistrements d'entrée ne contiendra pas
\n
instances dans le cas où la valeur par défautRS
est en vigueur, lesplit()
fonction lorsqu'elle est invoquée sans argument de séparateur de champ explicite sur une chaîne multiligne provenant d'une source différente (par exemple, une variable passée via le-v
option ou comme pseudo-nom de fichier) toujours traite\n
comme séparateur de champs.
- Même si les enregistrements d'entrée ne contiendra pas
Considérations importantes NON par défaut :
-
Attribuer le vide chaîne à
RS
a une signification particulière :il lit l'entrée en mode paragraphe , ce qui signifie que l'entrée est divisée en enregistrements par des séries de lignes non vides , avec les séries de lignes vides de début et de fin ignorées . -
Lorsque vous attribuez quoi que ce soit d'autre qu'un littéral espace à
FS
, l'interprétation deFS
change fondamentalement :- Un célibataire caractère ou chaque caractère d'un jeu de caractères spécifié est reconnu individuellement comme séparateur de champs - ne fonctionne de celui-ci, comme par défaut.
- Par exemple, définir
FS
à[ ]
- même si c'est efficacement équivaut à un seul espace - provoque chaque individu instance d'espace dans chaque enregistrement à traiter comme un séparateur de champ. - Pour reconnaître les courses , le quantificateur de regex (symbole de duplication)
+
doit être utilisé; par exemple,[\t]+
reconnaîtrait les courses d'onglets comme un seul séparateur.
- Par exemple, définir
- Avant et arrière les séparateurs ne sont PAS ignorés , et, à la place, séparez empty champs.
- Paramètre
FS
à la chaîne vide signifie que chaque caractère d'un enregistrement est son propre champ .
- Un célibataire caractère ou chaque caractère d'un jeu de caractères spécifié est reconnu individuellement comme séparateur de champs - ne fonctionne de celui-ci, comme par défaut.
-
Comme mandaté par POSIX, si
RS
est défini sur la chaîne vide (mode paragraphe), nouvelles lignes (\n
) sont aussi considérés comme des séparateurs de champs , quelle que soit la valeur deFS
.
- Avec
-P
en vigueur etRS
défini sur la chaîne vide ,\n
est toujours traité comme un séparateur de champs :
gawk -P -F' ' -v RS='' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
- Avec
-P
en vigueur et un non videRS
,\n
n'est PAS traité comme un séparateur de champs - c'est le comportement obsolète :
gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
Un correctif arrive , selon les mainteneurs de GNU Awk ; attendez-vous à la version 4.2 (pas de délai indiqué).
(Tip du chapeau à @JohnKugelman et @EdMorton pour leur aide.)
'[ ]+' fonctionne pour moi. Exécutez awk -W version
pour obtenir la version awk. Le mien est 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
Par exemple, je veux obtenir le port d'écoute. J'ai donc besoin d'utiliser le délimiteur par défaut awk ajouté avec ':'
# cat a.txt | awk -F '[ ]+|:' '{print $5}'
65002
26895
111
18422
22
8888
50010
50075
8093
8670
Si vous voulez juste tester le délimiteur par défaut, vous pouvez exécuter
# 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
Le résultat est comme prévu.
La question the default delimiter is only space for awk?
est ambigu, mais je vais essayer de répondre aux deux questions que vous pourriez vous poser.
La valeur par défaut du FS
variable (qui contient le séparateur de champ qui indique à awk comment séparer les enregistrements en champs lorsqu'il les lit) est un caractère d'espacement unique.
La chose qu'awk utilise pour séparer les enregistrements en champs est un "séparateur de champs" qui est une expression régulière avec des fonctionnalités supplémentaires qui ne s'appliquent que lorsque le séparateur de champs est un seul caractère vide. Cette fonctionnalité supplémentaire est la suivante :
- Les espaces blancs de début et de fin sont ignorés lors du fractionnement des champs.
- Les champs sont séparés par des chaînes d'espaces contigus comprenant des espaces, des tabulations et des retours à la ligne.
- Si vous souhaitez utiliser un caractère blanc littéral comme séparateur de champ, vous devez le spécifier sous la forme
[ ]
au lieu d'un caractère vide littéral autonome comme vous pourriez le faire dans une expression régulière.
En plus des séparateurs de champs utilisés pour diviser les enregistrements en champs lors de la lecture de l'entrée, ils sont utilisés dans d'autres contextes, par ex. le 3ème argument pour split()
, il est donc important que vous sachiez quels contextes nécessitent une chaîne ou une expression régulière ou un champsep et la page de manuel spécifie clairement chacun.
Entre autres choses, ce qui précède explique ceci :
$ 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>
donc si vous ne comprenez pas pourquoi les 2 premiers produisent le même résultat mais que le dernier est différent, veuillez demander.