procurando arquivos com várias strings (todos inclusivos, não um ou outro) e imprimindo números de linha

1

Eu quero pesquisar por 2 (ou mais) strings nos arquivos de um determinado diretório e imprimir os números de linha.

Os resultados da pesquisa devem incluir apenas os arquivos em que todas as cadeias mencionadas estão presentes (podem ou não estar na mesma linha). Deve excluir arquivos que contenham uma das strings, mas não todas.

Qual deve ser um comando conveniente para conseguir isso?

    
por Siddhartha Ghosh 04.06.2015 / 09:57

2 respostas

1

Com o GNU awk você pode fazer:

awk 'BEGINFILE { n1=n2=0 }
     /str1/ { n1=FNR }
     /str2/ { n2=FNR }
     ENDFILE { if (n1&&n2) print FILENAME,n1,n2 }
' files...

Uma variante para uma lista de strings a considerar:

awk -v s="str1 str2 str3" '
  BEGIN { n=split(s,str) ; m=(2^n)-1 }
  BEGINFILE { f=0 }
  { for (i=1; i<=n; i++)
    if ($0 ~ str[i]) {
      l[i] = FNR
      f += 2^(i-1)
    }
  }
  ENDFILE {
    if (f==m)
      for (i=1; i<=n; i++) print FILENAME,l[i]
  }
' files...

Os comandos são melhor colocados em um arquivo de script para execução e substituindo a files... list por "$@" para passar os arquivos como argumentos para o script.

Um script, digamos "findall", para passar o diretório (conforme solicitado no comentário) e as sequências de pesquisa podem ser:

dir=${1:?}
shift
cd "$dir" || exit 1

awk -v s="$*" '
  ...as above...
' *

e coukd serão chamados findall dir str1 str2 ... strN . (Observe que as sequências de pesquisa podem não conter caracteres de espaço em branco.)

    
por 04.06.2015 / 10:14
0

Um método é primeiro listar os arquivos correspondentes e ler os arquivos novamente para encontrar as linhas desejadas. Isso é eficiente, desde que os arquivos correspondentes não sejam muito grandes ou numerosos.

Assumindo utilitários GNU recentes (Linux / Cygwin) para evitar problemas com nomes de arquivos contendo caracteres especiais:

grep -Rlz -Fe "foo" . |
xargs -0 grep -lz -Fe "bar" /dev/null |
xargs -0 grep -lz -Fe "qux" /dev/null |
xargs -0 awk '/foo|bar|qux/ {print FNR}' /dev/null
    
por 05.06.2015 / 02:58