Localiza arquivos com um padrão específico de 2 linhas usando o awk

3

Eu tenho algumas centenas de arquivos com esse padrão

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
 1  3  5  ar
@<TRIPOS>SUBSTRUCTURE

entre eles, alguns dos arquivos estão faltando a linha após o @<TRIPOS>BOND e eles se parecem com

@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

Eu estou tentando encontrar todos os arquivos no meu diretório de trabalho que estão faltando a linha numérica após o @<TRIPOS>BOND e movê-los para outro diretório. Eu sei que esta é uma tarefa simples, mas sou bastante nova no Linux.

Nota: os arquivos variam em comprimento e números de linha, é por isso que estou "aplicando" a linha após a string @<TRIPOS>BOND .

Aqui está um dos meus códigos, que eu estava planejando escrever em um loop for. Não faz o trabalho, mas eu estou mostrando para mostrar uma das minhas tentativas.

cat file | grep -A1 '@<TRIPOS>BOND' | awk 'FNR == 2 {print}'

Obrigado

    
por Error404 07.05.2014 / 11:38

6 respostas

6

Se a sua versão do grep for compatível com o modo PCRE ( -P ), você poderá tentar uma correspondência multilinha que encontre instâncias de @<TRIPOS>BOND seguidas (após apenas uma nova linha) por @<TRIPOS>SUBSTRUCTURE , por exemplo.

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

O \Q e \E podem ser desnecessários neste caso, mas destinam-se a forçar correspondência literal (no caso de @ , > , < ter um significado especial na sintaxe regex Perl). O -l diz ao grep para listar os arquivos correspondentes em vez de imprimir a correspondência. Você pode usar a lista de arquivos como uma entrada para o comando mv , por exemplo,

grep -lzP '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' * | xargs mv -t /path/to/newdir/


Informações adicionais

Você pode expressar a segunda parte da partida como lookahead , mas não acho que tenha vantagem nesse caso

grep -lzP '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *

Expressões equivalentes em pcregrep (que não fazem parte do sistema padrão do Ubuntu, mas podem ser obtidas do repositório) seriam algo como

pcregrep -lM '\Q@<TRIPOS>BOND\E\n\Q@<TRIPOS>SUBSTRUCTURE\E' *

e

pcregrep -lM '\Q@<TRIPOS>BOND\E\n(?=\Q@<TRIPOS>SUBSTRUCTURE\E)' *
    
por steeldriver 07.05.2014 / 12:45
3

Que tal

for file in *.txt; do 
    grep -A1 "@<TRIPOS>BOND" "$file" | grep -q SUBSTR && mv "$file" bad_files/
done

Explicação:

Isso fará o loop de todos os arquivos .txt no diretório atual (mude para o blob para o que corresponder aos arquivos) e salve cada um como $file . Em seguida, ele pesquisará $file para @<TRIPOS>BOND e imprimirá essa e a próxima linha. Isso é passado pelo próximo grep , que silenciosamente ( -q ) procura SUBSTR , se ele encontrar, significa que a linha depois de BOND é SUBSTRUCTURE e não a linha numérica que você deseja, então será mova o arquivo atual para a pasta bad_files .

    
por terdon 07.05.2014 / 12:54
0

Não é tão simples assim:

find -type f -exec \
 awk '/@<TRIPOS>BOND/{getline; \
  if ($0 !~ /1  3  5  ar/){\
  printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \
| bash

Explicação:

  • find -type f : localize todos os arquivos no diretório de trabalho atual
  • awk '/@<TRIPOS>BOND/{getline; \ : encontre a linha dentro do arquivo e vá para a próxima linha
  • if ($0 !~ /1 3 5 ar/){\ : Se a próxima linha NÃO for ( !~ ), sua "linha numérica" desejada
  • printf "mv %s /path/to/move/%s\n", FILENAME, FILENAME}}' {} \; \ : construa um comando mv e canalize-o para ...
  • | bash : ... bash e executá-lo.

Portanto, o comando irá mv todos os arquivos que não estão contando a linha numérica para um diretório chamado /path/to/move/ .

    
por chaos 07.05.2014 / 12:41
0
nawk '/^@<TRIPOS>BOND/{getline;if( $0 ~ /^@/){print "mv", FILENAME, "../NewLoc/"}}' * | bash
    
por Richard Romanus 07.05.2014 / 18:13
0

A tarefa é bem simples usando o awk. Aqui está meu exemplo. Eu criei dois arquivos file-nm (para não-missing) e file-m (para missing), e moved directory para os arquivos que queremos mover.

awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m

Aqui encontramos a string @<TRIPOS>BOND , entramos na próxima linha e verificamos se essa linha é @<TRIPOS>SUBSTRUCTURE . Se for, fazemos a chamada do sistema com "mv" o FILENAME do arquivo que foi encontrado e "movido" como destino. Aqui está o resultado:

$ ls
file-m  file-nm  moved


$ awk '/@<TRIPOS>BOND/ {getline; if ($0 == "@<TRIPOS>SUBSTRUCTURE" ) system("mv \""FILENAME"\" moved")}' file-nm file-m      


$ ls                                                                                                                     
file-nm  moved


$ ls moved                                                                                                               
file-m
    
por Sergiy Kolodyazhnyy 03.07.2015 / 20:10
0

Usando awk ou gawk

awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")} exit}' <file_name>

Explicação

  • /@<TRIPOS>BOND/,/@/

    Precisamos apenas do bloco entre @<TRIPOS>BOND e a próxima linha que começa com @

  • getline

    Leia a próxima linha depois de @<TRIPOS>BOND

  • if ($_ ~ /^@/)

    Verifique se a linha começa com @

    • true

      Imprimir uma mensagem

      printf "%s:%s\n",$_,FILENAME
      

      Mova o arquivo

      system ("mv \""FILENAME"\" <bad_files>/$(basename \""FILENAME"\")")
      
    • false

      Deixe o script

      exit
      

Exemplo

$ cat foo
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

$ cat bar
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
 1  3  5  ar
@<TRIPOS>SUBSTRUCTURE

$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' foo
@<TRIPOS>SUBSTRUCTURE:foo

$ awk '/@<TRIPOS>BOND/,/@/ {getline; if ($_ ~ /^@/) {printf "%s:%s\n",$_,FILENAME; system ("mv \""FILENAME"\" \""FILENAME"\"_moved")} exit}' bar

$ cat foo_moved 
@<TRIPOS>ATOM
  2 H18 65.2220 Du 1 RES1 0.0000
@<TRIPOS>BOND
@<TRIPOS>SUBSTRUCTURE

$ cat bar_moved
cat: bar_moved: No such file or directory
    
por A.B. 03.07.2015 / 23:58