procura por uma string (extraída do arquivo) e substitui qualquer instância de uma string diferente dentro da primeira correspondência

2

Este liner irá procurar por Name: 0602 e então substituirá qualquer instância do Type ### pelo tipo 700 até que o próximo nome seja alcançado.

sed '/Name: R0602/,/Name.*$/ s/type .*;/type 700;/' file2

Eu estou olhando para usar algo semelhante a este forro, mas eu quero usar lista de nomes no arquivo1 para pesquisar o arquivo2. Depois que um arquivo de forma de string1 é encontrado, ele substitui qualquer instância de string2 até atingir o final da seção desse nome e, em seguida, faz o mesmo para a próxima linha no arquivo1.

Arquivo1

Name: 0602
Name: 0603
Name: 0604

arquivo2:

# Name: R0601
   Container 4 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 300;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
         name "C7";
         type 200;
     }
      set 31 40 {
         name "C7";
         type 1200;
     }
  }
}

 # Name: R0602
   Container 5 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 300;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
         name "C7";
         type 300;
     }
      set 31 40 {
         name "C7";
         type 1100;
     }
  }
}


 # Name: R0603
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
 # Name: R0604
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
 # Name: R0605
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
    
por Jdubyas 10.08.2017 / 14:42

2 respostas

1

Um script awk curto

awk '
  NR == FNR               { names["R"$2]; next }
  $2 == "Name:"           { replace = ($3 in names) }
  $1 == "type" && replace { sub(/type .*/, "type 700;") }
  1
' file1 file2

NR e FNR são variáveis awk incorporadas. NR conta o número total de linhas vistas até agora. FNR é o número de linhas no arquivo atual visto até agora. NR == FNR é um idioma do awk que significa "Estou trabalhando no primeiro arquivo de dados" - o único arquivo para o qual o número do registro atual seria igual ao número total do registro.

Então, lendo o primeiro arquivo, queremos armazenar as "chaves", que estão na segunda coluna. Armazená-los como a chave da matriz associativa de "nomes" é um local útil, dado o operador in que usamos mais tarde. Estou adicionando a letra "R" à chave porque o segundo arquivo tem isso.

Quando $2 == "Name:" , estamos no topo de uma seção. Queremos substituir os valores de tipo se a terceira palavra nesta linha foi vista no primeiro arquivo. ($3 in names) verifica se a terceira palavra aparece como uma chave na matriz names associativa. Se estiver lá, faremos as substituições de todas as linhas subseqüentes, onde a primeira palavra é "tipo".

A última linha do script é interessante. 1 é outra abreviação idiomática para instruir o awk a imprimir a linha atual. programas awk são uma série de condition {action} pares: se a condição for atendida, execute as ações especificadas. A condição pode ser omitida, caso em que a ação é executada para cada linha. A condição pode ser dada sem um bloco de ação, em cujo caso a ação padrão é imprimir a linha atual. O awk trata strings vazias e zero como false, portanto, 1 é uma condição que é sempre verdadeira. Quando estou me sentindo mais detalhado, escrevo {print} em vez de 1 para torná-lo mais óbvio.

    
por 10.08.2017 / 16:53
0

Com um script GNU awk como abaixo:

NR == FNR {
                strt=1
        }
strt == 0 {
                if (match($0,/Name/)) {
                        id=substr($0,RSTART,length($0))
                        id=gensub("R","","g",id)
                }
                file2[id]=file2[id]"\n"$0
        }
 FNR == 1 && NR != 1 {
                 strt=0
                 file2[$0]=""
        }
 strt == 1 {
            file1[$0]=$0
        }
 END {
        for (i in file2) {
                if (file1[i] != "") {
                       resp=gensub(/[[:blank:]]{5}type.*;/,"     type 
700;","g",file2[i])
                       print resp
               }
               else {
                    print file2[i]
               }
       }
}

Leia os dois arquivos em matrizes separadas (file1, file2) digitadas, por exemplo, "Name: 0603". No final, percorra o array array2 correspondendo ao arquivo1. Se houver uma entrada no arquivo1, use o gensub para corresponder e substituir o padrão, caso contrário, basta imprimir a entrada no arquivo2.

ação com:

 awk -f scriptfile file1 file2
    
por 10.08.2017 / 16:29

Tags