Найти текстовый файл, содержащий заданный текст, игнорируя новые строки и пробелы?

Найти текстовый файл, содержащий заданный текст, игнорируя новые строки и пробелы?

У меня есть строка типа: "thisissometext". Я хочу найти все текстовые файлы внутри заданного каталога (рекурсивно), содержащие эту строку или любые ее вариации с пробелами и/или символами новой строки в середине. Например, текстовый файл, содержащий "this is sometext", или "this\n issometext", "this\n isso metext" должен отображаться в результатах поиска. Как это сделать?

решение1

В более новых версиях GNU grep(где есть такая -zвозможность) можно использовать следующую однострочную команду:

find . -type f -exec grep -lz 'this[[:space:]]*is[[:space:]]*some[[:space:]]*text' {} +

Учитывая, что пробелы могут быть только между словами.

Если вы просто хотите рекурсивно искать все файлы, начиная с текущего каталога, вам не нужно find, вы можете просто использовать grep -r(рекурсивный). findможет использоваться для выборочного поиска файлов, например, для выбора файлов из какого каталога исключить. Итак, просто:

grep -rlz 'this[[:space:]]*is[[:space:]]*some[[:space:]]*text' .
  • Главный трюк здесь в том -z, что он будет обрабатывать каждую строку входного потока, заканчивающуюся ASCII NUL, а не новой строкой, в результате чего мы можем сопоставлять новые строки, используя обычные методы.

  • [[:space:]]Шаблон класса символов указывает на любые пробельные символы, включая пробел, табуляцию, CR, LF и т. д. Таким образом, мы можем использовать его для сопоставления всех пробельных символов, которые могут встречаться между словами.

  • grep -lнапечатает только имена файлов, которые имеют любой из желаемых шаблонов. Если вы хотите напечатать также совпадения, используйте -Hвместо -l.

С другой стороны, если пробелы могут появляться в любых местах, а не только в словах, это потеряет свой привлекательный вид:

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' .

С -Pопцией (PCRE) вы можете заменить [[:space:]]на \s(это будет выглядеть намного лучше):

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' .

Лучшим вариантом было бы воспользоваться предложением @steeldriver, чтобы sedсгенерировать шаблон для нас:

grep -rlzP "$(sed 's/./\\s*&/2g' <<< "thisissometext")" .

решение2

Вы можете удалить все пробелы и выполнить grep:

tr -d '[[:space:]]' < foo | grep thisissometext

Продление:

find . -type f -exec bash -c 'for i; do tr -d "[[:space:]]" < "$i" | grep -q thisissometext && printf "%s\n" "$i"; done' _ {} +

Команда bash, развернутая:

for i
do
    tr -d "[[:space:]]" < "$i" | 
      grep -q thisissometext && 
      printf "%s\n" "$i"
done

Это цикл по всем аргументам и использует указанный выше тест.

решение3

Код ниже рекурсивно ищет файлы в каталоге, удаляет все вхождения " "и "\n". Если строка существует в оставшемся тексте, есть совпадение. Это означает, что пробелы/переводы строк могут быть налюбойположение в строке внутри вашего файла(ов).

Что оно делает

Если будут найдены соответствующие файлы, они будут выведены в терминал, включая пути к ним, например:

/home/jacob/Bureaublad/testmap/test2.txt
/home/jacob/Bureaublad/testmap/Naamloze map 2/test1.txt

Я встроил try / except, чтобы предотвратить сбой скрипта, если он столкнется с нечитаемым файлом.

Сценарий

#!/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

Как использовать

  1. Скопируйте скрипт в пустой файл, сохраните его какfind_string.py
  2. Запустите его, указав каталог и строку в качестве аргументов:

    python3 /path/to/find_string.py <directory> <string_to_find>
    

    Если строка или каталог содержат пробелы, используйте кавычки:

    python3 /path/to/find_string.py '<directory>' '<string_to_find>'
    

Примечание

Скрипт, как он есть, находит файлы со строкой, содержащей либо пробелы, либо переводы строк. Он может быть расширен другими символами/строками (например, табуляциями) в строке:

if s in open(file).read().replace(" ", "").replace("\n",""):

решение4

Вы можете использовать grep -i --recursive 'word1\|word2' *и awk '/word1/,/word2/'можете использовать для работы с новой строкой

введите описание изображения здесь

Связанный контент