
Рассмотрим следующие файлы:
$ find findtest
findtest
findtest/test1
findtest/test1/start.ksh
findtest/test2
findtest/test2/start.ksh
findtest/test3
findtest/test3/start.ksh
findtest/test4
findtest/test4/start.ksh
Мой вопрос касается использования {}
в -exec
вызове. Он работает так, как я и ожидал, при обозначении файла результата:
$ find findtest -name test[1-4] -exec ls -d {} \;
findtest/test1
findtest/test2
findtest/test3
findtest/test4
Однако, похоже, он не расширяется при использовании в пути:
$ find findtest -name test[1-4] -exec md5sum {}/start.ksh \;
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory
md5sum: {}/start.ksh: No such file or directory
Как я могу использовать find -type d -exec
для доступа к файлам более низкой иерархии? Я знаю, что могу использовать for
такой цикл, но мне интересно узнать, можно ли это сделать за один find
вызов:
$ for f in $(find findtest -name test[1-4]); do md5sum "$f"/start.ksh; done
d41d8cd98f00b204e9800998ecf8427e findtest/test1/start.ksh
d41d8cd98f00b204e9800998ecf8427e findtest/test2/start.ksh
d41d8cd98f00b204e9800998ecf8427e findtest/test3/start.ksh
d41d8cd98f00b204e9800998ecf8427e findtest/test4/start.ksh
решение1
TheСтандарт POSIX для команды findтребует только замены изолированного {} на имя файла, и только первого. Использование {}/start.ksh
приводит к неопределенному поведению.
Аргумент, содержащий только два символа "{}", должен быть заменен набором агрегированных имен путей, при этом каждое имя пути должно передаваться как отдельный аргумент вызываемой утилите в том же порядке, в котором оно было агрегировано. Размер любого набора из двух или более имен путей должен быть ограничен таким образом, чтобы выполнение утилиты не приводило к превышению системного ограничения {ARG_MAX}. Если присутствует более одного аргумента, содержащего только два символа "{}", поведение не определено.
Если строка utility_name или аргумента содержит два символа «{}», а не только два символа «{}», то реализацией определяется, заменяет ли find эти два символа или использует строку без изменений.
Одним из способов сделать то, что вам нужно, с помощью Solaris find, является следующая команда:
find findtest -name "test[1-4]" -exec sh -c 'md5sum $1/start.ksh' foo {} \;
Более быстрый способ:
find findtest -name "test[1-4]" -exec sh -c 'for i; do md5sum "$i/start.ksh"; done' foo {} +
решение2
- На самом деле ваша оболочка расширяется
test[1-4]
до того, как она вызоветfind
. Вам нужно экранировать ее с помощью'…'
{}
рассматривается как шаблон только тогда, когда он является отдельным токеном
-exec
сам по себе обычно дорог и рекомендуется либо использовать его с отстающим +
, либо избегать в пользу кормления xargs
.
Я знаю, что можно использовать такой цикл for, но мне интересно, можно ли это сделать за один вызов find:
find findtest -name 'test[1-4]' -print0 | xargs -0I{} -- md5sum '{}/start.ksh'
— работает md5sum
эффективно — все имена файлов выдаются одновременно.