Encontre arquivos que contenham uma string e não contenham outra [duplicata]

0

Digamos que eu tenha alguns arquivos e quero encontrar os arquivos entre eles que contenham uma string, mas não contenham outra.

grep sendo baseado em linha, condições como grep -q printf file && grep -vq '#include <stdio.h>' file não funcionarão.

Como devo fazer isso?

(Eu estou no Debian, então respostas especificamente direcionadas a versões GNU de ferramentas estão bem.)

    
por user2064000 16.01.2017 / 17:03

4 respostas

2

grep -vl informaria o nome dos arquivos que possuem pelo menos uma linha que corresponde ao padrão. Aqui você quer os arquivos onde nenhum da linha corresponde ao padrão. O GNU grep (como encontrado no Debian) tem uma opção -L para isso:

grep -rlZ printf . | xargs -r0 grep -FL '#include <stdio.h>'

Com qualquer POSIX grep , você pode negar apenas grep -q :

find . -type f -exec grep -q printf {} \; \
               ! -exec grep -Fq '#include <stdio.h>' {} \; \
               -print

Muito menos eficiente, pois isso significa executar duas instâncias grep em cada arquivo.

    
por 16.01.2017 / 17:50
0

Combine find com bash -c em vez de um script. Pegamos o caminho do arquivo e o armazenamos na variável file , depois o passamos para outros comandos. Primeiro grep -q irá verificar se existe uma palavra / padrão que você quer que esteja presente. Usando seu status de saída, && irá passá-lo para o segundo grep -q . Se esse comando não encontrar uma correspondência, isso significa que a string não foi encontrada, portanto, usando seu status de saída, passamos para o operador echo via || .

No exemplo abaixo, apenas file2.txt contém abra , mas não cadabra word.

$ find -type f -exec bash -c 'file="$@";grep -q "abra" "$file"  &&  grep -q "cadabra" "$file" || echo "$file" ' sh "{}" >
./file2.txt
$ ls                                                                                                                     
file1.txt  file2.txt  file 3.txt
$ cat file1.txt
abra cadabra
$ cat file2.txt                                                                                                          
abra
$ cat file\ 3.txt                                                                                                        
abra cadabra
    
por 16.01.2017 / 17:25
0

É bem fácil:

for fname in ./*.c; do
  if grep -q -F "printf" "$fname" && ! grep -q -F "#include <stdio.h>" "$fname"; then
     printf 'File "%s" needs to include stdio.h\n' "$fname"
  fi
done

Isso examinará todos os arquivos de origem C no diretório atual e informará qualquer arquivo que use printf() sem incluir o cabeçalho stdio.h .

O cabeçalho pode ser incluído indiretamente, portanto, para evitar falsos positivos, você poderia passar o código através do pré-processador C e procurar pelo cabeçalho na saída pré-processada (isso parece funcionar com gcc e clang ):

for fname in ./*.c; do
  if grep -q -F "printf" "$fname" && cc -E "$fname" | ! grep -q "^#.*stdio\.h\""; then
     printf 'File "%s" needs to include stdio.h\n' "$fname"
  fi
done
    
por 16.01.2017 / 18:11
0

Se eu ler o requisito corretamente, você deseja que todos os arquivos correspondam a $PAT_INCL menos os arquivos correspondentes a $PAT_EXCL .

Conceitualmente, isso é apenas subtração definida. Não há um utilitário padrão muito bom para operações de conjunto no unix, mas comm funciona.

comm -23 <(grep --files-with-match "$PAT_INCL"  * | sort) \
         <(grep --files-with-match "$PATH_EXCL" * | sort)

Isso pode se tornar um pouco mais eficiente apenas percorrendo os arquivos correspondentes no segundo grep:

# Assuming filenames without whitespace
grep --files-with-match "$PAT_INCL" * | sort > incl_files
grep --files-with-match "$PAT_EXCL" $(cat incl_files) | sort > excl_files
comm -23 incl_files excl_files
    
por 16.01.2017 / 19:48