Как дополнение к другим хорошим ответам, Вы можете настройки крона проверки работоспособности с тестовыми страницами онлайн:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq
Вышеупомянутое находит все файлы ниже текущего каталога (.
) это - регулярные файлы (-type f
) и имейте f
где-нибудь на их имя (-name '*f*'
).Далее, sed
удаляет имя файла, оставляя просто имя каталога. Затем список каталогов отсортирован (sort
) и удаленные дубликаты (uniq
).
sed
команда состоит из единственной замены. Это ищет соответствия к регулярному выражению /[^/]+$
и замены что-либо соответствующее этому ничему. Знак доллара означает конец строки. [^/]+'
средства один или несколько символов, которые не являются наклонными чертами. Таким образом, /[^/]+$
средства все символы от заключительной наклонной черты в конец строки. Другими словами, это соответствует имени файла в конце полного пути. Таким образом команда sed удаляет имя файла, оставляя название без изменений каталога, в котором был файл.
Многие современные sort
команды поддерживают a -u
флаг, который делает uniq
ненужный. Для GNU sed:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort -u
И, для MacOS sed:
find . -type f -name '*f*' | sed -E 's|/[^/]+$||' |sort -u
Кроме того, если Ваш find
управляйте поддерживает его, возможно иметь find
распечатайте имена каталогов непосредственно. Это избегает потребности в sed
:
find . -type f -name '*f*' -printf '%h\n' | sort -u
Вышеупомянутые версии будут перепутаны именами файлов, которые включают новые строки. Больше надежного решения состоит в том, чтобы сделать сортировку на NUL-завершенных строках:
find . -type f -name '*f*' -printf '%h\0' | sort -zu | sed -z 's/$/\n/'
Существует по существу 2 метода, которые можно использовать, чтобы сделать это. Каждый проанализирует строку, в то время как другой будет воздействовать на каждый файл. Парсинг строки использует инструмент такой как grep
, sed
, или awk
очевидно, будет быстрее, но здесь пример, показывающий обоим, а также как можно "представить" эти 2 метода.
Для примеров ниже мы будем использовать следующие данные
$ touch dir{1..3}/dir{100..112}/file{1..5}
$ touch dir{1..3}/dir{100..112}/nile{1..5}
$ touch dir{1..3}/dir{100..112}/knife{1..5}
Удалите часть из *f*
файлы от dir1/*
:
$ rm dir1/dir10{0..2}/*f*
Здесь мы собираемся использовать следующие инструменты, find
, grep
, и sort
.
$ find . -type f -name '*f*' | grep -o "\(.*\)/" | sort -u | head -5
./dir1/dir103/
./dir1/dir104/
./dir1/dir105/
./dir1/dir106/
./dir1/dir107/
Тот же набор инструментальных средств как прежде, кроме этого времени мы будем использовать dirname
вместо grep
.
$ find . -type f -name '*f*' -exec dirname {} \; | sort -u | head -5
./dir1/dir103
./dir1/dir104
./dir1/dir105
./dir1/dir106
./dir1/dir107
Примечание: Вышеупомянутые примеры используют head -5
для простого ограничения суммы вывода, мы имеем дело с для этих примеров. Они обычно удалялись бы для получения полного списка!
Мы можем использовать time
смотреть на 2 подхода.
dirname
real 0m0.372s
user 0m0.028s
sys 0m0.106s
grep
real 0m0.012s
user 0m0.009s
sys 0m0.007s
Таким образом, всегда лучше иметь дело со строками, если это возможно.
grep и PCRE
$ find . -type f -name '*f*' | grep -oP '^.*(?=/)' | sort -u
sed
$ find . -type f -name '*f*' | sed 's#/[^/]*$##' | sort -u
awk
$ find . -type f -name '*f*' | awk -F'/[^/]*$' '{print $1}' | sort -u
Почему бы не попробовать это:
find / -name '*f*' -printf "%h\n" | sort -u
Этот ответ беззастенчиво основан на ответе шлма. Это был интересный подход, но он имеет ограничение, если имена файлов и/или каталогов имеют специальные символы (пробел, полуколонок...). Хорошей привычкой является использование find /somewhere -print0 | xargs -0 someprogam
.
Для приведенных ниже примеров воспользуемся следующими данными
mkdir -p dir{1..3}/dir\ {100..112}
touch dir{1..3}/dir\ {100..112}/nile{1..5}
touch dir{1..3}/dir\ {100..112}/file{1..5}
touch dir{1..3}/dir\ {100..112}/kni\ fe{1..5}
Удалить некоторые из файлов *f*
из dir1/*/
:
rm dir1/dir\ 10{0..2}/*f*
$ find -type f -name '*f*' -print0 | sed -e 's#/[^/]*\x00#\x00#g' | sort -zu | xargs -0 -n1 echo | head -n5
./dir1/dir 103
./dir1/dir 104
./dir1/dir 105
./dir1/dir 106
./dir1/dir 107
ПРИМЕЧАНИЕ: Вышеприведенные примеры используют head -5
, чтобы просто ограничить объем вывода, с которым мы имеем дело в этих примерах. Обычно они удаляются, чтобы получить полный список! также, замените echo
, которую вы хотите использовать.
Вот один, который я считаю полезным:
find . -type f -name "*somefile*" | xargs dirname | sort | uniq
Сzsh
:
typeset -aU dirs # array with unique values
dirs=(**/*f*(D:h))
printf '%s\n' $dirs
Вы можете использовать переключатель -exec
для запуска dirname и получения имени каталога вместо имени файла. Это имеет дополнительное преимущество совместимости с POSIX.
find. -name "*file*" -exec dirname {} \;
Я нашел этот вариант, который не использует sort
или unique
полезным
find. -type d -print0 | xargs -0 -I{} find {} -maxdepth 1 -iname '*.log' -print -quit
Преимущество в том, что вам не нужно ждать, пока будет пройдено все дерево перед сортировкой.
Найти все каталогиfind. -type d -print0
Для каждого каталога | xargs -0 -I{}
найдите файл в текущем каталоге -maxdepth 1
, соответствующий шаблону-iname '*.log'
(без учета регистра ).Если найдено, напечатайте имя файла -print
и прекратите перемещение по этому каталогу quit
В качестве альтернативы
find. -type d -print0 | xargs -0 -I// find // -maxdepth 1 -iname '*.log' -exec dirname {} \; -quit
который просто печатает имя родительского каталога, вдохновленный ответом Snowbuilders .
uniq
в соединение помогает много путем удаления повторных строк, которые уже являются друг прямо рядом с другом.find . -type f -name '*f*' -printf '%h\0' | uniq -z | sort -zu | tr '\0' '\n'
. Или если Ваши инструменты являются немного более старыми, то uniq не может иметь-z опции.find . -type f -name '*f*' -printf '%h\n' | uniq | sort -u
– jbo5112 30.06.2017, 21:06-E
для MacOS. – John1024 01.04.2018, 08:17