
Você pode me dar uma sugestão de como posso classificar exclusivamente a partir de uma linha ou linha? Tenho informações como esta:
Special c1,c2,c5,c7,c1,c2
Special2 C6
(este é um caractere TAB entre Special
e c1...
).
Eu quero a saída assim:
Special c1,c2,c5,c7
Special2 C6
Como posso fazer isso?
Responder1
Usandoesta resposta,
perl -MList::MoreUtils=uniq -laF'\t' -ne '
$F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'
Isso depende de um pacote externoLista::MaisUtilitários. Se você não deseja instalar uma dependência externa, reimplementar a uniq
função éapenas mais algumas linhas de Perl. (Embora pareça que ele está instalado como parte do sistema básico do macOS.)
Responder2
perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf
Explicação
-F'\t|,'
=> dividirá cada campo de registro na matriz@F
ouTAB
caracterescomma
.-l
definiráRS
paranewline
eORS
paranewline
também.-a
dividirá automaticamente cada registro em palavras com base naFS
escolha de-F
.-n
configurará um loop implícito de leitura de registro na entradaAND
e imprimirá coisas somente quando solicitado.-e
é oPerl
código a ser executado em cada registro da entrada com base naRS
escolha-l
acima.- O primeiro elemento será fornecido por
shift
e os demais elementos serãouniquified
armazenados como chaves de um hash,%h
, que será regenerado toda vez que um registro for lido. Os elementos únicos são então classificados e unidos por vírgula e impressos.
Responder3
Testado com OpenBSD awk
, GNU awk
e mawk
:
awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'
O primeiro awk
expande os dados fornecidos em
Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6
Ele usa vírgulas e múltiplos espaços como delimitador de campo e, para cada registro (linha) de entrada, imprime o primeiro campo seguido por cada um dos outros campos em linhas separadas. Isso pressupõe que não há outros espaços ou vírgulas nas linhas além de onde serão interpretados adequadamente como delimitadores.
O que sort
está no meio classifica em
Special2 C6
Special c1
Special c2
Special c5
Special c7
Ele faz uma classificação usando a linha completa como chave de classificação e descarta qualquer linha duplicada.
O último awk
recombina os dados em
Special c1,c2,c5,c7
Special2 C6
Ele faz isso usando o primeiro campo como chave em uma matriz associativa e armazena a concatenação separada por vírgula dos dados correspondentes no segundo campo como o valor. Ao final, todos os dados coletados são impressos.
Responder4
Outra maneira em uma linha:
while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' '; echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort
Ele pega a primeira coluna de cada linha ( echo $line | awk '{print $1}' | tr '\n' ' ';
) e classifica os valores da segunda coluna separados por ',' após convertê-los em uma única coluna para aplicar sort
e depois convertê-los novamente em uma única linha com a formatação original ( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ','
).
Fazendo divisão de linha conforme sugerido por @tripleee:
while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort