Подход @ meuh неэффективен, так как он -maxdepth 1
все еще позволяет find
читать содержимое каталогов на уровне 1, чтобы впоследствии игнорировать их в противном случае. Он также не будет работать должным образом с некоторыми find
реализациями (включая GNU find
), если некоторые имена каталогов содержат последовательности байтов, которые не образуют допустимые символы в локали пользователя (например, для имен файлов в другой кодировке символов).
find . \( -name . -o -prune \) -extra-conditions-and-actions
это более канонический способ реализации GNU -maxdepth 1
(или FreeBSD -depth -2
).
Однако, как правило, -depth 1
вы хотите ( -mindepth 1 -maxdepth 1
), поскольку вы не хотите учитывать .
(глубина 0), и тогда это еще проще:
find . ! -name . -prune -extra-conditions-and-actions
Ибо -maxdepth 2
это становится:
find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
И вот где вы бежите в недопустимых проблемах характера.
Например, если у вас есть каталог с именем, Stéphane
но é
он закодирован в кодировке iso8859-1 (он же latin1) (0xe9 байт), как это было наиболее распространенным в Западной Европе и Америке до середины 2000-х годов, то этот байт 0xe9 не является допустимый символ в UTF-8. Таким образом, в локалях UTF-8 *
подстановочный знак (с некоторыми find
реализациями) не будет совпадать, так Stéphane
как *
равен 0 или более символов, а 0xe9 не является символом.
$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
Мой find
(когда вывод идет на терминал) отображает этот недопустимый байт 0xe9, как ?
указано выше. Вы можете видеть, что St<0xe9>phane/Chazelas
не было prune
d.
Вы можете обойти это, выполнив:
LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
Но обратите внимание, что это влияет на все настройки локали find
и любого приложения, которое он запускает (например, с помощью -exec
предикатов).
$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith
Теперь я действительно понимаю, -maxdepth 2
но обратите внимание на то, ??
как символ é во втором Стефане, правильно закодированный в UTF-8, отображается как байты 0xc3 0xa9 (рассматриваемые как два отдельных неопределенных символа в локали C) в кодировке é UTF-8. непечатаемые символы в локали C.
И если бы я добавил a -name '????????'
, я бы получил неправильный Стефан (тот, который закодирован в iso8859-1).
Чтобы применить к произвольным путям вместо .
, вы должны сделать:
find some/dir/. ! -name . -prune ...
для -mindepth 1 -maxdepth 1
или:
find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...
для -maxdepth 2
.
Я бы все равно сделал:
(cd -P -- "$dir" && find . ...)
Во-первых, потому что это делает пути короче, что снижает вероятность появления слишком длинных путей или слишком длинных списков аргументов, но также помогает обойти тот факт, что find
не может поддерживать произвольные аргументы пути (кроме как -f
с FreeBSD find
), так как он будет подавлен значения $dir
как !
или -print
...
-o
В сочетании с отрицанием является обычным трюком для запуска двух независимых наборов -condition
/ -action
в find
.
Если вы хотите запускать -action1
на собрании файлов -condition1
и независимо -action2
на собрании файлов -condition2
, вы не можете сделать:
find . -condition1 -action1 -condition2 -action2
Как -action2
будет запускаться только для файлов, которые удовлетворяют обоим условиям.
Также:
find . -contition1 -action1 -o -condition2 -action2
Как -action2
не будет работать для файлов, которые отвечают обоим условиям.
find . \( ! -condition1 -o -action1 \) -condition2 -action2
работает так же, как \( ! -condition1 -o -action1 \)
и для истины для каждого файла. Это предполагает -action1
, что действие (например -prune
, -exec ... {} +
) всегда возвращает true . Для таких действий -exec ... \;
может возвращаться значение false , вы можете добавить другое, -o -something
где -something
это безопасно, но возвращает true, как -true
в GNU find
или -links +0
или -name '*'
(хотя обратите внимание на проблему с недопустимыми символами выше).
-depth -2
,-depth 1
... можно рассматривать как лучший, чем подход GNU-maxdepth
/-mindepth