
Eu tenho um arquivo parecido com o abaixo:
1
4 5 6 7 19
20
22
24 26 27
29
30
31
32
34
40
50
56
58
100
234 235 270 500
1234 1235 1236 1237
2300
2303
2304
2307
2309
Como está claro, existem algumas linhas com mais de 1 coluna e outras com apenas uma coluna. Gostaria de unir linhas de coluna única de forma que houvesse no máximo 4 colunas em cada linha combinada. Então a saída deve ficar assim:
1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309
Alguma sugestão de como fazer isso, considerando que os dados reais são grandes?
Responder1
Um pouco idiomático, mas trabalhando com gnu awk:
awk '{printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)} \
{(NF==1?++c:c=0)} \
c==4{printf "\n";c=0} \
END{printf "\n"}' file
#Output
1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309
Explicação:
variáveis awk:
NF=Número de Campos
FS=Separador de Campos = espaço por padrão
RS=Separador de Registros= nova linha por padrão.
c = contador
Linha 1: {printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)}
: operações if ternárias aninhadas
#Single ternary if operation:
condition?true action:false action
#Nested if operations:
condition1?true action 1:(condition2:true action2:false action2) #nested ternary if operations
-------------------------[ ^ false action1 ^ ]
Isso pode ser explicado em pseudocódigo como:
if NF==1 then print $0 and print FS
else (if c==0 then print "" else print RS) and print $0 and print RS again
Linha 2: {(NF==1?++c:c=0)}
: Outra operação if ternária que pode ser expressa como:
If NF==1 (line has one field)
then increase counter c by one
else reset counter c.
Linha 3: c==4{printf "\n";c=0}
Sintaxe clássica do awk:condition{action}
If counter c==4 then print a new line and reset counter c
Linha 4: END{printf "\n"}' file
: Isso apenas imprime uma nova linha no final do script.
Responder2
Você pode usar sed
para conseguir o que deseja:
sed -e '
/./!b
/[^[:space:]]/!b
/[^[:space:]][[:blank:]]\{1,\}[^[:space:]]/b
:loop
$q;N
/\n.*\S[[:blank:]]\+\S/b
s/\n/ /;tdummy
:dummy
s/[[:space:]]\{1,\}/&/3;t
bloop
' yourfile
Explicações
- Pule linhas vazias, em branco e com NF > 1.
- Configure um loop do-while no ponto onde o espaço padrão contém uma linha de campo único.
- Pegamos a próxima linha e verificamos se ela possui NF > 1, momento em que imprimimos todo o espaço do padrão e voltamos à leitura da próxima linha.
- Agora sabemos que a próxima linha também é de campo único, então seguimos em frente e cortamos a nova linha que une essas duas partes no espaço padrão.
- O espaço padrão já tem 3 pedaços de espaços? Se sim, imprimimos todo o espaço do padrão e começamos a ler a próxima linha.
- Caso contrário, voltamos ao loop que, por sua vez, lerá a próxima linha, mas a anexará ao espaço padrão existente.
Resultado
1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309
Responder3
Uso: ./join_rows.awk input.txt
Verifique shebang #!/usr/bin/awk -f
, porque a awk
localização pode ser diferente no seu sistema.
#!/usr/bin/awk -f
BEGIN {
count = 1;
}
{
if (NF == 1) {
if (count > 1 && count <= 4) printf " ";
printf "%s", $1;
count++;
if (count > 4) {
printf "\n";
count = 1;
}
} else {
if (count > 1) printf "\n";
print;
count = 1;
}
}
END {
if(count > 1) printf "\n";
}
Saída:
1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309
Responder4
Estendidoficar boquiabertoabordagem:
rearranjar_colunas.awkroteiro:
#!/bin/awk -f
function printRow(a, i, v)
{
for (i in a) {
printf "%s ", a[i]
}
print ""
delete a
}
NF <= 2{
for (i=1; i<=NF; i++) {
a[++c] = $i
if (length(a) == 4) {
c = 0
printRow(a)
}
}
}
NF > 2{
if (length(a) > 0) {
c = 0
printRow(a)
}
print $0
}
END{ print }
Uso:
awk -f rearrange_columns.awk yourfile
A saída:
1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309