%
est l'opérateur modulo (voir https://en.wikipedia.org/wiki/Modulo_operation) et NR%3?FS:RS
est une expression ternaire (voir https://en.wikipedia.org/wiki/%3F:). Ce sont deux constructions courantes dans de nombreux langages de programmation, elles ne sont pas spécifiques à awk. Pour la signification de ORS, NR, FS et RS, consultez simplement cette page de manuel awk.
Exécutez ceci pour voir les valeurs des variables dans le code avant et après la commande que vous exécutez :
$ cat tst.awk
BEGIN {
printf "%s=\"%s\"\n", "RS", RS
printf "%s=\"%s\"\n", "FS", FS
}
{
printf "---\n"
printf "%s=\"%s\"\n", "$0", $0
printf "%s=\"%s\"\n", "NR", NR
printf "%s=\"%s\"\n", "NR%3", NR%3
printf "before) %s=\"%s\"\n", "ORS", ORS
ORS = (NR%3 ? FS : RS)
printf "after) %s=\"%s\"\n", "ORS", ORS
}
.
$ awk -f tst.awk file
RS="
"
FS=" "
---
$0="1"
NR="1"
NR%3="1"
before) ORS="
"
after) ORS=" "
---
$0="2"
NR="2"
NR%3="2"
before) ORS=" "
after) ORS=" "
---
$0="3"
NR="3"
NR%3="0"
before) ORS=" "
after) ORS="
"
---
$0="4"
NR="4"
NR%3="1"
before) ORS="
"
after) ORS=" "
---
$0="5"
NR="5"
NR%3="2"
before) ORS=" "
after) ORS=" "
---
$0="6"
NR="6"
NR%3="0"
before) ORS=" "
after) ORS="
"
Remarquez sur quels numéros de ligne d'entrée (NR
) le séparateur d'enregistrements de sortie (ORS
) devient une nouvelle ligne (comme RS
) vs un caractère vide (comme FS
).
Une façon plus détaillée d'écrire le même code serait :
$ cat tst.awk
{
if (NR%3 == 0) {
ORS = "\n"
}
else {
ORS = " "
}
print
}
$ awk -f tst.awk file
1 2 3
4 5 6
et pour votre information, la manière correcte (plus robuste et plus claire) d'écrire le code concis et idiomatique tenté dans votre question serait :
awk '{ORS=(NR%3?FS:RS)}1'
Les parenthèses autour du ternaire sont nécessaires dans certains cas dans certains contextes et améliorent toujours la lisibilité, alors utilisez-les toujours. Le code d'origine s'appuie sur le résultat de l'affectation à ORS produisant une valeur non nulle/non nulle pour qu'il s'agisse d'une condition vraie et invoque ainsi l'action par défaut awks d'impression de l'enregistrement en cours. N'utilisez le résultat d'une action dans ce contexte que lorsque vous en avez BESOIN, sinon cela vous mordra un jour lorsque vos données ne correspondront pas exactement à ce que vous attendiez. Au lieu de laisser l'affectation dans un bloc de condition, je l'ai déplacée dans un bloc d'action, puis j'ai ajouté une condition vraie constante par la suite, 1
pour s'assurer que chaque enregistrement est imprimé, quel que soit le résultat de cette affectation.
Pas le awk
explication puisque vous avez déjà plus d'une bonne réponse, mais des alternatives pour la même tâche
$ seq 6 | xargs -n3
1 2 3
4 5 6
$ seq 6 | paste - - -
1 2 3
4 5 6
avec paste
le délimiteur par défaut est la tabulation, que vous pouvez changer en espace avec -d' '
$ seq 6 | pr -3ats' '
1 2 3
4 5 6