Como substituir texto em uma coluna

7

Eu tenho um arquivo enorme (mais de 2 GB), onde os dados são como abaixo.

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,E:,23432,34534,45345,324

Aqui eu preciso substituir todas as ocorrências da quarta coluna onde quer que ela encontre E: com um espaço em branco "" , mas onde quer que encontre uma string depois de E: , isso deve permanecer como está. >

O resultado esperado seria:

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,,23432,34534,45345,324
    
por anurag 21.12.2015 / 07:48

3 respostas

8

Sua sintaxe está quase correta. Para testar a igualdade de strings em awk , use um sinal de igual duplo: == . Para atribuir um valor , use um único sinal de igual.

Portanto, use if ($4 == "E:") e você deve obter o resultado desejado.

O comando completo ficaria assim. Note que há apenas uma diferença de caractere do comando que você usou; esse foi seu único erro:

awk -F , '{ if ($4 == "E:") $4="";}1' OFS=, data.final

Para mostrar algumas sintaxes e abordagens diferentes, as seguintes versões são exatamente equivalentes:

awk -F, -v OFS=, '$4 == "E:" { $4 = "" }; 1' data.final

awk 'BEGIN { FS=OFS="," }; $4 == "E:" { $4 = "" }; {print}' data.final

awk -F, -v OFS=, '{sub( /^E:$/, "", $4); print}' data.final

Notas sobre o acima:

  1. Se todo o seu bloco de código é apenas um if / then, você pode simplesmente usar a condição como um filtro para o bloco de código. Portanto, $4 == "E:" {$4 = ""} é exatamente equivalente a {if ($4 == "E:") {$4 = ""}}
  2. É uma boa prática incluir instruções "then" em um bloco de código mesmo quando houver apenas uma delas, ou seja, if ($4 == "E:") {$4 = ""} em vez de if ($4 == "E:") $4 = "";
  3. -F define o valor de FS e -v pode ser usado para definir o valor de qualquer variável antes que awk considere a primeira linha do primeiro arquivo. (Você provavelmente sabia disso.) Você também pode usar um bloco BEGIN para fazer a mesma coisa; vale a pena saber quando você deseja tornar o script awk autônomo.
  4. O motivo pelo qual 1 imprime linhas em awk é que é uma condição (um filtro) que sempre é avaliada como true e a ação padrão em awk quando nenhum bloco de código é anexado ao filtro é %código%. Portanto, print $0 é equivalente a 1 ou 1 {print} ou apenas 1 {print $0} .
  5. Na minha última variação, usei uma função {print} para substituir o regex sub (início da sequência, /^E:$/ , fim da sequência) por E: in "" .

Como a função $4 retorna o número de substituições feitas (1 ou 0; use sub para fazer mais de uma substituição), você pode codificar esse problema adicionando um à função gsub resultado para garantir que você tenha um padrão que seja sempre verdadeiro para que a linha resultante seja impressa se uma substituição é feita ou não. Aqui está a versão do código de golfe, não recomendado para uso iniciante se você está colocando isso em um script que você irá manter:

awk -F, -v OFS=, 'sub(/^E:$/,"",$4)+1' data.final

:)

    
por 21.12.2015 / 07:58
2

com sed :

sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)//' file.txt

O quarto campo separado por vírgulas ficará em branco se contiver apenas E: .

Exemplo:

% cat file.txt
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,E:,23432,34534,45345,324

% sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)//' file.txt 
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,,23432,34534,45345,324
    
por 21.12.2015 / 09:00
0

Supondo que o nome do seu arquivo seja file , você pode tentar o seguinte:

while read -r line; 
do 
var="$(echo "$line" | cut -d ',' -f 4)";

  if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; 
  else echo "$line";
  fi; 

done < file

ou:

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; else echo "$line";fi; done < file

Explicação:

  1. while read -r line; lê o arquivo linha por linha
  2. var="$(echo "$line" | cut -d ',' -f 4)"; procura a string no quarto lugar separado por , na variável var
  3. if [[ && "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/' '/g ; if $var tem string exatamente E: então sed s/"$var"/''/g ; substitui por "" em branco
  4. else echo "$line"; de outro modo, imprime linha como é

Exemplo output (como esperado da pergunta):

  • file :

    $ cat file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,E:,23432,34534,45345,324
    
  • Comando de execução:

    $ while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,,23432,34534,45345,324
    

Você também pode redirecionar sua saída para o arquivo usando >> file2 ou |tee file2 no último comando:

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file | tee file2
    
por 21.12.2015 / 09:42