web-dev-qa-db-fra.com

Séparateur de champs par défaut pour awk

Désolé pour cette question stupide, recherchée mais pas sûre que la bonne réponse soit trouvée, donc le séparateur par défaut n'est que de l'espace pour awk?

20
Lin Ma

Voici un résumé pragmatique qui s'applique à toutes les principales implémentations Awk :

  • GNU Awk (gawk) - la valeur par défaut awk dans certains distributions Linux
  • Mawk (mawk) - la valeur par défaut awk dans certains distributions Linux (par exemple, les versions antérieures d'Ubuntu crysman signale que la version 19.04 est désormais livrée avec GNU Awk - voir son commentaire ci-dessous.)
  • BSD Awk - a.k.a. BWK Awk - la valeur par défaut awk sur les plates-formes de type BSD, y compris OSX

Sous Linux, awk -W version Vous dira quelle implémentation est le awk par défaut.
BSD Awk seulement ​​comprend awk --version (Qui GNU Awk comprend en plus à awk -W version).

Les versions récentes de toutes ces implémentations suivent les standard POSIX par rapport aux séparateurs field[1] (mais pas record séparateurs).

Glossaire:

  • RS est l'entrée -record séparateur , qui décrit comment l'entrée est divisée en enregistrements:

    • La valeur par défaut mandatée par POSIX est un saut de ligne , également appelé \n Ci-dessous; autrement dit, l'entrée est divisée en lignes par défaut .
    • Sur la ligne de commande de awk, RS peut être spécifié comme -v RS=<sep>.
    • POSIX restreint RS à une valeur littérale, à un caractère, mais GNU Prise en charge Awk et Mawk multi-caractère valeurs cela peut être expressions régulières étendues (BSD Awk ne pas supporte cela).
  • FS est l'entrée -champ séparateur , qui décrit comment chaque enregistrement ​​est divisé en champs; il peut s'agir d'une expression régulière étendue.

    • Sur la ligne de commande de awk, FS peut être spécifié comme -F <sep> (Ou -v FS=<sep>).
    • Le valeur par défaut mandatée par POSIX est formellement ​​a espace (0x20), Mais cet espace n'est pas littéralement ​​interprété comme le (seul) séparateur, mais a signification spéciale; voir ci-dessous.

Par défaut :

  • toute exécution de espaces et/o tabulations et/ou sauts de ligne est traité comme un séparateur de champ
  • avec exécutions avant et arrière ignorées .

La spécification POSIX. tilise l'abstraction <blank> pour les espaces et les tabulations , ce qui est vrai pour tous locales, mais pourrait ​​comprendre supplémentaire caractères dans des paramètres régionaux spécifiques - je ne sais pas si de tels paramètres régionaux existent.

Notez que avec le séparateur d'entrée-enregistrement par défaut (RS), \n, sauts de ligne généralement ​​n'entrez pas l'image comme séparateurs de champs , car aucun enregistrement lui-même contient \n dans ce cas.

Les nouvelles lignes comme séparateurs de champs do entrent en jeu , cependant:

  • Lorsque RS est défini sur une valeur qui se traduit par des enregistrements eux-mêmes contenant \n Instances (comme lorsque RS est défini sur chaîne vide; voir ci-dessous).
  • Général, lorsque la fonction split() est utilisée pour diviser une chaîne en éléments de tableau sans argument de séparation de champ explicite.
    • Même si les enregistrements d'entrée ne contiendront pas d'instances de \n Dans le cas où la RS par défaut est en vigueur, la fonction split() lorsqu'elle est invoquée sans argument explicite de séparateur de champs sur une chaîne de plusieurs lignes provenant d'une source différente (par exemple, une variable transmise via l'option -v ou comme pseudo-nom de fichier) toujours traite \n comme un séparateur de champs.

Considérations importantes NON par défaut :

  • L'affectation de la chaîne empty à RS a une signification particulière : elle lit l'entrée dans mode paragraphe, ce qui signifie que l'entrée est divisée en enregistrements par séries de non vide lignes, avec les lignes de début et de fin des lignes vides ignorées .

  • Lorsque vous attribuez quelque chose autre qu'un littéral espace à FS, le interprétation de FSchange fondamentalement ​​:

    • Un single caractère ou chaque caractère d'un caractère spécifié set ​​ est reconnu individuellement ​​comme séparateur de champ - pas s'exécute de celui-ci, comme par défaut.
      • Par exemple, la définition de FS sur [ ] - même si elle effectivement ​​équivaut à un seul espace - provoque chaque individ instance d'espace dans chaque enregistrement à traiter comme un séparateur de champ.
      • Pour reconnaître s'exécute, le quantificateur d'expression régulière (symbole de duplication) + Doit être utilisé; Par exemple, [\t]+ reconnaîtrait exécute des onglets comme un seul séparateur.
    • Les séparateurs de début et de fin ne sont PAS ignorés , et, à la place, séparent les champs empty.
    • Définir FS sur chaîne vide signifie que chacun - caractère d'un enregistrement est son propre champ .
  • Comme mandaté par POSIX , si RS est défini sur chaîne vide (mode paragraphe), nouvelles lignes (\n) sont également ​​considérés comme des séparateurs de champs , quelle que soit la valeur de FS.

[1] Malheureusement, GNU Awk jusqu'à au moins la version 4.1.3 est conforme à une norme obsolète POSIX en ce qui concerne les séparateurs de champs lorsque vous utilisez l'option pour appliquer POSIX conformité, -P (--posix): avec cette option en vigueur et RS réglé sur une valeur non vide, sauts de ligne (\n ne sont PAS reconnus comme séparateurs de champs. Le manuel GNU Awk précise le comportement obsolète (mais néglige de mentionner qu'il ne s'applique pas lorsque RS est défini sur la chaîne vide). La norme POSIX a changé en 2008 (voir commentaires) en aussi considérez nouvelles lignes séparateurs de champ lorsque FS a sa valeur par défaut - comme GNU Awk a toujours fait sans-P (--posix).
Voici 2 commandes qui vérifient le comportement décrit ci-dessus:
* Avec -P En vigueur et RS réglé sur chaîne vide, \n Est toujours traité comme un séparateur de champ:
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 champ - c'est le comportement obsolète:
gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
n correctif arrive, selon les responsables GNU Awk; attendez-le dans la version 4.2 (aucun délai imparti) ).
(Pointe du chapeau à @JohnKugelman et @EdMorton pour leur aide.)

20
mklement0

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 de la variable FS (qui contient le séparateur de champ qui indique à awk comment séparer les enregistrements en champs lors de leur lecture) est un seul caractère d'espace.

La chose que 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'applique que lorsque le séparateur de champs est un seul caractère vide. Cette fonctionnalité supplémentaire est la suivante:

  1. Les espaces blancs avant et arrière sont ignorés lors de la division du champ.
  2. Les champs sont séparés par des chaînes de caractères d'espaces contigus qui incluent des blancs, des tabulations et des retours à la ligne.
  3. Si vous souhaitez utiliser un caractère vide littéral comme séparateur de champ, vous devez le spécifier comme [ ] Au lieu d'un simple caractère vide littéral comme vous le feriez 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 troisième argument pour split(), il est donc important pour vous de savoir quels contextes nécessitent une chaîne ou une expression rationnelle ou un fieldsep 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 la même sortie mais que le dernier est différent, veuillez demander.

11
Ed Morton

Jetons un œil à la page de manuel GNU awk:

FS - Le séparateur de champ de saisie, un espace par défaut. Voir Champs , ci-dessus.

À la section Champs !

À mesure que chaque enregistrement d'entrée est lu, gawk divise l'enregistrement en champs, en utilisant la valeur de la variable FS comme séparateur de champ. Si FS est un seul caractère, les champs sont séparés par ce caractère. Si FS est la chaîne nulle, alors chaque caractère individuel devient un champ séparé. Sinon, FS devrait être une expression régulière complète. Dans le cas particulier où FS est un seul espace, les champs sont séparés par des séries d'espaces et/ou de tabulations et/ou de nouvelles lignes.

8
John Kugelman