Найдите команду, если имя файла не существует в каталоге

Я провел небольшое собственное исследование. Основной источник: http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/c23.html

Короче говоря: нет ничего, что запрещало бы пользователю создавать файлы . Однако в стандартном Linux FHS только некоторые каталоги доступны для записи всем. Пока вы используете дистрибутив, который следует этому соглашению, вам следует проверять только следующие каталоги (как показывает тест в моей собственной системе):

  • / dev / shm (установлен по умолчанию в некоторых дистрибутивах)
  • Пользователь домашний каталог
  • / var / tmp
  • / var / run / screen / S-rubenf
  • / tmp
  • / mnt / usb-disk (смонтирован с помощью gid = users)

Источник:

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

3
24.10.2018, 08:22
5 ответов

Вы не можете использовать 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также будет верен для символической ссылки на обычный файл.

Связанные:

9
27.01.2020, 21:08

Это частичный ответ, но было слишком много, чтобы написать комментарий. В этой команде есть несколько ошибок.

Во-первых, ваша логика неверна. Вы, вероятно, хотите -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. Это просто файл в каталоге .

0
27.01.2020, 21:08

С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 , которые обычный после разрешения символических ссылок (исключить каталоги, неработающие ссылки и другие специальные типы файлов ).

2
27.01.2020, 21:08

Учитывая, что я голосую за ясное и элегантное решение Кусалананды, добавлю, что такого рода задачи выглядят как операции над множествами. Чистый 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
3
27.01.2020, 21:08

Я бы использовал следующее:

find -type d -maxdepth 2 -not -name '*readme*' | awk -F "/" '{print $$2}' | uniq
0
27.01.2020, 21:08

Теги

Похожие вопросы