Eu tenho uma string como: "thisissometext"
. Quero encontrar todos os arquivos de texto dentro de um determinado diretório (recursivamente) que contenha essa string, ou qualquer variação dela com espaços em branco e/ou novas linhas no meio dela. Por exemplo, um arquivo de texto contendo "this is sometext"
, ou "this\n issometext"
, "this\n isso metext"
deve aparecer na pesquisa. Como posso fazer isso?
Responder1
Com as versões mais recentes do GNU grep
(que tem a -z
opção), você pode usar este liner:
find . -type f -exec grep -lz 'this[[:space:]]*is[[:space:]]*some[[:space:]]*text' {} +
Considerando que os espaços em branco podem aparecer apenas entre as palavras.
Se você deseja apenas pesquisar todos os arquivos recursivamente a partir do diretório atual, não precisa find
, basta usar grep -r
(recursivo). find
pode ser usado para ser seletivo nos arquivos a serem pesquisados, por exemplo, escolher os arquivos de qual diretório excluir. Então, simplesmente:
grep -rlz 'this[[:space:]]*is[[:space:]]*some[[:space:]]*text' .
O truque principal aqui é
-z
: ele tratará cada linha do fluxo de entrada terminada em ASCII NUL em vez de uma nova linha, como resultado, podemos combinar novas linhas usando métodos usuais.[[:space:]]
O padrão de classe de caracteres indica quaisquer caracteres de espaço em branco, incluindo espaço, tabulação, CR, LF etc. Portanto, podemos usá-lo para corresponder a todos os caracteres de espaço em branco que podem aparecer entre as palavras.grep -l
imprimirá apenas os nomes de arquivos que possuem algum dos padrões desejados. Se você quiser imprimir as correspondências também, use-H
em vez de-l
.
Por outro lado, se os espaços em branco pudessem vir em qualquer lugar em vez das palavras, isso perderia a boa aparência:
grep -rlz
't[[:space:]]*h[[:space:]]*i[[:space:]]*s[[:space:]]*i[[:space:]]*\
s[[:space:]]*s[[:space:]]*o[[:space:]]*m[[:space:]]*e[[:space:]]*\
t[[:space:]]*e[[:space:]]*x[[:space:]]*t' .
Com -P
a opção (PCRE) você pode substituir [[:space:]]
por \s
(ficaria muito melhor):
grep -rlzP 't\s*h\s*i\s*s\s*i\s*s\s*s\s*o\s*m\s*e\s*\
t\s*e\s*x\s*t' .
Usar a sugestão de @steeldriver para sed
gerar o padrão para nós seria a melhor opção:
grep -rlzP "$(sed 's/./\\s*&/2g' <<< "thisissometext")" .
Responder2
Você pode excluir todos os espaços em branco e fazer o grep:
tr -d '[[:space:]]' < foo | grep thisissometext
Estendendo:
find . -type f -exec bash -c 'for i; do tr -d "[[:space:]]" < "$i" | grep -q thisissometext && printf "%s\n" "$i"; done' _ {} +
O bash
comando, expandido:
for i
do
tr -d "[[:space:]]" < "$i" |
grep -q thisissometext &&
printf "%s\n" "$i"
done
Isso percorre todos os argumentos e usa o teste acima.
Responder3
O código abaixo pesquisa arquivos recursivamente em um diretório, remove todas as ocorrências de " "
e "\n"
. Se a string existir no texto restante, há uma correspondência. Isso implica que os espaços/novas linhas podem estar emqualquerposição na string dentro do(s) seu(s) arquivo(s).
O que faz
Se encontrar arquivos correspondentes, eles serão impressos no terminal, incluindo seus caminhos, como:
/home/jacob/Bureaublad/testmap/test2.txt
/home/jacob/Bureaublad/testmap/Naamloze map 2/test1.txt
O try / except que eu incorporei para evitar que o script seja quebrado se for executado em um arquivo ilegível.
O roteiro
#!/usr/bin/env python3
import os
import sys
s = sys.argv[2]
for root, dirs, files in os.walk(sys.argv[1]):
for file in files:
file = root+"/"+file
try:
if s in open(file).read().replace(" ", "").replace("\n",""):
print(file)
except:
pass
Como usar
- Copie o script em um arquivo vazio e salve-o como
find_string.py
Execute-o com o diretório e a string como argumentos:
python3 /path/to/find_string.py <directory> <string_to_find>
Se a string ou o diretório contiver espaços, use aspas:
python3 /path/to/find_string.py '<directory>' '<string_to_find>'
Observação
O script, tal como está, encontra arquivos com a string, com espaços em branco ou novas linhas. Pode ser expandido com outros caracteres/strings (por exemplo, tabulações) na linha:
if s in open(file).read().replace(" ", "").replace("\n",""):
Responder4
Você poderia usar grep -i --recursive 'word1\|word2' *
e awk '/word1/,/word2/'
pode ser usado para lidar com a nova linha