Команды Linux: как "найти" только текстовые файлы?
после нескольких поисков от Google, что я придумал это:
find my_folder -type f -exec grep -l "needle text" {} ; -exec file {} ; | grep text
что очень неудобно и выводит ненужные тексты, такие как информация о типе mime. Лучше решения? У меня есть много изображений и других двоичных файлов в той же папке с большим количеством текстовых файлов, которые мне нужно искать.
15 ответов:
Я знаю, что это старая нить, но я наткнулся на нее и подумал, что поделюсь своим методом, который я нашел очень быстрый способ использовать
findнайти только двоичные файлы:find . -type f -exec grep -Iq . {} \; -and -printThe
-Iопция grep говорит ему немедленно игнорировать двоичные файлы и вместе с-qсделает это сразу же соответствовать текстовые файлы, так что это идет очень быстро. Вы можете изменить-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"
Comments