%
è l'operatore modulo (vedi https://en.wikipedia.org/wiki/Modulo_operation) e NR%3?FS:RS
è un'espressione ternaria (vedi https://en.wikipedia.org/wiki/%3F:). Questi sono entrambi costrutti comuni in molti linguaggi di programmazione, non sono specifici di awk. Per il significato di ORS, NR, FS e RS basta vedere la pagina man di awk.
Esegui questo per vedere i valori delle variabili nel codice prima e dopo il comando che stai eseguendo:
$ 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="
"
Nota su quali numeri di riga di input (NR
) il separatore di record di output (ORS
) diventa una nuova riga (come RS
) rispetto a un carattere vuoto (come FS
).
Un modo più prolisso per scrivere lo stesso codice sarebbe:
$ cat tst.awk
{
if (NR%3 == 0) {
ORS = "\n"
}
else {
ORS = " "
}
print
}
$ awk -f tst.awk file
1 2 3
4 5 6
e Cordiali saluti, il modo corretto (più robusto e più chiaro) di scrivere il codice conciso e idiomatico tentato nella tua domanda sarebbe:
awk '{ORS=(NR%3?FS:RS)}1'
Le parentesi attorno al ternario sono richieste in alcuni awk in alcuni contesti e migliorano sempre la leggibilità, quindi usale sempre. Il codice originale si basa sul risultato dell'assegnazione a ORS che produce un valore diverso da null/diverso da zero in modo che sia una condizione vera e quindi richiama l'azione predefinita di awks per stampare il record corrente. Usa il risultato di un'azione in quel contesto solo quando ne hai BISOGNO altrimenti ti morderà un giorno quando i tuoi dati non saranno esattamente quelli che ti aspettavi. Invece di lasciare l'assegnazione in un blocco di condizione, l'ho spostata in un blocco di azione e successivamente ho aggiunto una condizione true costante, 1
per garantire che ogni record venga stampato indipendentemente dal risultato dell'assegnazione.
Non il awk
spiegazione poiché hai già più di una buona risposta, ma alternative per lo stesso compito
$ seq 6 | xargs -n3
1 2 3
4 5 6
$ seq 6 | paste - - -
1 2 3
4 5 6
con paste
il delimitatore predefinito è tab, che puoi cambiare in spazio con -d' '
$ seq 6 | pr -3ats' '
1 2 3
4 5 6