Dado um token de chave de partida seguido de n tokens, intercale os n tokens com a chave

0

No shell osx, dado um fluxo com essas linhas, onde o primeiro token é uma chave, o primeiro caractere na linha sempre corresponderá a [a-z] , os tokens restantes serão sempre apenas numéricos, haverá um número variável de eles e apenas espaços únicos separam os tokens:

key  [1] [...] [n]
---- --------------------
key1 17 89 52
key2 5 189 6 3 5 21

Como posso emitir a seguinte saída (independente do número de tokens em cada linha) sem fazer apenas substituições repetidas vezes?

17 key1
89 key1
52 key1
5 key2
189 key2
6 key2
3 key2
5 key2
21 key2

(Também é perfeitamente correto trocar chaves ou números, ou cada linha permanecer uma linha separada por espaços ao invés de novas linhas como key1 17 key1 89 key1 52 , pois eu posso trocar tokens ou dividi-los em múltiplas linhas facilmente). / p>

Atualmente, estou usando sed para substituir sucessivamente cada próximo número sem chave, mas isso parece ineficiente, e tenho de garantir que canalize para sed mais vezes do que o número máximo de tokens, o que poderia aumentar (e por que mais você acha que eu estou aqui?):

sed -E 's/^([a-z][^ ]*) ([0-9]+) / \n /g' filename.txt | sed ... | sed ...

Se eu pudesse me dar ao luxo de investigar awk , tenho certeza de que isso funcionaria. Talvez cut possa fazer o trabalho ou uma das outras ferramentas que podem trabalhar efetivamente com tokens.

Como você faria isso de maneira eficiente tanto no código quanto no tempo de processamento?

    
por ErikE 18.07.2018 / 06:17

2 respostas

2

Você pode usar o awk para essa finalidade

awk '{ for(i = 2; i <= NF; i++) { print $i,$1; } }'  file

O loop for vai do segundo campo até o último e cada campo é impresso com o primeiro campo anexado

    
por 18.07.2018 / 06:20
1

sed é adequado para essa tarefa. Apenas aprimorando seu código sed, temos:

sed -E '
    s/^([a-z][^ ]*) ([0-9]+)/ \n/
    /\n/P;D
' filename.txt

Saída:

17 key1
89 key1
52 key1
5 key2
189 key2
6 key2
3 key2
5 key2
21 key2

Explicação:

  • Você já conhece o comando s /// substituto que eu tirei de você e apenas remova o global /g flag .
  • A ideia básica é que nós olhamos os dois primeiros elementos, os invertemos e também salvamos uma cópia do primeiro elemento (antes do flip) e colocamos uma nova linha \n após a operação de inversão, para que possamos ser capazes de use o comando P , que imprime apenas até a primeira nova linha no espaço padrão.
  • Qualifique P com /\n/ para evitar um loop infinito.
  • O D é excluído da primeira nova linha no espaço de padrão e, com o que resta do espaço de padrão, leva o controle de volta à parte superior do script. IOW, o que você fez é, fornecido por um mecanismo de looping implícito.
  • O looping termina, para a linha atual, quando o espaço padrão foi finalmente corroído por esse processo contínuo de s/// --- P --- D --- s/// --- P --- D ........... .
  • Depois disso, sed inicia um novo ciclo de leitura e você já sabe o que acontece .... HTH.
por 18.07.2018 / 10:20