Comando UNIX para substituir dentro do delimitador baseado na posição do delimitador

5

Eu tenho uma string de entrada com | [pipe] delimitadora e gosto de substituir a string vazia 3ª e 5ª colunas por & character.

Arquivo de entrada:

a a|b b|c c|d d|e e
f f|g g|h h|i i|j j

Arquivo de saída:

a a|b b|c&c|d d|e&e
f f|g g|h&h|i i|j&j

Você pode ver que o espaço entre cc, ee, hh and jj foi substituído por & Eu tenho uma solução alternativa que envolve arquivo de leitura usando while loop e usando o comando cut com base no delimitador e armazenando-o na variável com base na posição e substituindo o espaço por '&' usando sed e acrescente toda a variável dividida em uma variável e anexe-a em um novo arquivo. Existe um único comando que pode ser usado para conseguir isso?

    
por user7952074 03.08.2017 / 09:39

3 respostas

12

Use awk para isso:

awk -F\| '{gsub(" ","\&",$3); gsub(" ","\&",$5)}1' OFS=\| infile.txt 
  • O -F\| , informando 'awk' que os campos são delimitados por | pipe (ele escapou de \ para shell, não o interprete como pipeline stdin , poderíamos usar -F"|" ou -F'|' ).

  • A sintaxe gsub("regexp","replacement"[, INDEX]) usada para substituir " " (espaço ) com literal & no índice (coluna) $3 e $5 , abaixo está mostrando cada posição do Índice com base no | delimiter.

    a a|b b|c c|d d|e e
    ^^^|^^^|^^^|^^^|^^^
    $1 |$2 |$3 |$4 |$5
    

    Leia mais sobre por que escapamos de \& e duas vezes ?!

  • Qual é o 1 usado no final em awk '{...}1' ? é o controle de ação padrão do awk para imprimir. leia mais em detalhes

  • O OFS=\| retorna novamente ou imprime os campos com o delimitador | especificado.

por 03.08.2017 / 09:50
8

Você poderia fazer

sed 's/\(|[^| ]*\) */\&/4;s//\&/2'

para o seu exemplo. Explicado:

|[^| ]* pesquisa seu separador de campo e todos os espaços que não são nessa coluna. Ele é agrupado com \(\) para que possa ser copiado posteriormente para a substituição por . Em seguida, um ou mais espaços em branco serão substituídos pelo & , que precisa ser escapado na sequência de substituição. O 4 significa aplicar isso à quarta ocorrência, que é a quinta coluna. Em seguida, repita com 2 para a terceira coluna. Você não precisa repetir o padrão dando um padrão vazio.

Mais complicado se puder haver mais de um grupo de espaços na coluna ou nenhum. Então melhor usar uma ferramenta diferente como awk .

Por outro lado, se você sabe que há sempre um espaço em branco em cada coluna, faça um simples

sed 's/ /\&/5;s//\&/3'
    
por 03.08.2017 / 09:52
7
perl -aF'(\|)' -lne 's/\h/&/ for @F[2*2,2*4]; print @F' input_file

Resultados

a a|b b|c&c|d d|e&e
f f|g g|h&h|i i|j&j

Trabalhando

Divida o registro atual no canal | e inclua também o delimitador nos campos. Assim, os campos 3 e 5 se tornam campos 2 * 2 e 2 * 4.

Para esses dois campos, substituímos o espaço em branco horizontal \h por um literal & . Quando terminar, basta imprimir os campos.

    
por 03.08.2017 / 12:26