perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e'
Você pode executar o acima da seguinte forma:
$ perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e' afile
A 1,2,3,4
B 5,6
C 15
Como funciona
A primeira chamada de perl
com -lpe
faz as três coisas a seguir.
-
-l[octal]
habilita o processamento final da linha, especifica o terminador de linha -
-p
assume loop como -n mas linha de impressão também, como sed -
-e program
uma linha de programa (vários -e é permitido, omitir arquivo de programa)
Isso essencialmente pega o arquivo, retira as novas linhas, opera em uma linha e depois coloca um caractere de nova linha de volta nele quando terminar. Então, é apenas passar pelo arquivo e executar nosso código Perl contra cada um deles.
Quanto ao código Perl real:
-
\s
significa um caractere de espaçamento (os cinco caracteres[ \f\n\r\t]
e\v
nas versões mais recentes deperl
, como[[:space:]]
). -
\K
Guarde as coisas restantes de \ K, não inclua em $ & -
\S+
um ou mais caracteres que não estão no conjunto [\ f \ n \ r \ t \ v]
O join ",",
vai obter os resultados e voltar a cada campo para que seja separado por uma vírgula.
O split ",", $&
pegará as correspondências encontradas pelo \S+
e as dividirá em apenas os campos, sem a vírgula.
O grep {!$seen{$_}++}
pegará o número de cada campo e o adicionará ao hash, $seen{}
, onde o número de cada campo será $_
conforme passarmos por cada um deles. Cada vez que um número de campo é "visto", é contado pelo operador ++
, $seen{$_}++
.
O grep{!$seen{$_}++}
retornará um valor de campo se for visto apenas uma vez.
Modificado para ver o que está acontecendo
Se você usar essa abominação modificada, você pode ver o que está acontecendo enquanto esse forro de Perl se move pelas linhas do arquivo.
$ perl -lpe 's/\s\K\S+/join ",", grep {!$seen{$_}++} split ",", $&/e; @a=keys %seen; @b=values %seen; print "keys: @a | vals: @b"' afile
keys: 4 1 3 2 | vals: 1 1 1 1
A 1,2,3,4
keys: 6 4 1 3 2 5 | vals: 1 2 1 2 1 1
B 5,6
keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1
C 15
Isso mostra o conteúdo de $seen{}
no final do processamento de uma linha do arquivo. Vamos pegar a segunda linha do arquivo.
B 4,5,6,3
E aqui está o que minha versão modificada mostra nessa linha como:
keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1
Então, isso está dizendo que vimos o campo # 6 (1 vez), o campo # 4 (2 vezes), etc. e o campo # 5 (1 vez). Então, quando grep{...}
devolve os resultados, ele só retornará resultados desta matriz se estiver presente nesta linha (4,5,6,3) e se tivermos visto apenas 1 vez (6,1,15,5 ). A interseção dessas 2 listas é (5,6) e é isso que é retornado por grep
.