Для поиска фиксированной строки (, а не регулярного выражения ), используйте параметр -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
.
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"
если он не существует (или не является обычным файлом ), выведите имя каталога.
Вы можете попробовать это, хотя вывод может быть немного беспорядочным, ls -R | grep report.md | grep -v report.pdf
ls -R здесь рекурсивно перечисляет каталоги, затем greps report.md и grep -v означают, что все с report.pdf будет проигнорировано.
Вы можете использовать короткий лайнер 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 {} \;
Сzsh
:
print -rC1 -- **/report.md(DN^e['[[ -e $REPLY:r.pdf ]]']:h)
Будет лиprint
r
отображаться в1
C
колонке h
ead (имя каталога )файлов 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
для обработать список найденных каталогов.
Может быть, это сработает?
comm -23 <(find -name "report.md" -printf '%h\n' | sort) <(find -name "report.pdf" -printf '%h\n' | sort)