Команда Linux: Как «найти» только текстовые файлы? - PullRequest
88 голосов
/ 22 января 2011

После нескольких поисков в Google, я пришел к выводу:

find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text

, что очень неудобно и выводит ненужные тексты, такие как информация о типе пантомимы.Есть лучшие решения?У меня есть много изображений и других двоичных файлов в одной папке с большим количеством текстовых файлов, которые мне нужно найти.

Ответы [ 15 ]

157 голосов
/ 01 декабря 2012

Я знаю, что это старый поток, но я наткнулся на него и подумал, что поделюсь своим методом, который, как я обнаружил, является очень быстрым способом использования find для поиска только недвоичных файлов:

find . -type f -exec grep -Iq . {} \; -print

Параметр -I для grep указывает ему немедленно игнорировать двоичные файлы, а параметр . вместе с -q заставит его немедленно сопоставлять текстовые файлы, поэтому он будет работать очень быстро.Вы можете изменить -print на -print0 для подачи в xargs -0 или что-то еще, если вас интересуют пробелы (спасибо за подсказку, @ lucas.werkmeister!)

Также первая точканеобходим только для определенных версий BSD find, таких как в OS X, но это ничего не помешает, если он постоянно находится там, если вы хотите поместить его в псевдоним или что-то в этом роде.

EDIT : Как правильно заметил @ruslan, -and можно опустить, поскольку он подразумевается.

10 голосов
/ 06 июля 2012

На основании этого ТАК вопрос :

grep -rIl "needle text" my_folder

10 голосов
/ 22 января 2011

Почему это неудобно?Если вам нужно часто его использовать, и вы не хотите вводить его каждый раз, просто определите для него функцию bash:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text
}

поместите его в .bashrc, а затем просто запустите:

findTextInAsciiFiles your_folder "needle text"

всякий раз, когда вы хотите.


РЕДАКТИРОВАТЬ , чтобы отразить редактирование OP:

если вы хотите вырезать информацию MIME, вы можете просто добавитьдальнейшая стадия к конвейеру, который отфильтровывает информацию пантомимы.Это должно сработать, взяв только то, что предшествует :: cut -d':' -f1:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}
4 голосов
/ 22 января 2011
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

К сожалению, это не экономия места. Помещение этого в скрипт bash делает это немного проще.

Это пространство безопасно:

#!/bin/bash
#if [ ! "$1" ] ; then
    echo "Usage: $0 <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "$1" "%"
2 голосов
/ 03 февраля 2016

У меня есть два вопроса с ответом по истории:

  • Это только список текстовых файлов.На самом деле он не ищет их в соответствии с запросом.Для фактического поиска используйте

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • . Он запускает процесс grep для каждого файла, который очень медленный.Тогда лучшим решением будет

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    или просто

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    Это займет всего 0,2 с по сравнению с 4 с для решения выше (данные 2,5 ГБ / 7700 файлов), то есть 20xбыстрее .

Кроме того, никто не процитировал ag, Silver Searcher или ack-grep - как альтернативы.Если один из них доступен, они являются гораздо лучшими альтернативами:

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

В качестве последнего примечания остерегайтесь ложных срабатываний (двоичные файлы, принимаемые как текстовые файлы).У меня уже был ложный положительный результат при использовании grep / ag / ack, поэтому перед тем, как редактировать файлы, лучше перечислить соответствующие файлы.

2 голосов
/ 16 марта 2012

Вот как я это сделал ...

1.создайте небольшой скрипт, чтобы проверить, является ли файл простым текстом:

#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]

2.используйте find как раньше

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;
2 голосов
/ 22 января 2011

Как насчет этого:

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

Если вы хотите, чтобы имена файлов без типов файлов, просто добавьте окончательный фильтр sed.

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

Вы можете отфильтровать ненужныетипы файлов путем добавления дополнительных параметров -e 'type' к последней команде grep.

EDIT:

Если ваша версия xargs поддерживает параметр -d, приведенные выше команды становятся проще:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
1 голос
/ 04 ноября 2017

Другой способ сделать это:

# find . |xargs file {} \; |grep "ASCII text"

Если вы тоже хотите пустые файлы:

#  find . |xargs file {} \; |egrep "ASCII text|empty"
1 голос
/ 15 апреля 2017

Хотя это старый вопрос, я думаю, что эта информация ниже повысит качество ответов здесь.

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

find . ! -perm -111

Чтобы не допустить рекурсивного входа в другие каталоги:

find . -maxdepth 1 ! -perm -111

Нет необходимости в pipe для смешивания большого количества команд, только мощная простая команда find .

  • Отказ от ответственности: это не точно , о котором спрашивал OP, потому что он не проверяет, является ли файл двоичным или нет.Например, он будет отфильтровывать файлы bash script , которые сами являются text , но с установленным битом .

Тем не менее, я надеюсь, что это полезно для всех.

0 голосов
/ 14 июля 2018

Если вы заинтересованы в поиске файлов любого типа по их магическим байтам с помощью удивительной утилиты file в сочетании с мощностью find, это может пригодиться:

$ # Let's make some test files
$ mkdir ASCII-finder
$ cd ASCII-finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "$@" | grep ASCII &>/dev/null && echo "file is ASCII: $@"' -- @@

Вывод:

file is ASCII: ./text.txt

Условные обозначения: $ - это интерактивная подсказка оболочки, в которую мы вводим наши команды

Вы можете изменить деталь после &&, чтобы вызвать какой-либо другой сценарий или выполнитьтакже некоторые другие встроенные функции, например, если этот файл содержит заданную строку, присвойте ему весь файл или найдите в нем вторичную строку.

Объяснение:

  • find элементы, которые являются файлами
  • Make xargs подача каждого элемента в виде строки в один слой bash command / script
  • file проверяет тип файла по магическому байту,grep проверяет, существует ли ASCII, если так, то после && выполняется ваша следующая команда.
  • find выводит результаты с разделением null, это хорошо, если экранировать имена файлов с пробелами и метасимволами вit.
  • xargs, используя опцию -0, читает их null seВ аргументе -I @@ принимает каждую запись и использует как позиционный параметр / args для bash-скрипта.
  • -- для bash гарантирует, что все, что будет после аргумента, даже если оно начинается с -, как -c, который в противном случае может быть интерпретирован как опция bash

Если вам нужно найти типы, отличные от ASCII, просто замените grep ASCII другим типом, например grep "PDF document, version 1.4"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...