Как найти каталоги, в которых есть определенные файлы, но нет других

Для поиска фиксированной строки (, а не регулярного выражения ), используйте параметр -Fс grep. Если вам дополнительно нужно убедиться, что ваша строка соответствует всей строке , используйте-x:

grep -Fx -r '...your string here...' directory

Чтобы получить приблизительные совпадения (, если поиск по полной строке ничего не возвращает ), я бы начал только сport is up(без -x),или, возможно,

grep -F -r -e 'port is up' -e 'valid output' directory

Ни |, ни {, ни }не являются особыми в шаблоне регулярного выражения, когда вы используете базовое регулярное выражение, как здесь. 'никогда не бывает специальным в регулярном выражении. Однако, поскольку вы ищете по строке (, а не по шаблону ), тем не менее следует использовать -F.

0
26.08.2020, 19:25
5 ответов
for f in "$1"/*/"$2"; do dir=$(dirname -- "$f"); [ -f "$dir/$3" ] || printf '%s\n' "$dir"; done

Сохраните сценарий как search. Первый аргумент — это родительский каталог, второй — включение, а третий — исключение.

sh search "reports_dir" "report.md" "report.pdf"
  • "$1"/*/"$2"получает только путь к файлам report.mdв примере.

  • dir=$(dirname -- "$f")получает путь к каталогу этих файлов (предполагает, что он не заканчивается символами новой строки ).

  • [ -f "$dir/$3" ]проверяет наличие файла в 3-м аргументе в этом каталоге(report.pdf)и что он имеет обычный тип (не каталог, fifo, устройство... ).

  • || printf '%s\n' "$dir"если он не существует (или не является обычным файлом ), выведите имя каталога.

5
18.03.2021, 23:09

Вы можете попробовать это, хотя вывод может быть немного беспорядочным, ls -R | grep report.md | grep -v report.pdfls -R здесь рекурсивно перечисляет каталоги, затем greps report.md и grep -v означают, что все с report.pdf будет проигнорировано.

0
18.03.2021, 23:09

Вы можете использовать короткий лайнер bash one -, чтобы проверить существование PDF-файла(-execтакже является фильтром):

find. -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -print

Если вам нужно только имя каталога, вы также можете поместить его в другой -execпосле того, как первый(findостановится после первого теста):

find. -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -exec dirname {} \;
1
18.03.2021, 23:09

Сzsh:

print -rC1 -- **/report.md(DN^e['[[ -e $REPLY:r.pdf ]]']:h)

Будет лиprintrотображаться в1Cколонке head (имя каталога )файлов report.mdна любом уровне подкаталогов (**/), включая Dили (скрытые )те, для которых eоценка кода [[ -e $REPLY:r.pdf ]]не возвращает(^)true (, где $REPLY:r— это rимя файла $REPLY, содержащего файл для проверки ).

С findреализациями (, такими как GNU find), которые позволяют {}встраиваться в -execаргументы и любую Bourne -подобную оболочку (, включая bash), вы можете сделать:

find. -type d -exec test -e '{}/report.md' \; \
             ! -exec test -e '{}/report.pdf' \; -print

Хотя это означает выполнение до 2 testкоманд на каталог.

С boshи его встроенным findэтого можно избежать с помощью:

find. -type d -call '
  [ -e "$1/report.md" ] && [ ! -e "$1/report.pdf" ]' {} \; -print

Где на этот раз -callоболочка интерпретирует этот код напрямую и вызывает встроенную [.

POSIXly:

find. -type d -exec sh -c '
  for d do
    [ ! -e "$d/report.md" ] || [ -e "$d/report.pdf" ] || printf "%s\n" "$d"
  done' sh {} +

С теми shреализациями, в которых [и printfвстроены в (больше всего, в наши дни )они должны быть относительно эффективными, поскольку shкак можно меньше shвызываются findдля обработать список найденных каталогов.

3
18.03.2021, 23:09

Может быть, это сработает?

comm -23 <(find -name "report.md" -printf '%h\n' | sort) <(find -name "report.pdf" -printf '%h\n' | sort)
0
18.03.2021, 23:09

Теги

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