Підхід @ 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 (він же латин1) (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.
І якби я додав -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 \)
вирішив би значення true для кожного файлу. Це передбачає -action1
, що це дія (як -prune
, наприклад -exec ... {} +
), яка завжди повертає істину . Для таких дій, -exec ... \;
які можуть повернутись помилково , ви можете додати ще одне, -o -something
де -something
це нешкідливо, але повертає істину, як -true
у GNU find
або -links +0
або -name '*'
(хоча зверніть увагу на проблему щодо недійсних символів вище).
-depth -2
,-depth 1
... підхід можна вважати кращим, ніж GNU-maxdepth
/-mindepth