Выполнить команду, где найден файл

Выполнить команду, где найден файл

Как выполнить команду, где найден файл?
Предположим, у меня есть каталог с именем testdir, который содержит следующее:

$ ls -R testdir/
testdir/:
dir1  dir2  dir3  dir4  dir5

testdir/dir1:
doc1.pdf

testdir/dir2:
file1.txt

testdir/dir3:
doc2.pdf

testdir/dir4:
file2.txt

testdir/dir5:
doc5.pdf

Теперь я хочу выполнить действие (выполнить команду), где findнаходит определенный файл/тип файла. Например, позвольте мне найти *.pdf:

$ find . -name '*.pdf'
./testdir/dir3/doc2.pdf
./testdir/dir5/doc5.pdf
./testdir/dir1/doc1.pdf

Теперь предположим, что я хочу выполнить команду (например, скажем touch file), где указанная выше команда находит файл(ы). Другими словами, я хочу создать файл с именем fileв каждом каталоге, где был найден хотя бы один, .pdfтак что я получаю:

$ ls -R testdir/
testdir/:
dir1  dir2  dir3  dir4  dir5

testdir/dir1:
doc1.pdf  file

testdir/dir2:
file1.txt

testdir/dir3:
doc2.pdf  file

testdir/dir4:
file2.txt

testdir/dir5:
doc5.pdf  file

Как мне выполнить такую ​​работу?
Может быть, для каждого найденного файла, cdгде файл существует и рекурсивно выполнить команду.
Я знаю, что это findпотрясающая функция: -execно я не могу заставить ее работать.


Это всего лишь пример для понимания того, что я хочу сделать. В общих чертах: как выполнить команду, в которой файл(ы) найдены (по find) рекурсивно?

решение1

Если вы запустите эту команду, она touch fileбудет запущена (возможно, несколько раз) из каталога, в котором она была запущена:

find -name '*.pdf' -exec touch file \;

С другой стороны, если запустить этот вариант, каждый экземпляр команды будет запущен в каталоге целевого файла:

find -name '*.pdf' -execdir touch file \;

В обоих случаях вы можете увидеть это в действии, заменив touch fileна echo {}and/or pwd.


Из страницы руководства:

-execdir command ;
-execdir command {} +

    Аналогично -exec, но указанная команда запускается из подкаталога, содержащего соответствующий файл, который обычно не является каталогом, в котором вы запустили find.

решение2

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

find . -name "*.pdf" -type f -exec bash myscript {} \;

где файл myscriptсодержит следующее:

dir=$(dirname "$1")
cd "$dir"
touch file

решение3

С zshпомощью квалификаторов glob можно выбрать, например, только .pdfфайлы и черезмодификаторысохраните имена каталогов в массиве суникальныйэлементы и затем cdв каждый из этих каталогов и запустите свою команду. Таким образом вы запустите только свою командуодин разв каждом каталоге, независимо от количества .pdfнайденных в этом каталоге файлов:

dirlist=(**/*.pdf(.:a:h))
for d in ${(u)dirlist[@]}
  (cd $d && touch file)

или

typeset -U dirlist
dirlist=(**/*.pdf(.:a:h))
for d in ${dirlist}
  (cd $d && touch file)

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

dirlist=(**/*.bkp(D.:a:h))

решение4

Не ищите дальше, просто войдите:

https://bitbucket.org/eradman/entr

Что вы можете сделать, так это позволить entr следить за указанным каталогом. Когда find найдет файл, коснитесь файла с именем, скажем, triggerfile.txt в этом каталоге и позвольте entr взять управление на себя.

Связанный контент