Substituição específica no nível da coluna

3

Se eu tiver um arquivo com entradas colunares, é possível substituir somente entradas específicas de colunas específicas e salvar as alterações no mesmo arquivo ??

Exemplo de um arquivo abc.txt :

SR|FRUITS|COLOR|
1|Apple|Red|
2|Mango|Yellow|
3|Orange|Orange|
4|W.Melon|Green|

É necessário alterar Laranja das frutas para Orange_Edit . No entanto, o laranja da cor não deve ser afetado.

    
por abhishek nair 27.05.2015 / 15:57

3 respostas

4

Você pode fazer isso em duas etapas com awk like

awk '{$2="VAL";print}' input_file > temp_file
mv temp_file input_file

Isso dividirá o arquivo de entrada no espaço em branco, substituirá o valor na segunda coluna (use qualquer outro número diferente de 2 para coluna diferente), de modo que agora será "VAL". A menos que você o altere com OFS , o delimitador do campo de saída será um espaço. Se você quiser algo mais você pode adicionar, dentro das aspas, algo como 'BEGIN {OFS="\ t"} ...' para definir o separador de campo de saída para o que você quiser.

Se você quiser que os valores sejam algo diferente de uma constante, você terá um pouco mais de trabalho a fazer, mas poderá adaptá-lo para isso.

Para fazer esse trabalho para a edição no seu caso, você pode fazer:

awk -F\| 'BEGIN {OFS="|";} $2~/^Orange$/ {$2="Orange_edit";} {print}' abc.txt > temp_file
mv temp_file abc.txt

Primeiro, informa awk para dividir os campos com base em | passando -F\| . Em seguida, configuramos nossa saída para usar também | para o delimitador de saída (o padrão é espaço) fazendo o primeiro bloco de código (a parte que corresponde a BEGIN, uma palavra-chave em awk que corresponde ao início da execução) e definindo nosso OFS ou Separador do campo de saída. Como Otheus apontou, nós poderíamos fazer {OFS=FS} para definir o delimitador de saída para ser o mesmo que o de entrada.

Depois disso, começamos a olhar para as linhas. Comparamos o segundo campo, que é referenciado por $2 , e depois verificamos se ele corresponde a uma expressão regular usando ~ . Depois que ~ é a regex que queremos corresponder, ^ aqui significa corresponder ao início do campo, depois temos a string "Orange" e, em seguida, $ que corresponde ao final do campo. Como esta é uma string codificada em disco, Otheus também observou corretamente que poderíamos testar a igualdade de strings aqui e fazer $2=="Orange" e pular o processamento regex, já que ele não faz nada dessa vez. Se essa correspondência for bem sucedida no bloco de código em {} após a execução, o que salvará um novo valor no segundo campo.

Finalmente, executamos o último bloco de código {print} para cada linha, mas quando a nossa correspondência "Orange" foi bem-sucedida, alteramos o valor do segundo campo para que ele seja impresso com nosso novo valor em vez do antigo.

awk normalmente imprime na tela (aparentemente o mais novo gawk tem uma opção para simplificar essa parte), então salvamos isso em um arquivo e, em seguida, movemos esse arquivo de volta para o nome original.

    
por 27.05.2015 / 16:07
2

Existem muitas maneiras de fazer isso. Os mais simples provavelmente são awk e perl :

  1. GNU gawk . Se você tiver uma versão relativamente recente de gawk instalada, poderá fazer uma edição sequencial como esta:

    gawk -i inplace -F"|" -vOFS="|"  '$2=="Orange"{$2="Orange_Edit"}1;' file 
    

    O -i inplace informa gawk para editar o arquivo no local, o -F"|" define o separador de campo como | e o -vOFS="|" define o separador do campo de saída como | também. O script define o segundo campo ( $2 ) para Orange_Edit apenas se o segundo campo for Orange . A abreviação 1; é awk para "imprimir a linha atual".

  2. Perl

    perl -i -F"\|" -lane '$F[1]="Orange_Edit" if $F[1] eq "Orange"; 
                       print join "|",@F' file 
    

    O -a faz o Perl agir como awk e divide linhas no valor dado por -F , salvando os campos resultantes no array @F . Em seguida, o script define o segundo campo ( $F[1] , matrizes iniciadas em 0) para Orange_Edit se seu valor original for Orange . Em seguida, os campos são unidos por | e impressos.

  3. Se você quiser apenas alterar a primeira ocorrência de Orange , poderá simplificar e usar

    sed -i 's/Orange/Orange_Edit/' file 
    

    Você pode tornar isso um pouco mais robusto apenas combinando campos inteiros:

    sed -i 's/|Orange|/|Orange_Edit|/' file 
    
por 27.05.2015 / 17:25
2

Você pode usar perl :

$ perl -i.bak -F'\|' -aple 's/Orange/Orange_Edit/ if $F[1] eq "Orange"' file

ou versão mais segura:

$ perl -i.bak -F'\|' -aple '$F[1]=~s/^Orange$/Orange_Edit/; $_=join "|",@F' file
    
por 27.05.2015 / 16:28