Команды Linux: как "найти" только текстовые файлы?



после нескольких поисков от Google, что я придумал это:



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


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

589   15  

15 ответов:

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

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

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

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

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

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

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

findTextInAsciiFiles your_folder "needle text"

когда вы хотите.


EDIT чтобы отразить редактирование OP:

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

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "" -type f -exec grep -l "" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}

на основе это так вопрос:

grep -rIl "needle text" my_folder

find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

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

это пространство безопасным:

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

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "" "%"

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

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

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

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

вы можете отфильтровать ненужные типы файлов, добавив больше -e 'type' опции до последнего

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

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

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

2 . применение находят как и раньше

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;

у меня есть две проблемы с ответом histumness:

  • это только список текстовых файлов. На самом деле он не ищет их как запрошенный. Чтобы на самом деле искать, используйте

    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 С по сравнению с 4s для решения выше (2,5 ГБ данных / 7700 файлов), т. е. 20x быстрее.

кроме того, никто не привел АГ, Серебряный Искатель или ack-grepв качестве альтернативы. Если один из них доступен, они являются гораздо лучшими альтернативами:

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

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

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

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

find . ! -perm -111

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

find . -maxdepth 1 ! -perm -111

Не нужно труб чтобы смешать много команд, просто мощный равнина найти.

  • отказ от ответственности: это не ровно что ОП спросил, потому что он не проверяет, если файл binary или нет. Он будет, например, отфильтровывать bash script файлы, которые текст и сами, но есть исполняемый бит set.

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

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

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

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

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

Я делаю это таким образом: 1) поскольку слишком много файлов (~30k) для поиска, я ежедневно генерирую список текстовых файлов для использования через crontab, используя следующую команду:

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2) создать функцию .bashrc следующее:

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

тогда я могу использовать команду ниже, чтобы сделать поиск:

findex "needle text"

HTH:)

Я предпочитаю xargs

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

Если ваши имена файлов странные, посмотрите вверх, используя параметры -0:

find . -type f -print0 | xargs -0 grep -I "needle text"
  • пример bash для текста serach "eth0" в /etc во всех текстовых/ascii-файлах

grep eth0 $(find/ etc / - type f-exec file {} \; | egrep-i "text / ascii" | cut-d': '- f1)

вот упрощенная версия с расширенным объяснением для начинающих, таких как я, которые пытаются научиться помещать более одной команды в одну строку.

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

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

для этого мы можем использовать три команды UNIX:find,file и grep.

find проверит каждый файл в каталоге.

file даст нам типов. В нашем случае, мы ищем возвращение 'ASCII text'

grep будет искать ключевое слово 'ASCII' в выводе из file

так как же мы можем связать их вместе в одну строку? Есть несколько способов сделать это, но я считаю, что делать это в порядке нашего псевдо-кода имеет наибольший смысл (особенно для новичка, как я).

find ./ -exec file {} ";" | grep 'ASCII'

выглядит сложно, но не плохо, когда мы разбиваем его:

find ./ = полистай каждый файл в этом каталоге. Элемент find команда выводит имя файла любого файла, который соответствует "выражению", или все, что приходит после пути, который в нашем случае является текущим каталогом или ./

самое главное, чтобы понять, что все после этого Первого БИТа будет оцениваться как истина или ложь. Если True, имя файла будет распечатано. Если нет, то команда движется дальше.

-exec = этот флаг является вариант в команда find, которая позволяет нам использовать результат какой-либо другой команды в качестве выражения поиска. Это как вызов функции внутри функции.

file {} = команда вызывается внутри find. Элемент file команда возвращает строку, которая сообщает вам тип файла. Регулярно, это будет выглядеть так: file mytextfile.txt. В нашем случае мы хотим, чтобы он использовал любой файл, на который смотрит find команда, поэтому мы ставим фигурные скобки {} действовать как пустой переменной или параметру. Другими словами, мы просто просим систему вывести строку для каждого файла в каталоге.

";" = это требуется find и знак препинания в конце . См. руководство для "find" для получения дополнительных объяснений, если вам это нужно, запустив man find.

| grep 'ASCII'= | - это труба. Труба принимает выход того, что находится слева, и использует его как вход для того, что находится справа. Оно принимает выход из find команду (строку с типом файла) и тестов, чтобы увидеть, если он содержит строку 'ASCII'. Если это так, он возвращает true.

теперь выражение справа от find ./ вернет true, когда grep команда возвращает true. Вот.

если вы заинтересованы в поиске любого типа файлов по их волшебным байтам с помощью awesome 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

легенда: $ - это интерактивная командная строка, где мы вводим наши команды

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

объяснение:

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

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

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

 find . -type f|xargs grep "needle text"

Comments

    Ничего не найдено.