Я провел небольшое собственное исследование. Основной источник: http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/c23.html
Короче говоря: нет ничего, что запрещало бы пользователю создавать файлы . Однако в стандартном Linux FHS только некоторые каталоги доступны для записи всем. Пока вы используете дистрибутив, который следует этому соглашению, вам следует проверять только следующие каталоги (как показывает тест в моей собственной системе):
Источник:
find -type d |
while read DIR; do
if touch $DIR/test_can_be_removed123 2>/dev/null; then
rm $DIR/test_can_be_removed123
echo $DIR >> writable_directories
fi
done
Вы не можете использовать find
для поиска файлов, которые не существуют. Однако вы можете использовать find
для поиска каталогов, а затем проверить, существуют ли файлы с указанными именами в этих каталогах.
При использовании find
для поиска каталогов убедитесь, что вы используете -type d
. Затем проверьте каждый из найденных каталогов на наличие файлов README
и readme
.
Предполагая следующую иерархию каталогов для некоторого верхнего -каталогаprojects
:
projects/
|-- toola
| |-- doc
| |-- readme
| `-- src
|-- toolb
| |-- doc
| `-- src
|-- toolc
| |-- README
| |-- doc
| `-- src
`-- toold
|-- doc
`-- src
Использование find
для поиска каталогов непосредственно в projects
, которые не содержат файл README
или readme
:
$ find projects -mindepth 1 -maxdepth 1 -type d \
! -exec test -f {}/README ';' \
! -exec test -f {}/readme ';' -print
projects/toolb
projects/toold
Здесь мы находим любой каталог непосредственно в projects
, а затем используем утилиту test
, чтобы определить, какой из найденных каталогов не содержит ни одного из двух файлов.
Это точно эквивалентно
find projects -mindepth 1 -maxdepth 1 -type d \
-exec [ ! -f {}/README ] ';' \
-exec [ ! -f {}/readme ] ';' -print
Другая формулировка вышеизложенного:
find projects -mindepth 1 -maxdepth 1 -type d -exec sh -c '
for pathname do
if [ ! -f "$pathname/README" ] &&
[ ! -f "$pathname/readme" ]; then
printf "%s\n" "$pathname"
fi
done' sh {} +
Здесь мы позволяем небольшому -строковому сценарию оболочки выполнить фактическое тестирование двух файлов и вывести пути к каталогам, которые не содержат ни один из них. Утилита find
действует как "генератор путей" из путей к каталогам для перебора строкового скрипта -.
На самом деле, если структура каталогов такая, мы можем вообще не использовать find
:
for pathname in projects/*/; do
if [ ! -f "$pathname/README" ] &&
[ ! -f "$pathname/readme" ]; then
printf '%s\n' "$pathname"
fi
done
Обратите внимание на косую черту в конце шаблона projects/*/
. Именно поэтому шаблон соответствует только каталогам (или символическим ссылкам на каталоги ).
Разница между этим способом и использованием find
заключается в том, что в приведенном выше цикле оболочки мы исключим скрытые каталоги в project
и включим символические ссылки на каталоги.
Во всех случаях мы перебираем пути к каталогам и проверяем -отсутствие двух имен файлов.
Единственная оговорка заключается в том, что тест -f
также будет верен для символической ссылки на обычный файл.
Связанные:
Это частичный ответ, но было слишком много, чтобы написать комментарий. В этой команде есть несколько ошибок.
Во-первых, ваша логика неверна. Вы, вероятно, хотите -a
вместо -o
. Ваша команда:
find. -maxdepth 2 ! -name '*readme*' -o ! -name '*README*'
найдет файлы, в которых (нет readme
)ИЛИ в (нет README
). Если вы просто запустите свою команду, вы увидите, что она возвращает все файлы в вашем дереве. Следовательно, вы можете использовать
find. -maxdepth 2 ! -name '*readme*' -a ! -name '*README*'
Во-вторых,вам, вероятно, даже не нужна эта конструкция. Если у вас есть чтение man find
, вы можете увидеть, что есть опция с именем -iname
, которая является нечувствительной к регистру -версией -name
. Следовательно, вы можете сделать
find. -maxdepth 2 ! -iname '*readme*'
Наконец, вы можете видеть, что если вы запустите эти команды, они вернут все, что не имеет строки в своем имени. Следовательно, появятся родительские каталоги, включая toola
и toolb
, поскольку в их имени нет строки. Это ожидаемо, потому что, если вы посмотрите на вывод, в строке вообще нет ни readme
, ни README
. Это просто файл в каталоге .
Сzsh
:
set -o extendedglob # for (#i) for case insensitive matching
all_projects=(projects/*(-/))
typeset -aU projects_with_readme # -U for unique
projects_with_readme=(projects/*/(#i)readme(:h))
projects_without_readme=(${all_projects:|projects_with_readme})
echo Projects with READMEs:
printf ' - %s\n' $projects_with_readme
echo Projects without READMEs:
printf ' - %s\n' $projects_without_readme
Вы можете изменить (#i)readme
на (#i)*readme*
для учета файлов с именами README.txt
или 000README
или (:h)
на (-.:h)
, чтобы учитывать только файлы readme , которые обычный после разрешения символических ссылок (исключить каталоги, неработающие ссылки и другие специальные типы файлов ).
Учитывая, что я голосую за ясное и элегантное решение Кусалананды, добавлю, что такого рода задачи выглядят как операции над множествами. Чистый find
инструмент сам по себе не подходит. Действительно, он должен использовать внешние инструменты с помощью -exec
.
Другой подход может заключаться в использовании инструмента сравнения/различия. Например, если у вас есть доступ к GNU find
и оболочке, поддерживающей подстановку процессов (, т.е. bash
), и что у вас нет символов новой строки в ваших путях:
comm -2 -3 <(find./tool* -maxdepth 0 -type d | sort) \
<(find./tool* -iname "readme" -printf "%H\n" | sort)
Где:
comm
сравнивает два отсортированных файла построчно; опции-2
-3
позволяют удалить из вывода результаты, которые есть только во втором файле или в обоих файлах. -printf "%H\n"
позволяет find
печатать только начальную точку, под которой был найден файл, за которой следует новая строка (мы должны соответствовать опции -maxdepth 0
, которая определяет другой список ). Проверено на дереве:
$ find./tool* -printf "%p %y\n" | sort
./toola d
./toola/doc d
./toola/readme f
./toola/src d
./toolb d
./toolb/doc d
./toolb/src d
./toolc d
./toolc/doc d
./toolc/README f
./toolc/src d
./toold d
./toold/doc d
./toold/doc/readme f
./toold/src d
Приведенная выше команда дает:
./toolb
Я бы использовал следующее:
find -type d -maxdepth 2 -not -name '*readme*' | awk -F "/" '{print $$2}' | uniq