Aqui está um pequeno script de sed
que eu realmente escrevi para mim não há muito tempo. Eu só me diverti um pouco atualizando, no entanto. Ele faz todo o trabalho por si só:
cdup() { _u= _d=
case "${1#-}" in (U) _u='\)\(';; (D) _d='\
'; _d="$_d\2$_d";; (*) ! :;;esac && shift
sed 's/ */ /g;H;1h;1d;x;:t
s/ *\(.*\(\n\)\)\([^ ]\{1,\}\) */ /;tt
s/ / /g;h;$!d;s/.*/ & /;:n
/\( \([^ ]\{1,\}\) \)\(.*'"$_u${_d:+.*}\)/{
s//${_d:- }"'/;s/$\n*//;tn
}; s/.* \n\n*//;s/ *//;s// /g
s/\n\n/ /g;y/ \n/\n /' "$@"
unset -v _u _d
}
sed
trabalha duas linhas de cada vez ao reorganizar os campos em sua entrada para alinhar por coluna - e empilha seu trabalho no buffer de armazenamento entre cada linha. Ele não delimita nada além do delimitador de espaço original em seu exemplo (e eu originalmente o escrevi para manipular $IFS
arrays separados por arg) - e assim, desde que o delimitador seja sólido, campos de qualquer tamanho razoável contendo mais qualquer caractere, mas o delimitador deve funcionar também.
Por isso, faz (L1COL1\nL2COL1) (L1COL2\nL2COL2)...((L[12]C1)\nL3COL1)...
pelo tempo que for necessário até encontrar a última linha. No momento em que isso acontece, todos os dados da memória são organizados de forma tão precisa que é uma tarefa trivial verificar se há duplicatas - e, portanto, só imprime colunas uma vez, independentemente de quantas vezes elas aparecem na entrada:
cdup <<\COLS
1 A 4 Z 1
2 B 3 Y 2
3 C 2 X 3
4 D 1 W 4
5 E 0 U 5
COLS
OUTPUT
A B C D E
4 3 2 1 0
Z Y X W U
1 2 3 4 5
Mas com o sinal -U
, imprime apenas itens exclusivos, por isso ...
cdup -U <<\COLS
1 A 4 Z 1
2 B 3 Y 2
3 C 2 X 3
4 D 1 W 4
5 E 0 U 5
COLS
... fica ...
A B C D E
4 3 2 1 0
Z Y X W U
Ou -D apenas para duplicados, com um registro extra por aparência de coluna duplicada.
Não é tão ruim ...
cdup -D <<\DATA
1 1 A A 4 Z 1
2 2 B B 3 Y 2
3 3 C C 2 X 3
4 4 D D 1 W 4
5 5 E E 0 U 5
DATA
1 2 3 4 5
1 2 3 4 5
A B C D E