Reordenando linhas de arquivo como outro arquivo (Unix)

2

Existe uma ferramenta (ou opção para sort ) que irá reordenar linhas de um arquivo para que elas sejam ordenadas como uma chave em outro arquivo?

Por exemplo, eu tenho um arquivo de dados:

T01F01475558    30
T01F022B3A17    31
T01F022EEDFD    19
T01F026E0209    19

E outro (arquivo "chave" de classificação):

T01F022EEDFD
T01F026E0209
T01F022B3A17
T01F01475558

Existe uma maneira de classificar o primeiro arquivo para que o primeiro campo esteja na mesma ordem do segundo arquivo? Cada chave é única (sem duplicatas) e há um número igual de linhas em cada arquivo.

Existe uma ferramenta UNIX que eu não conheço que fará isso?

    
por Taj Morton 27.08.2013 / 20:40

1 resposta

0

Each key is unique (no duplicates), and there are an equal number of lines in each file.

Esta suposição é muito importante. Se ele for válido, este comando fará o trabalho (no Bash):

paste <(nl key.file | sort -k 2 | cut -f 1) <(sort data.file) | sort -n | cut -f 2-

Poucas ferramentas usam caracteres de tabulação como separadores. Por esse motivo, as guias não devem ocorrer em key.file (elas podem ocorrer em data.file ). As entradas sãs em key.file devem formar uma única coluna, portanto, isso não deve ser um problema.

Explicação:

  1. nl adiciona um número de linha na frente de cada linha de key.file ; isso faz com que as chaves se movam para a segunda coluna; sort -k 2 ordena de acordo com a segunda coluna, ou seja, com as chaves. As chaves são então descartadas por cut -f 1 .
  2. Outro sort classifica data.file . Como as chaves na frente são exclusivas, essa classificação padrão é equivalente à classificação de acordo com as chaves exclusivas.
  3. Os dois resultados de sort -s são mesclados por paste . Sem o primeiro cut , uma linha de exemplo seria:

         4  T01F01475558    T01F01475558    30
    

    A unicidade das chaves e o número igual delas em ambos os arquivos são cruciais. Com efeito, as mesmas chaves de ambos os sort -s encontram-se na mesma linha, deixando paste . Como você não precisa de chaves duplicadas para ocupar a memória, o primeiro cut foi usado o mais rápido possível. Com isso, a linha de exemplo real deixando paste é:

         4  T01F01475558    30
    
  4. Essas linhas são classificadas de acordo com seu valor numérico. Os números de linha de nl estão na frente, portanto, esta operação introduz a ordem desejada.

  5. No final, cut descarta a primeira coluna, deixando as linhas exatas de data.file , ainda na ordem desejada.

Como alternativa, você pode tentar isso (testado no Bash):

while IFS='' read -r ; do
   [ -n "$REPLY" ] && grep "^$REPLY " data.file
done <key.file

Observe que o código espera um caractere de espaço após cada chave em data.file .

Prós:

  • key.file pode especificar qualquer número de chaves, chaves duplicadas, chaves inexistentes. Neste caso, não pense em "ordenar", pense em "recuperar as linhas desejadas uma por uma".
  • Você pode fazer stream de entrada (como stdin em vez de key.file , apenas omitir <key.file ) e obter a saída em tempo real.

Contras:

  • grep interpretará as chaves como expressões regulares, isso pode sair pela culatra. Há grep -F , mas em geral você precisa de ^ no padrão.
  • read é lento; desova grep novamente e novamente é lento; abrir data.file de novo e de novo é lento.
por 13.06.2018 / 14:29

Tags