поиск каталогов, содержащих один файл, и отсутствие другого

В настоящее время я знаю, как искать каталоги и перечислять те, которые НЕ содержат определенный файл:

find parent_directory -mindepth 1 -maxdepth 1 -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^file_name$"' \; -print 

но теперь я хочу использовать результирующие каталоги, чтобы проверить, содержат ли они другой файл, но я не могу этого сделать в расширенном однострочном выражении. Возможно ли это как-то?

3 Solutions collect form web for “поиск каталогов, содержащих один файл, и отсутствие другого”

Вы делаете это намного сложнее, чем нужно. Кажется, вы не хотите переписывать в подкаталоги, поэтому вам нужно найти те каталоги, у которых нет определенного файла:

 for dir in */; do [ ! -e "$dir"/"$filename" ] || printf '%s\n' "$dir"; done 

И, чтобы увидеть, у кого из них есть другой файл:

 for dir in */; do [ ! -e "$dir"/"$filename1" ] && [ -e "$dir"/"$filename2" ] && printf '%s\n' "$dir"; done 

Или, в несколько более ясном синтаксисе:

 for dir in */; do if [ ! -e "$dir"/"$filename1" ]; then if [ -e "$dir"/"$filename2" ]; then printf '%s\n' "$dir"; fi fi done 

Все это делается с использованием встроенных инструментов оболочки. В частности:

  • [ : это и сопровождающие ] являются синонимами для встроенного test (см. help [ или help test если используется оболочка sh-style). Это способы написания тестовых операций в оболочке.
  • -e : проверяет, существует ли файл / каталог и т. д. См. help test . Простой формат: [ -e file ] который вернет true, если file существует.
  • [ ! -e filename ] [ ! -e filename ] ! просто инвертирует тест. Итак, [ ! -e file ] [ ! -e file ] будет истинным, если file не существует.

Взятый вместе, это означает, что приведенная выше команда:

 ## Iterate over every directory (dirs only because of the '/' in '*/') ## saving each of them in the variable $dir. for dir in */; do ## If this $dir does not contain $filename1 if [ ! -e "$dir"/"$filename1" ]; then ## If this $dir does contain $filename2 if [ -e "$dir"/"$filename2" ]; then ## Print the directory name printf '%s\n' "$dir"; fi fi done 

Для запуска этого, конечно, вам нужно сначала установить $filename1 и $filename2 соответственно. Например:

 filename1="unwantedFile" filename2="wantedFile" 

Вы также можете определить свои требуемые каталоги:

 find . -maxdepth 2 -path '*/*/wanted.txt' -type f \ -execdir test ! -f unwanted.txt \; -execdir pwd \; 

Как это работает:

  • Мы ищем записи до глубины 2.
  • Опция -path дополнительно ограничивает их глубиной в 2 из-за наличия двух слэшей, так как maxdepth не позволяет идти дальше, а 2 изъятых косая черта препятствует переходу на глубину 2.
  • Запись wanted.txt, найденная на уровне глубины 2 лучше, является обычным файлом, обеспечиваемым -type f
  • Опция -execdir операцию к каталогу, в котором находится файл wanted.txt, и, следовательно, команда test будет искать там ненужный файл.
  • Затем просто печатать каталог (повышенный из-за -execdir ), где нежелательный файл не найден.
  • Без смысла, чтобы заполучить этот момент, каталог может содержать конкретный файл только один раз, поэтому операции -execdir запускаются один раз / каталог и только в тех каталогах, которые, по крайней мере, обязательно содержат необходимые файлы want.txt.

С помощью zsh для отображения каталогов в текущем каталоге, содержащих файл musthave а не файл mustnothave :

 contain() [[ -e $REPLY/$1 || -L $REPLY/$1 ]] printf '%s\n' *(D/e(contain musthave)^e(contain mustnothave)) 

Обратите внимание, что выполнение:

 find ... -exec sh -c 'ls {}' \; 

не только не переносима, но также является уязвимостью в отношении ввода команд. Например, если есть каталог с именем $(reboot) или ;reboot , который запускает строки командной строки ls $(reboot) или ls ;reboot вызывающие перезагрузку. {} никогда не должен быть встроен в аргумент кода ( sh или любой другой язык), где он может быть неверно истолкован. Использование:

 find ... -exec sh -c 'ls "$1"' sh {} \; 

вместо.

  • Сравните существующий файл в двух разных каталогах, скопируйте, если не существует, иначе перезапишите его
  • Почему «find -delete» рекурсивно удаляет все файлы в каталоге
  • Извлекать записи из файла в диапазоне от одной даты к другой
  • Что означает ^ @ ^ @ ^ @ в текстовом файле?
  • поиск файлов с определенным текстом и копирование этих файлов в другой каталог
  • Как узнать, какие программы читают мой файл?
  • Правильное понимание прав для cp
  • сплит 60GB плоский файл с записями, иногда охватывающих несколько строк
  • Кто переименовал каталог?
  • Простой сценарий bash, который слишком долго выполняется
  • выполнить команду из txt-файла
  • Синхронизация файлов в реальном времени
  • Linux и Unix - лучшая ОС в мире.