Substituir condicionalmente as linhas do arquivo1 pelas linhas correspondentes do arquivo2

2

Por exemplo, eu tenho dois arquivos:

arquivo1:

1
4
X
5
X
7

arquivo2:

2
3
5
X
X
1

Eu quero substituir X -lines do arquivo1 pelo que estiver no arquivo2 na linha correspondente:

resultado:

1
4
5
5
X
7

Eu prefiro a solução usando comandos da CLI, por exemplo, sed .

    
por Fibo Kowalsky 24.09.2018 / 01:51

3 respostas

2

Se o arquivo2 couber na memória, você poderá usar o awk. Faça com que ele seja lido no arquivo2 primeiro e, em seguida, quando estiver processando o arquivo1, se ele vir "X", substitua-o da matriz do arquivo2:

$ awk 'NR == FNR { lines[NR]=$0; } NR != FNR { if ($0 == "X") print lines[FNR]; else print $0 }' file2 file1

Re-formatado, isso é:

$ awk 'NR == FNR { lines[NR]=$0; } 
       NR != FNR { if ($0 == "X") print lines[FNR]; 
                   else           print $0 
                 }' file2 file1

Observe que o arquivo2 é o primeiro nome de arquivo; file1 é o segundo nome de arquivo.

    
por 24.09.2018 / 14:54
1
$ paste file1 file2 | awk -F '\t' '$1 == "X" { $1 = $2 } { print $1 }'
1
4
5
5
X
7

O comando paste gerará a saída delimitada por tabulação

1       2
4       3
X       5
5       X
X       X
7       1

e o script awk simplesmente define o primeiro campo delimitado por tabulação para o conteúdo do segundo campo se o primeiro é o caractere X e, em seguida, imprime o primeiro campo (agora possivelmente modificado).

Uma abordagem diferente sugerido por glenn jackman que não modifica os dados recebidos, apenas seleciona o campo para imprimir dependendo dos dados da primeira coluna:

$ paste file1 file2 | awk -F '\t' '{ print $1 == "X" ? $2 : $1 }'

Usando o GNU sed :

$ paste file1 file2 | sed -E -e '/^X/s/^[^\t]+\t//' -e 's/\t.*$//'
1
4
5
5
X
7

As duas expressões sed fazem o seguinte:

  1. Se a linha atual começar com X , a primeira substituição removerá tudo, inclusive o primeiro caractere de tabulação. Isso efetivamente move a segunda coluna da saída paste para a primeira coluna se a primeira coluna for X .
  2. A segunda expressão remove o caractere de tabulação e qualquer coisa depois dela. Isso remove os dados nos quais não estamos interessados.
por 24.09.2018 / 15:58
0

Com bash

while IFS= read -r -u3 f1; IFS= read -r -u4 f2; do
    [[ $f1 == X ]] && echo "$f2" || echo "$f1"
done 3<file1 4<file2

ou mais geralmente, POSIX

while IFS= read -r f1 <&3; IFS= read -f f2 <&4; do
    [ "$f1" = X ] && echo "$f2" || echo "$f1"
done 3<file1 4<file2
    
por 24.09.2018 / 16:46