Подход @ 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не было pruned.
Вы можете обойти это, выполнив:
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