Comparando Arquivo1 e Arquivo2 para comentar o padrão correspondente no Arquivo2

0

Eu tenho 2 arquivos que são listas contendo nomes de teste. Um arquivo contém o nome do teste básico, como usb30_tb_7_10 , e no outro arquivo, ele é mostrado como 'include "usb30_tb_7_10.sv" . Eu quero pegar todos os nomes de list ' que são os nomes base (sem incluir ou .sv) e encontrá-los em list2 e comentar a linha inteira.

Ou seja:

Lista 1

test1
test3

Lista 2 antes do comentário

'include "test1.sv"
'include "test2.sv"
'include "test3.sv"
'include "test4.sv"

Lista 2 depois de comparar

//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
'include "test4.sv"

Ainda sou novo no grep / sed / awk, mas ainda não consegui encontrar uma solução para isso.

Eu vi respostas envolvendo o awk, que tem um padrão específico como entrada, mas isso não me ajuda muito.

Eu tentei fazer o seguinte:

awk '-include list1.lst {print "// " $0; next} 1' list2.sv

Mas não funcionou (ou até aceitou o comando, pois foi digitado incorretamente).

    
por Javia1492 08.08.2017 / 00:21

3 respostas

4

Usando o awk:

$ awk -F'[".]' 'NR==FNR{a[$0]; next} $2 in a{$0="//"$0} 1' list1 list2
//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
'include "test4.sv"

Como funciona:

  • -F'[".]'

    Isso informa ao awk para separar os campos sempre que um " ou . ocorre.

  • NR==FNR{a[$0]; next}

    Ao ler o primeiro arquivo, list , isso diz ao awk para criar uma chave na matriz associativa a igual à linha atual e, em seguida, pular o restante dos comandos e pular para a linha next .

    Mais detalhes: NR é o número total de linhas que o awk leu até agora. FNR é o número de linhas lidas até agora do arquivo atual. Isso, quando FNR==NR , estamos lendo o primeiro arquivo.

  • $2 in a{$0="//"$0}

    Ao ler o segundo arquivo, isso diz ao awk para adicionar // ao início da linha se o segundo campo na linha atual for uma chave na matriz associativa a .

  • 1

    Esta é uma abreviada enigmática do awk para imprimir a linha.

Exemplo estendido

Usando a linha adicional mencionada nos comentários:

$ cat list1
test1
test3
usb30_suspend_resume
$ cat list2
'include "test1.sv"
'include "test2.sv"
'include "test3.sv"
'include "usb30_suspend_resume.sv"
'include "test4.sv"
$ awk -F'[".]' 'NR==FNR{a[$0]; next} $2 in a{$0="//"$0} 1' list1 list2
//'include "test1.sv"
'include "test2.sv"
//'include "test3.sv"
//'include "usb30_suspend_resume.sv"
'include "test4.sv"

Adaptando para arquivos pastebin

Os arquivos em pastebin têm espaços em branco à direita em list1 e ambos os arquivos têm terminações de linha no estilo windows. Para lidar com esse formato, use:

awk 'NR==FNR{a[$1]; next} $2 in a{$0="//"$0} 1' FS='[[:space:]]' list1.txt FS='[".]' list2.txt
    
por 08.08.2017 / 00:40
1

Francamente, eu faria isso de forma interativa no Vim em menos tempo do que seria necessário para digitar qualquer uma das soluções de script fornecidas até agora.

vim list2

Em seguida, leia na lista1 no topo. (Eu estou supondo que será fácil dizer visualmente onde termina e onde lista2 começa, então não há necessidade de marcar nada antes do tempo - mas você pode :1k a primeiro se você quiser, então a linha original de list2 está marcada. )

:0r list1

Após este comando, o cursor estará no início do arquivo, na primeira palavra test1 .

Pressione * para ir para a próxima instância da palavra sob o cursor. (Essa será a linha que você quer comentar.)

Pressione I para entrar no modo de inserção (no primeiro caractere que não seja espaço em branco na linha, pois você usou um maiúscula I e não minúscula) e digite // e depois pressione Escape.

Pressione n para ir para a próxima instância da palavra pesquisada. (Já que você está no começo da linha logo após os caracteres // , o cursor irá para a instância que acabou de encontrar. Então, pressione-o novamente para ir para a próxima instância.)

Supondo que havia apenas uma instância para ser comentada, você estará agora no início do arquivo novamente - a primeira linha. Pressione j para descer (ou simplesmente pressione Enter para ir para o primeiro caractere que não seja espaço em branco da próxima linha - o mesmo resultado neste caso).

Pressione * para ir para a próxima instância test3 , pois é isso que está sob o cursor agora.

Pressione . para repetir a ação "comentando a linha". O comando ponto é incrível. :)

Pressione n novamente. (Twice.) No texto do seu exemplo, você está pronto agora - você está de volta na segunda linha, test3 . Se houver mais linhas a serem comentadas, digite novamente j*.nn . E se houver outro, digite j*.nn novamente.

Quando terminar (você está em test3 ou qualquer que seja a última linha de list1 , logo acima da primeira linha original de list2 ), pressione dgg para excluir todas as linhas da linha atual para a primeira linha do arquivo - para que as entradas de list1 não estejam mais lá.

No total, o que você digita é

vim list2<Enter>

para abrir o arquivo e, em seguida:

:0r list1<Enter>
*I//<Esc>nn
j*.nn
j*.nn
j*.nn
(Repeat however many times)
dgg

Em seguida, para salvar e sair, digite :x e pressione Enter.

EDITAR:

Eu aprendi que o seu "list1" é enorme. Não importa; basta usar uma macro.

Depois de fazer o que foi mencionado acima algumas vezes, para ter certeza de que funciona, digite:

qkj*.nnq

Isso registrará j*.nn como uma macro no registro k .

Execute a macro digitando @k .

Execute-o novamente digitando @@ .

Em seguida, execute-o 4000 vezes digitando 4000@@ . Mas pessoalmente, eu faria em pedaços menores. E talvez não use o comando dot na macro, mas digite explicitamente I//<Esc> .

Aponte, eu ainda faço isso de forma interativa, e ainda levaria apenas um ou dois minutos, independentemente de quantas linhas eu tivesse que manipular. A magia do Vim. :)

    
por 09.08.2017 / 00:03
0

O algoritmo é:

 for each line of List2
     if line matches ANY pattern in List1 then
         print //line
     else
         print line

Aqui está uma implementação no bash (ou similar):

 while read line ;do
     if echo $line | fgrep -f List1 >/dev/null ;then
         echo "//$line"
     else
         echo "$line"
     fi
 done < List2
    
por 08.08.2017 / 00:39

Tags