Этот вопрос запрашивается коротким сценарием, который я нашел в журнале Linux. Поскольку доказательство, что я не составлял это, вот является изображением его:
Я хотел бы записать букву редактору этой публикации обо что случилось с этим и как записать это лучше.
Сценарий пытается получить jpeg файлы в переменную, так, чтобы что-то (использование сжатия lepton
) может быть сделан с ними.
for jpeg in `echo "$(file $(find ./ ) |
grep JPEG | cut -f 1 -d ':')"`
do
/path/to/command "$jpeg"
...
По-видимому, в этом экземпляре мы не можем доверять файлам, которые назовут с a .jpg
расширение, таким образом, мы не можем поймать их с чем-то как
for f in *.JPG *.jpg *.JPEG *.jpeg ; do ...
потому что писатель использовал file
проверять их тип, но если именам файлов нельзя доверять, чтобы иметь разумное расширение, то я не вижу, как мы можем доверять им, чтобы не быть -rf *
или (; \ $!|
или имейте новые строки или безотносительно.
Как я могу нормально получить файлы в переменную типом с for
или while
, или, возможно, постарайтесь не делать так при помощи find
с -exec
, или некоторый другой метод?
Премия для понимания и демонстраций что случилось с кодом в изображении.
Я отметил этот вопрос с [ударом], так как это о сценарии удара, но если Вы испытываете желание отвечать способом сделать это, которое не использует удар, затем не стесняйтесь делать это.
Давайте сделаем это со специальными шариками и a Bash for
цикл:
#!/bin/bash
shopt -s globstar dotglob
for f in ./** ; do
if file -b -- "$f" | grep -q '^JPEG image data,' ; then
# do whatever you want with the JPEG file "$f" in here:
md5sum -- "$f"
fi
done
В первую очередь, мы должны сделать шарики Bash более полезными путем включения globstar
и dotglob
опции оболочки. Вот их описание от man bash
в SHELL ВСТРОЕННЫЙ раздел COMMANDS о shopt
:
dotglob
If set, bash includes filenames beginning with a `.' in the results of
pathname expansion.
globstar
If set, the pattern ** used in a pathname expansion context will match
all files and zero or more directories and subdirectories. If the pattern
is followed by a /, only directories and subdirectories match.
Затем мы используем этот новый "рекурсивный шарик" ./**
в a for
цикл для итерации по всем файлам и папкам в текущем каталоге и всех его подкаталогах. Всегда используйте полные пути или явные относительные пути, запускающиеся с a ./
или ../
в Ваших шариках, не просто **
, предотвратить проблемы со специальными именами файлов как ~
.
Теперь мы тестируем каждый файл (и папка) имя с file
команда для ее содержания. -b
опция препятствует тому, чтобы он печатал имя файла снова перед строкой информации о содержании, которая делает фильтрацию более безопасной.
Теперь мы знаем, что информация о содержании всех допустимых файлов JPG/JPEG должна запуститься с JPEG image data,
, который является тем, из чего мы тестируем вывод file
поскольку с grep
. Мы используем -q
опция подавить любой вывод, поскольку мы только интересуемся grep
код выхода, который указывает, соответствовал ли шаблон или нет.
Если это соответствовало, код в if
/then
блок будет выполняться. Мы можем сделать что-либо, в чем мы хотим здесь. Текущее имя файла JPEG доступно в переменной оболочки $f
. Мы просто должны удостовериться, что всегда поместили его в двойные кавычки для предотвращения случайной оценки имен файлов со специальными символами как пробелы, новые строки или символы. Также обычно лучше разделить его от других аргументов путем размещения его после --
, который заставляет большинство команд интерпретировать его как имя файла, даже если это - что-то как -v
или --help
это было бы иначе интерпретировано как опция.
Время для аварийного завершения некоторого кода, для науки! Вот версия от Вашего вопроса/книги:
for jpeg in `echo "$(file $(find ./ )
| grep JPEG | cut -f 1 -d ':')"`
do
/path/to/command "$jpeg"
done
В первую очередь, позвольте мне упоминать, как сложный они записали это. У нас есть 4 уровня вложенных подоболочек, с помощью смешанных синтаксисов замены команды (``
и $()
), которые просто необходимы из-за неправильного/субоптимального использования find
.
Здесь find
просто списки все файлы и печать их имена, один на строку. Затем полный вывод передается file
исследовать каждого из них. Но ожидайте! Одно имя файла на строку? Что относительно имен файлов, содержащих новые строки? Право, они повредят его!
$ ls --escape ne*ne
new\nline
$ file $(find . -name 'ne*ne' )
./new: cannot open `./new' (No such file or directory)
line: cannot open `line' (No such file or directory)
На самом деле даже простые пробелы повреждают его также, потому что их рассматривают как разделители также file
. Вы не можете даже заключить в кавычки "$(find ./ )"
здесь как средство, потому что это затем заключило бы целый многострочный вывод в кавычки как один единственный аргумент имени файла.
$ ls simple*
simple spaces.jpg
$ file $(find ./ -name 'simple*')
./simple: cannot open `./simple' (No such file or directory)
spaces.jpg: cannot open `spaces.jpg' (No such file or directory)
Следующий шаг, file
вывод сканируется с grep JPEG
. Не делайте Вы думаете, что немного легко обмануть такой простой шаблон, тем более, что вывод плоскости file
всегда содержит имя файла также? В основном все с "JPEG" в его имени файла инициирует соответствие, независимо от того, что он содержит.
$ echo "to be or not to be" > IAmNoJPEG.txt
$ file IAmNoJPEG.txt | grep JPEG
IAmNoJPEG.txt: ASCII text
Хорошо, таким образом, мы имеем file
вывод всех файлов JPEG (или те, кто симулирует быть одним), теперь они обрабатывают все строки с cut
извлечь исходное имя файла из первого столбца, разделенного двоеточием... Угадайте, что, давайте попробуем это на файле с двоеточием на его имя:
$ ls colon*
colons:evil.jpeg
$ file colon* | grep JPEG | cut -f 1 -d ':'
colons
В заключение, подход от Ваших книжных работ, но только если все файлы это проверяет, не содержит пробелов, новых строк, двоеточий и вероятно других специальных символов и не содержит строку "JPEG" нигде в их именах файлов. Это также довольно ужасно, но поскольку красота лежит в глазу наблюдателя, я не собираюсь околачиваться об этом.
Сценарий, показанный в Вашем вопросе, пытается перечислить файлы и проверку, если они - JPEGs, но не делает ни одного надежно. Это пытается передать все пути к file
в единственном выполнении и извлечении и имена файлов и типы от вывода file
, который разумен, так как это может быть быстрее, чем выполнение file
снова и снова для каждого файла. Но сделать это правильно, необходимо быть осторожны относительно того, как пути передаются file
, как file
разграничивает его вывод, и как Вы используете тот вывод. Можно использовать это:
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
# Bash placed the filename in "$REPLY" -- put commands that use it here.
# You can have as many commands as you want before the closing ";;" token.
;;
esac
done
Это - один из нескольких корректных путей. (Это не должно устанавливать IFS=
; посмотрите ниже.) find
с +
аргументы разнообразного пути передач file
и только выполнения это так же много раз по мере необходимости для обработки их всех, обычно только однажды. Кредит переходит к AFSHIN для идеи передать --mime-type
кому: file
получить тип MIME, который содержит информацию, которую Вы на самом деле хотите и легки проанализировать.
Подробное объяснение следует. Я использовал определенную задачу сжатия JPEG как пример. Это - то, что сценарий, который Вы показали, для, и lepton
имеет некоторые причуды, которые нужно рассмотреть в решении, как улучшить тот сценарий. Если Вы просто хотите видеть сценарий, который работает lepton
на каждом файле JPEG можно пропустить для разделения 7. Соединение Всего этого.
Термин путь имеет несколько определений. В этом ответе я использую его для значения пути.
lepton
Сценарий, который Вы показали, предназначен, чтобы пересечь иерархию каталогов, найти изображения JPEG и обработать их с компрессором JPEG без потерь lepton
. Для основной мотивации Вашего вопроса не может действительно иметь значения команда, но различные команды имеют другой синтаксис. Некоторые команды принимают несколько входных имен файлов для единственного выполнения. Большинство принимает --
указать на конец опций. Я буду использовать lepton
как мой пример. lepton
команда не принимает несколько входных имен файлов и не распознает --
.
Использовать lepton
, установите его сначала. Это официально упаковывается для Ubuntu 17.04 и позже (sudo apt install lepton
). Для более ранних релизов Ubuntu, или использовать более новую версию, чем упаковывается для Вашего выпуска, клон git
репозиторий (git clone https://github.com/dropbox/lepton.git
) и создайте источник, как проинструктировано в README. Или Вы смогли находить PPA.
Завися, как Вы устанавливаете его, lepton
может быть в /usr/bin
, /usr/local/bin
, или в другом месте. Вероятно, Вы захотите это где-нибудь в $PATH
; затем можно выполнить его как lepton
. Сценарий Вы показали полные пути использования lepton
и стандартные утилиты mv
и rm
, но не к другим стандартным утилитам file
, find
, grep
и cut
. (Это - Bash, таким образом, echo
- бессмысленный в том сценарии так или иначе - встроенная оболочка. exit
всегда встроенное.), Хотя это не один из серьезных дефектов сценария, нет никакой заметной причины такого несоответствия. Если Вы не пишете сценарий для признания не наличия $PATH
набор разумно - в этом случае необходимо использовать полные пути для всех внешних команд - я предлагаю использовать относительные пути для стандартных команд и тех, которых Вы установили.
lepton
Я протестировал с лептоном v1.0-1.2.1-104-g209463a (от Мерзавца). lepton
был выпущен назад в июле 2016, таким образом, я предположу, что текущий синтаксис будет продолжать работать. Но будущие версии могут добавить опции. При чтении этого годы с этого времени Вы могли бы проверить если lepton
добавила поддержка задач, которые когда-то потребовали сценариев.
Будьте осторожны, какие параметры командной строки Вы передаете. Например, я пытался работать lepton
с -verbose
как первый аргумент и art.jpg
как второе. Это интерпретировало -verbose
как входное имя файла и выход с ошибкой, но не перед усечением art.jpg
- который это интерпретировало как выходное имя файла - вниз для обнуления байтов. К счастью, у меня было резервное копирование!
Можно передать нуль, один, или два пути к lepton
. Во всех случаях это исследует свой входной файл или поток, чтобы видеть, содержит ли это данные Лептона или JPEG. JPEG сжат до Лептона; Лептон распаковывается к JPEG. lepton
удалит и добавит расширения файла, но не использует их для решения, что сделать.
lepton -
чтения от stdin и записей к stdout.Таким образом lepton - < infile > outfile
один путь состоит в том, чтобы читать из infile
и запишите в outfile
, даже если их имена запускаются с -
(как опции делают). Но метод, я буду использовать пути передач, которые запускаются с .
, таким образом, я не должен буду волноваться об этом.
lepton infile
чтения infile
и называет его собственный выходной файл.Это - то, как сценарий Вы показали использование lepton
.
Если содержание infile
похож на JPEG, lepton
производит файл Лептона; если его содержание похоже на файл Лептона, lepton
производит JPEG. lepton
решает, как это хочет назвать свой выходной файл путем разделения расширения от infile
, если таковые имеются, и добавление любого a .jpg
или .lep
расширение в зависимости от того, какой файл это создает. Но это не использует расширение, которое это удаляет (если таковые имеются) для выведения типа файла, на который это воздействует.
Это рассматривает последнее .
и что-либо после него как расширение. Если infile
a.b.c
, Вы добираетесь a.b.lep
или a.b.jpg
. Если имя файла запускается с a .
без другого .
s, lepton
все еще отношения, что как расширение: от названного JPEG .abc
Вы добираетесь .lep
. Только .
в имени файла - не именах каталогов - инициировал это, таким образом, из файла Лептона x/fo.o/abc
Вы добираетесь x/fo.o/abc.jpg
(который Вы хотите), нет x/fo.jpg
(который был бы плох).
Если выходное имя файла получило этот путь имена существующий файл, _
s добавляются в конец, после расширения, пока оно не делает, и используется имя с добавленными символами нижнего подчеркивания: abc.lep
, abc.lep_
, abc.lep__
, и т.д.,xyz.jpg
, xyz.jpg_
, xyz.jpg__
, и т.д.
Автоматически удаление и добавление расширений и добавление символов нижнего подчеркивания избегают проблемы, которой необходимо было бы иначе управлять сами - предотвращение потери данных, когда выходной файл уже существует. Но это также выставляет то, что могло бы быть глубоким недостатком дизайна в сценарии, который Вы показали. Если Ваши файлы называют разумно, то весь Ваш конец файлов JPEG в .jpg
или .jpeg
(возможно, использованный для своей выгоды), и никакие файлы не-JPEG так названы. Но затем Вы не должны исследовать файлы с file
узнать, которые JPEGs!
Таким образом предпосылка сценария, который Вы показали, - то, что файлы нельзя было бы назвать обоснованно. Это всегда плохо для сценария для поведения неправильно или неожиданно на именах файлов, содержащих пробелы, *
, и другие специальные символы. Таким образом, его поведение разделения на пробеле и расширения шариков (внешняя неупомянутая замена команды, предназначенная только для разделения отдельных имен файлов, делает это) особенно плохо. См. превосходный ответ Командующего Байта для деталей. Это - вероятно, худший дефект в сценарии, который Вы показали.
Но это также достойно рассмотрения, что происходит с именами файлов чей в последний раз .
концептуально не начинает расширение файла. Предположим Pictures
имеет четыре файла, весь JPEGs: 01. Milan wide-angle sunset
, 01. Milan wide-angle sunset highres
, 02. Kyle birthday party prep - blooper cakes
, и 03. The subtle found art of unopened expired paint cans with peeling labels
. Затем for f in ~/Pictures/0*; do lepton "$f"; done
создает 01.lep
, 01.lep_
, 02.lep
, и 03.lep
- вероятно, не, что Вы хотите.
Если у Вас есть JPEGs, не названный .jpg
или возможно .jpeg
, лучший общий подход должен переименовать их тот путь и исследовать любые конфликты имен, которые возникают при выполнении так. Но это выходит за рамки этого ответа.
Те, которые переименовывают проблемы, происходят с JPEGs, не названным как JPEGs, не non-JPEGs названный как JPEGs. Все же даже затем, может быть лучшее решение. Если проблема ._
файлы от macOS и Вы не хотите удалять их, просто исключать файлы с продвижением ._
(или даже продвижение .
). Однако, передавая всего один путь к lepton
избегает потери данных (из-за _
добавление правил); если главная цель состоит в том, чтобы исключить non-JPEGs, основная идея является звуковой даже при том, что для реализации нужна фиксация.
Таким образом, я буду использовать один путь lepton infile
синтаксис. Но любой, кто рассматривает автоматизацию lepton
как это на странно именованных файлах должен помнить сгенерированный .lep
файлы можно назвать способами, которые не показывают входные имена файлов.
lepton infile outfile
делает точно, что Вы ожидаете.Но просто потому что Вы ожидаете, что это не делает это правильным поступком.
Как с другими способами работать lepton
, lepton
определяет ли infile
JPEG должен быть сжат или файл Лептона, который будет распакован путем исследования его содержания. Если infile
JPEG, lepton
пишет названный файл Лептона outfile
; если infile
файл Лептона, lepton
пишет названный JPEG outfile
. С этим синтаксисом с двумя путями, lepton
не изменяет Ваше указанное выходное имя файла всегда. Это не добавляет или удаляет расширения или добавляет _
s для разрешения конфликтов имен. Если outfile
уже существует, это перезаписывается.
Можно хотеть это, но если не и Вы используете этот синтаксис затем, необходимо решить проблему сами, заставив сценарий скорректировать выходные имена файлов. Вы можете делать это способом, которое служит Вам лучше, чем lepton
собственная схема, когда выполнено со всего одним параметром пути. Но я не попытаюсь предположить Ваши определенные потребности и предпочтения; я буду просто использовать синтаксис с одним путем.
find
кому: file
Сценарий Вы показали попытки использовать file $(find ./ )
передать один путь на аргумент file
путем выполнения find
в замене команды. Это часто не будет работать, потому что $(find ./ )
разделения на пробеле, который могут содержать имена файлов. Это характерно для файлов - особенно отображает! - и папки, чтобы иметь пробелы на их имена. Сценарий Вы показали обработкам путь ./abc/foo bar.jpg
как два пути, ./abc/foo
и bar.jpg
. В лучшем случае ни один не существует; если они делают, Вы неумышленно воздействуете на неправильную вещь. И первоначальный тракт не будет обработан вообще.
Хотя ширина этой проблемы может быть уменьшена путем установки IFS=$'\n'
таким образом, разделение слова только выполняется между строками (\n
представляет символ новой строки), это не хорошее решение. Помимо того, чтобы быть неловким, это может все еще перестать работать, поскольку имена файлов и имена каталогов могут содержать новые строки. Я отговариваю от именования файлов или каталогов с ними кроме к тестовым программам или сценариям для ошибок. Но такие имена могут быть созданы, включая случайно, где Вы не ожидаете их. Единственные символы, которые не может содержать имя файла, являются разделителем пути /
и нулевой символ. Нулевой символ является таким образом единственным, который не может появиться в пути и единственном безопасном выборе разграничить списки произвольных путей. Вот почему find
имеет a -print0
действие и xargs
имеет a -0
опция.
Это может быть сделано правильно с find . -print0 | xargs -0 ...
но Вам не нужна третья утилита для передачи путей от find
кому: file
. find
-exec
действие достаточно. Аргументы после -exec
создайте команду для выполнения, до \;
или +
. find ... -exec ... \;
выполняет команду однажды на файл, в то время как find ... -exec ... +
передает команду столько путей, сколько она может на выполнение, которое обычно быстрее. Обычно все аргументы соответствуют и выполнения команды только однажды. В редких случаях командная строка была бы слишком длинной и find
выполняет команду несколько раз. Так +
форма только безопасна для выполнения команд, которые (a) взятие их параметры пути в конце и (b) работа то же в одном выполнении с несколькими именами файлов, как они делают в отдельных выполнениях.
lepton
пример команды, которая не должна быть выполнена с помощью +
форма -exec
потому что это не принимает несколько исходных имен файлов. Первым был бы вход, вторым будет вывод, и другие были бы чрезмерными. Но много команд действительно делают то же самое, когда выполнено однажды с несколькими аргументами как тогда, когда выполнено несколько раз с одним аргументом, и file
один из них.
Эта команда генерирует таблицу:
find . -exec file --mime-type -r0F '' {} +
find
замены {}
спор с путем, когда это вызывает file
, и замены +
со столькими дополнительными параметрами пути, сколько будет соответствовать.
Опции --mime-type -r0F ''
переданный find
объяснены ниже.
Некоторые люди кавычка {}
, например, '{}'
. Хорошо делать так, но ни Bash, ни другие оболочки стиля Границы не требуют его. Bash и некоторое другое расширение фигурной скобки поддержки оболочек, но пустая пара фигурных скобок не расширены. Я принимаю решение не заключить в кавычки {}
, в свете неправильного представления то заключение в кавычки {}
предотвращает find
от работающего разделения слова. Даже если Ваша оболочка требуется {}
чтобы быть заключенным в кавычки, это все еще не имело бы никакого отношения к разделению слова, потому что find
никогда не делает это. (Если бы Вы хотели разделение слова, то необходимо было бы сказать find
кому: -exec
оболочка.) И find
не может сказать, записали ли Вы {}
или '{}'
- повороты оболочки '{}'
в {}
(во время удаления кавычки) прежде, чем передать его find
.
file
Причина я должен передать некоторые опции file
- и не может просто использовать find . -exec file {} +
- это таблица file
генерирует по умолчанию неоднозначно:
01. Milan wide-angle sunset: JPEG image data, JFIF standard 1.01, resolution (DPI), density 1x1, segment length 16, baseline, precision 8, 1400x1400, frames 3
02. Kyle birthday party prep - blooper cakes: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 512x512, frames 3
first line
second line: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 500x500, frames 3
Те три строки похожи четыре; одно имя файла содержит новую строку. Имена файлов могут также содержать двоеточия, таким образом, не всегда будет ясно, где имя файла заканчивается. Путем более запутывающие примеры, чем показанный выше возможны.
Столбец описания также имеет путь больше информации, чем нам нужно. Командующий байта объясняет одну причину grep
луг для JPEG
в каждой целой строке возвраты неправильно заканчивается: файл не-JPEG с JPEG
на его имя дает положительную ложь. (Точка проверки типа - то, что Вы не можете полагаться на имя, таким образом, это - вполне пагубная ошибка в сценарии, Вы показали.), Но даже когда Вы знаете, что смотрите в столбце описания, он может все еще содержать JPEG
даже если это не тип:
$ touch empty.JPEG # not a JPEG
$ gzip -k empty.JPEG
$ file empty.JPEG*
empty.JPEG: empty
empty.JPEG.gz: gzip compressed data, was "empty.JPEG", last modified: Mon Aug 28 16:37:56 2017, from Unix
Ответ Командующего байта решил это (a), передающим -b
опция к file
, то, чтобы заставлять это опустить пути, :
разделитель и пробелы перед типом, затем (b) использование grep
проверять, начинается ли описание JPEG
( ^
привязка в шаблоне ^JPEG image data,
делает это). Это работает, если Вы отслеживаете пути, переданные file
- не проблема для метода Командующего Байта, который работал file
отдельно для каждого пути так или иначе.
Я должен использовать другое решение, потому что моя цель состоит в том, чтобы проанализировать и пути и типы от file
вывод так, чтобы file
не должен быть выполнен отдельно для каждого файла. К счастью, file
в Ubuntu имеет много опций. Я использую file --mime-type -r0F '' paths
:
--mime-type
печатает тип MIME, а не подробное описание. Это - все, в чем я нуждаюсь, и затем я могу просто выполнить точное совпадение против всего этого. Для JPEG, file --mime-type
шоу image/jpeg
в столбце описания. (См. также ответ AFSHIN.)man file
, -r
заставляет непечатные символы не быть замененными восьмеричными Escape как \003
. Я полагаю, что должен был бы иначе добавить шаг для преобразования таких последовательностей назад в фактические символы, которые, вероятно, не могут быть сделаны надежно - что, если такая последовательность появляется буквально в имени файла? (file
не выходит \
как \\
.) Я говорю, что "Верю", поскольку мне не удалось добраться file
для распечатывания такой escape-последовательности, и я не уверен, что она действительно делает так в столбце имени файла. Так или иначе, -r
безопасно здесь.-0
ключевая опция здесь. Без него этот метод не мог работать надежно. Это делает file
распечатайте нулевой символ - один символ, который никогда не позволяется в путях, потому что он обычно используется для маркировки концов строк в программах C - сразу после имени файла. Это отмечает повреждение, в каждой строке, между двумя столбцами таблицы.-F ''
делает file
ничего не распечатайте (''
пустой аргумент) вместо :
. Двоеточие ненадежно (это может появиться в именах файлов), и никакого преимущества здесь, так как нулевой символ уже печатается для указания на конец столбца пути и запуск столбца описания.Сделать find
выполненный file --mime-type -r0F '' paths
Я использую -exec file --mime-type -r0F '' {} +
. find
-exec
замены действия {} +
с путями.
Я составил таблицу этот путь:
find . -exec file --mime-type -r0F '' {} +
Как детализировано выше, это помещает нулевой символ после каждого пути. Было бы удобно, если бы описание было также завершено пустым указателем, но file
не сделает этого - описание всегда заканчивается новой строкой. Таким образом, я должен поочередно читать до нулевого символа, затем предположить, что существует больше текста, и считайте его до новой строки. Я должен сделать это для каждого файла и остановки, когда ничто не оставляют.
Та комбинация - текст чтения, который может содержать новую строку до нулевого символа, затем прочитал текст, который не может содержать новую строку, пока новая строка - не то, как любая из общих утилит Unix обычно используется. Подход, который я проявлю, должен передать вывод по каналу find
к циклу. Каждое повторение цикла читает одну строку таблицы при помощи read
оболочка, встроенная дважды, с различными вариантами.
Для чтения пути я использую:
read -rd ''
-r
read
только стандартная опция и Вы должны почти всегда использовать его. Без него обратная косая черта выходит как \n
от входа переводятся в символы, которые они представляют. Мы не хотим это.read
чтения, пока это не видит новой строки. Для игнорирования новых строк и остановки в нулевом символе вместо этого, я использую -d
возможность, которую Bash предоставляет, для определения другого символа. Для нулевого символа передайте пустой аргумент ''
.-d
опция), таким образом, я могу также пользоваться поведением Bash по умолчанию, когда никакое имя переменной не передается read
. Это помещает все, что это считало - кроме оконечного знака - в специальной переменной $REPLY
. Обычно read
пробел полос ($IFS
символы) с начала и конца входа, и это - общая идиома для записи IFS= read ...
предотвратить это. При чтении неявно в $REPLY
в Bash это не необходимо.Для чтения описания я использую:
read -r mimetype
-r
кому: read
если Вы не хотите \
Escape переводятся.mimetype
.IFS=
препятствовать тому, чтобы ведущий и запаздывающий пробел был разделен, является значительным. Я хочу удаленный. Это отбрасывает пробелы с начала описания это find
записи для создания таблицы более человекочитаемой, когда это показывают в терминале.Цикл должен продолжиться, пока существует другой путь, который будет считан. read
команда возвращает true (в оболочке, программируя это, нуль, в отличие от почти всех других языков программирования), когда это успешно читает что-то и ложь (в программировании оболочки, любом ненулевом значении), когда это не делает. Так общее while read
идиома полезна здесь. Я передаю по каналу (|
) вывод find
- который является выводом одного или (редко) больше file
команды - к while
цикл.
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
# Commands using "$REPLY" and "$mimetype" go here.
done
В цикле я считал остальную часть строки для получения описания (read -r mimetype
). Я не потрудился проверять, успешно выполнилось ли это. file
должен только когда-либо производить полные строки, даже если это встречается с ошибками. (file
отправляет сообщения об ошибках и предупреждающие сообщения к стандартной погрешности, таким образом, они, будет казаться, в конвейере не повредят таблицу.) Необходимо смочь полагаться на это.
Если Вы хотите проверить если read -r mimetype
следовавший так или иначе, можно использовать if
. Или можно включать его в while
условие цикла:
find . -exec file --mime-type -r0F '' {} + |
while read -rd '' && read -r mimetype; do
# Commands using "$REPLY" and "$mimetype" go here.
done
Вы видите, что я также разделяю верхнюю строку для удобочитаемости. (Нет \
требуется разделить в |
.)
Если Вы хотите протестировать цикл перед продолжением, можно поместить эту команду под (или вместо) # Commands...
комментарий:
printf '[%s] [%s]\n\n' "$REPLY" "$mimetype"
Вывод цикла выглядит примерно так, в зависимости от того, что Вы имеете в каталоге (и я не учел большинство записей для краткости):
[.] [inode/directory]
[./stuv] [inode/x-empty]
[./ghi
jkl] [inode/x-empty]
[./fo.o/abc
def ] [image/jpeg]
[./fo.o/wyz.lep] [application/octet-stream]
[./fo.o/wyz] [image/jpeg]
Это должно только видеть, работает ли цикл правильно. Размещение записей таблицы в [
]
как это не помог бы сценарию сделать то, что он должен сделать, поскольку пути могут содержать [
, ]
, и последовательные новые строки.
В каждом повторении цикла, "$REPLY"
содержит путь и "$mimetype"
содержит описание типа. Узнать если "$REPLY"
называет файл JPEG, проверьте если "$mimetype"
точно image/jpeg
.
Можно сравнить строковое использование if
и [
/test
(или [[
) с =
. Но я предпочитаю case
:
find -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
# Put commands here that use "$REPLY".
;;
esac
done
Если Вы просто хотели показать пути JPEG в том же формате как выше - чтобы помочь протестировать с путями, содержащими новые строки - все case
...esac
оператор мог быть:
case "$mimetype" in image/jpeg) printf '[%s]\n\n' "$REPLY";; esac
Но цель состоит в том, чтобы работать lepton
на каждом файле JPEG. Чтобы сделать это, используйте:
case "$mimetype" in image/jpeg) lepton "$REPLY";; esac
Добавление этого lepton
команда и hashbang строка для выполнения его с Bash, вот являются полным сценарием:
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg) lepton "$REPLY";; esac
done
lepton
отчеты, что это делает, но это не показывает имена файлов. Этот альтернативный сценарий печатает сообщение с каждым путем перед выполнением lepton
на нем:
#!/bin/bash
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
printf '\nProcessing "%s":\n' "$REPLY" >&2
lepton "$REPLY"
esac
done
Я распечатал сообщения к стандартной погрешности (>&2
), так как это то, где lepton
отправляет его собственные сообщения. Тем путем, вывод, все остается вместе при передаче по каналу или перенаправлении. Запущение того скрипта производит вывод как это (но больше из него, если у Вас есть больше чем два JPEGs):
Processing "./art.jpg":
lepton v1.0-1.2.1-104-g209463a
6777856 bytes needed to decompress this file
56363 86007
65.53%
2635854 bytes needed to decompress this file
56363 86007
65.53%
Processing "./fo.o/abc
def ":
lepton v1.0-1.2.1-104-g209463a
6643508 bytes needed to decompress this file
36332 46875
77.51%
2456117 bytes needed to decompress this file
36332 46875
77.51%
Повторение в каждой строке файла конфигурации - который также появляется, когда Вы работаете lepton
не печатая имена файлов - то, потому что lepton
проверки, которые его выходные файлы могут распаковать правильно.
Сценарий, который Вы показали, имел exit 0
в конце. Можно сделать это, если Вам нравится. Это заставляет сценарий всегда сообщать об успехе. Иначе сценарий возвращает статус выхода последней выполненной команды - который, вероятно, предпочтителен. Так или иначе это может сообщить об успехе даже если find
, file
, или lepton
возникшие проблемы, если последнее lepton
за командой следуют. Можно, конечно, развернуть сценарий с более сложным кодом обработки ошибок.
Если Вы хотите генерировать список путей, отдельных от lepton
собственный вывод, можно использовать в своих интересах lepton
поведение записи в стандартную погрешность путем печати путей к стандартному выводу вместо этого. В этом случае Вы, вероятно, хотите распечатать просто пути и не сообщение "Обработки". Можно дополнительно хотеть завершить пути с нулевыми символами вместо новых строк, поскольку затем можно обработать список, не повреждаясь на путях, которые содержат новые строки.
#!/bin/bash
case "$1" in
-0) format='%s\0';;
*) format='%s\n';;
esac
find . -exec file --mime-type -r0F '' {} + | while read -rd ''; do
read -r mimetype
case "$mimetype" in image/jpeg)
printf "$format" "$REPLY"
lepton "$REPLY"
esac
done
Когда Вы запускаете тот скрипт, можно передать -0
флаг, чтобы заставить его испустить нулевые символы вместо новых строк. Тот сценарий не делает надлежащей обработки Параметра стиля Unix: это только проверяет первый аргумент, который Вы передаете; передача флага неоднократно в том же аргументе (-00
) не работает; и никакие связанные с опцией сообщения об ошибках никогда не сгенерированы. Это ограничение для краткости, и потому что Вам, вероятно, не нужно ничто более сложное, поскольку сценарий не поддерживает аргументов неопции и -0
единственный возможный вариант.
В моей системе я назвал тот сценарий jpeg-lep3
и вставленный в него ~/source
, затем работал ~/source/jpeg-lep3 -0 > out
, который распечатал просто lepton
вывод к моему терминалу. Если Вы делаете что-то как этот, можно протестировать это, нулевые символы были правильно записаны между использованием путей:
xargs -0 printf '[%s]\n\n' < out
Вы имеете find
и сверьтесь file
команда для ее типа пантомимы также.
find . -type f -exec file --mime-type -b '{}' +
Или заставить его завершиться так же как следуйте:
find . -type f -exec sh -c '
file --mime-type -b "$0" | grep -q "aPATTERN" && printf "$0\n"
' {} \;
Или identify
опция от пакетов ImageMagic.
find -type f -print0 | xargs -0 identify