Eu quero procurar arquivos contendo as palavras Dansk
, Svenska
ou Norsk
em qualquer linha, com um código de retorno utilizável (como eu realmente só gosto de ter a informação de que as strings estão contidas, meu one-liner vai um pouco além disso).
Tenho muitos arquivos com linhas como este:
Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20,
Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21,
Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22,
Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23,
Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24,
(...)
Aqui está o pseudocódigo do que eu quero:
for all files in directory;
if file contains "Dansk" AND "Norsk" AND "Svenska" then
then echo the filename
end
Qual é a melhor maneira de fazer isso? Isso pode ser feito em uma linha?
PIPESTATUS
matriz contém os valores de saída dos membros de um pipeline.pipefail
opção shell (temporariamente):shopt -so pipefail
grep -Z
exargs -0
se seus nomes de arquivo podem conter espaços.Ainda outra maneira usando apenas bash e grep:
Para um único arquivo 'test.txt':
Será impresso
test.txt
se o arquivo contiver todos os três (em qualquer combinação). Os dois primeiros greps não imprimem nada (-q
) e o último só imprime o arquivo se os outros dois tiverem passado.Se você quiser fazer isso para cada arquivo no diretório:
fonte
for f ...
: use"$f"
(aspas duplas) em vez de apenas$f
garantir que os nomes dos arquivos com espaços embutidos, etc. sejam tratados corretamente.-i
torna a pesquisa insensível a maiúsculas e minúsculas-r
torna a pesquisa de arquivos recursiva através de pastas-l
canaliza a lista de arquivos com a palavra encontradacat -
faz com que o próximo grep examine os arquivos passados para sua lista.fonte
Como fazer o grep para várias strings no arquivo em linhas diferentes (use o símbolo de barra vertical):
for file in *;do test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file done
Notas:
Se você usar aspas duplas
""
com seu grep, terá que escapar do tubo assim:\|
para pesquisar Dansk, Norsk e Svenska.Presume que uma linha possui apenas um idioma.
Passo a passo: http://www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/
fonte
Norsk
, mas em três linhas diferentes.Você pode fazer isso facilmente com ack :
ack -l 'cats' | ack -xl 'dogs'
-l
: retorna uma lista de arquivos-x
: pegue os arquivos de STDIN (a pesquisa anterior) e pesquise apenas esses arquivosE você pode simplesmente continuar enviando até obter os arquivos que deseja.
fonte
Unknown option: x
. Existe uma certa versão do ack que suporta este sinalizador x?awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }'
você pode então pegar o valor de retorno com o shell
se você tem Ruby (1.9+)
ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file
fonte
if (a && b && c) {exit 0} else {exit 1}
:, ou mais concisoexit !(a && b && c)
Isso pesquisa várias palavras em vários arquivos:
egrep 'abc|xyz' file1 file2 ..filen
fonte
Simplesmente:
grep 'word1\|word2\|word3' *
veja esta postagem para mais informações
fonte
-l
sinalizador, mas fora isso, essa resposta parece a mais direta para mim, a menos que esteja faltando alguma coisa.Esta é uma mistura das respostas de glenn jackman e kurumi que permite um número arbitrário de regexes em vez de um número arbitrário de palavras fixas ou um conjunto fixo de regexes.
#!/usr/bin/awk -f # by Dennis Williamson - 2011-01-25 BEGIN { for (i=ARGC-2; i>=1; i--) { patterns[ARGV[i]] = 0; delete ARGV[i]; } } { for (p in patterns) if ($0 ~ p) matches[p] = 1 # print # the matching line could be printed } END { for (p in patterns) { if (matches[p] != 1) exit 1 } }
Execute assim:
./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat
fonte
Aqui está o que funcionou bem para mim:
find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \; ./path/to/file1.sh ./another/path/to/file2.txt ./blah/foo.php
Se eu quisesse apenas encontrar arquivos .sh com esses três, poderia ter usado:
find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \; ./path/to/file1.sh
fonte
Expandindo a resposta awk de @kurumi, aqui está uma função bash:
all_word_search() { gawk ' BEGIN { for (i=ARGC-2; i>=1; i--) { search_terms[ARGV[i]] = 0; ARGV[i] = ARGV[i+1]; delete ARGV[i+1]; } } { for (i=1;i<=NF; i++) if ($i in search_terms) search_terms[$1] = 1 } END { for (word in search_terms) if (search_terms[word] == 0) exit 1 } ' "$@" return $? }
Uso:
if all_word_search Dansk Norsk Svenska filename; then echo "all words found" else echo "not all words found" fi
fonte
Eu fiz isso com duas etapas. Faça uma lista de arquivos csv em um arquivo Com a ajuda dos comentários desta página, fiz duas etapas sem script para obter o que precisava. Basta digitar no terminal:
$ find /csv/file/dir -name '*.csv' > csv_list.txt $ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`
fez exatamente o que eu precisava - imprimir nomes de arquivos contendo todas as três palavras.
Lembre-se também dos símbolos como
`' "
fonte
Se você só precisa de dois termos de pesquisa, provavelmente a abordagem mais legível é executar cada pesquisa e cruzar os resultados:
fonte
Se você tem git instalado
O --no-index procura arquivos no diretório atual que não é gerenciado pelo Git. Portanto, este comando funcionará em qualquer diretório, independentemente de ser um repositório git ou não.
fonte
Tive esse problema hoje, e todos os one-liners aqui falharam porque os arquivos continham espaços nos nomes.
Isso é o que eu descobri que funcionou:
grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
fonte