
Мне бы хотелось найти find
файлы (со схожими функциями), но следовать и переходить только по определенным символическим ссылкам (путем сопоставления с шаблоном).
Очевидно, find
что сам по себе он не может с этим справиться: нет возможности настроить поведение следования по символическим ссылкам; и наивная find -L
легкодоступная блокировка (или работающая крайне медленно).
решение1
Последнее предложение вопроса предполагает, что проблема заключается не в отслеживании символических ссылок в целом (и, например, в применении -newer
к символической ссылке в одном случае и к цели в другом случае), а в отслеживании символических ссылокв каталогии таким образом спускаетесь туда, куда не хотите.
ЗаСпецификация, find
будет обнаруживать бесконечные циклы, поэтому лайвлок не должен произойти. Ресурсы (включая время), которые тратятся впустую, могут быть проблемой, и я понимаю ваше беспокойство.
Прежде всего, используйте, -L
чтобы разрешить find
следовать символическим ссылкам, по которым вы хотите, чтобы он следовал. Затем вам нужен способ обнаружения других символических ссылок.
In find -L
-type l
никогда не бывает истинным, но вы можете обнаружить символические ссылки с помощью -exec test -L {} \;
(помните -exec … \;
, это тоже тест, он успешен, если внутренняя команда завершается со статусом 0). Таким образом, вы все равно можете применить некоторые тесты специально к символическим ссылкам и -prune
(или нет) соответственно.
Например, следующая команда будет спускать только те символические ссылки, имена которых начинаются foo
или заканчиваются на bar
:
find -L . -exec test -L {} \; ! \( -name 'foo*' -o -name '*bar' \) -prune -o -print
Какое бы выражение вы изначально ни хотели, поместите его после -prune -o
. В приведенной выше команде «исходное» выражение — -print
. Помните, -exec
что подавляет неявное -print
, поэтому, если вам нужно -print
, добавьте его явно (как мы это сделали).
Обратите внимание, что -name
проверяется имя самой симлинки. Если вы хотите проверить имя цели, то вам понадобится realpath
, возможно basename
, и некоторый код оболочки; например:
find -L . -exec test -L {} \; -exec sh -c '
case "$(basename "$(realpath "$1")")" in
baz* ) exit 0 ;;
*qux ) exit 1 ;;
esac
exit 0
' find-sh {} \; -prune -o -print
Приведенная выше команда создаст -prune
любую символическую ссылку на любой файл, имя которого начинается с baz
, но она создаст символические ссылки на каталоги с именами, заканчивающимися на qux
(если они не начинаются с baz
), и, наконец, -prune
все остальные символические ссылки.
Примечания:
realpath
иbasename
не являются переносимыми.realpath
разрешает все символические ссылки.- Поведение в случае неработающей символической ссылки может соответствовать вашим ожиданиям, а может и нет.
- Вызов отдельного
test
для каждого файла повредит производительности, но я не нашел лучшего способа. Вызовsh
,realpath
иbasename
также плох в этом вопросе, но здесь это происходит только для символических ссылок, поэтому в большинстве случаев влияние будет ограниченным. find-sh
объясняется здесь:Какая вторая буква «ш» в словеsh -c 'some shell code' sh
?- В примерах пути, которые получают
-prune
d, не будут-print
ed. Измените последний фрагмент на-prune -false -o -print
, и они будут напечатаны. Смотритеобъяснение-false
; на случай, если вам понадобится, есть портативная альтернатива .