Запустите команду для отдельного файла, когда измените его с помощью некоторой магии оболочки (например, замените расширение)

546
Hotschke

Я пишу несколько файлов .gv ( graphviz ) в одном каталоге и хочу создать файл png neatoсразу после сохранения одного из них. Я нахожусь на MacOS 10.12.6 с zshмоей оболочкой по умолчанию, и я установил entrс http://entrproject.org/ для мониторинга изменений файлов. Я безуспешно пытался выполнить следующую команду

$ echo $0 -zsh $ ls *.gv | entr 'F="/_";neato -Tpng "$F" -o"$"' entr: exec F="/_";neato -Tpng "$F" -o"$": No such file or directory 

Следующие работы

  1. Простая печать последнего измененного файла

    $ ls *.gv | entr echo /_ # Press <Space> to manually trigger event to see last changed file /Users/hotschke/complete.gv 
  2. Используя одно и то же имя вывода для всех файлов:

    $ ls *.gv | entr neato -Tpng /_ -oConstantname.png 
  3. Заменить .gv на .png

    $ F="/Users/hotschke/complete.gv";neato -Tpng "$F" -o"$" 

Обратите внимание на специальный аргумент /_оentr

Специальный /_аргумент (в некоторой степени аналогичный $_Perl) обеспечивает быстрый способ обращения к первому измененному файлу. Если указан один файл, это удобный способ избежать повторного ввода пути:

Было бы здорово получить несколько ответов с использованием разных инструментов (например, watchman, watchdog, fswatch, entr, launchd (только для Mac); см. Также обсуждение https://stackoverflow.com/q/1515730/ )

1
Почему бы не использовать `inotifywait -m`, который выводит затронутые узлы, вместо` entr`, который, по-видимому, использует список узлов для мониторинга. Затем вы можете использовать `sed` (или аналогичный) для создания команды для запуска. Attie 6 лет назад 0
Я не против использовать inotifywait. Однако, насколько я могу судить, его нет в macOS. Hotschke 6 лет назад 0
Я бы предпочел кросс-платформенное решение, но использование только встроенных утилит так же хорошо, как это. Hotschke 6 лет назад 0
Да, вы использовали тег `inotify` ... Attie 6 лет назад 0
Attie: Извините за вводящий в заблуждение тег! Я не нашел хорошего. Hotschke 6 лет назад 0
Вы видели [fswatch] (https://github.com/emcrisostomo/fswatch)? Attie 6 лет назад 0
@bertieb: Это последний шаг при объединении команд 2. и 3.: замена постоянного имени выходного файла на имя, полученное из `/ _`, путем замены расширения` gv` на `png`. Я думаю, что это, возможно, проблема выхода из оболочки. Моя изначально упомянутая команда работает на вас? Я был бы удивлен. Hotschke 6 лет назад 0
@bertieb: Я также добавил сообщение об ошибке в вопрос. Hotschke 6 лет назад 0
@Hotschke Похоже, мы оба добрались до репозитория Bitbucket. Вы хотели бы добавить объяснение Eic в качестве ответа? Я счастлив замкнуть петлю, но решил, что вы должны получить первую трещину :) bertieb 6 лет назад 0

4 ответа на вопрос

2
bertieb

Вызовите скрипт с entr

tl; dr : передать /_в качестве аргумента сценарию Do The Thing ™

Вместо того, чтобы пытаться использовать специальные аргументы и переменные, перейдите /_к простому сценарию (который сам по себе может быть однострочным) для генерации png:

$ ls *.gv | entr ./update.sh /_ 

с update.shвдоль линий:

neato -Tpng "$1" -o"$" 

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

Как примечание, я склонен использовать сценарий обновления в entrлюбом случае, так как он делает вещи более ясными для меня. Например, я использую entrдля просмотра исходных файлов LaTeX и создания обновленного PDF, в этом случае запускается скрипт обновления xelatex, biberа также обновляется программа просмотра PDF ( pkill -HUP mupdf).

Спасибо! Однако в этом случае я бы предпочел избегать создания сценария. Если бы я создал файл поддержки для сборки, я бы написал Makefile и использовал предложенный рабочий процесс `$ ls * .gv | сделай Makefile будет работать без entr или подобного, и текстовые редакторы часто поддерживают вызов make-файла (например, vim). Я использую vim и могу активировать автокоманду для сохранения `: au BufWritePostmake`. Если я хочу, чтобы make запускался в фоновом режиме, я могу использовать vim-dispatch, asyncrun.vim, neomake, vim-accio или один из множества других плагинов. Hotschke 6 лет назад 0
Кстати, вы знаете [latexmk] (https://ctan.org/pkg/latexmk)? Это часть TexLive. Он предлагает параметр `$ latexmk -pvc`, который делает избыточным` entr` и очень умный в отношении вызова программ xelatex, biber и других так же часто, как это необходимо, а также обновляет средство просмотра. Hotschke 6 лет назад 0
@Hotschke справедливое замечание о make-файлах (и хороший ответ); Я не являюсь опытным программистом, поэтому мне нужно больше изучить их синтаксис - в списке TODO - затем написать вкладку «от одного до трех» в зависимости от контекста; хотя я признаю, что это немного неуместно - не использовать правильный инструмент для работы. bertieb 6 лет назад 0
IMHO Синтаксис Makefile не очень интуитивно понятен. Мне понадобилось некоторое время, чтобы выучить его, и мне все еще приходится искать значение `$ <`, `$ +` и тому подобное. Я не использую его достаточно часто, а также предпочитаю latexmk для латекса и cmake для c / c ++. Hotschke 6 лет назад 0
1
Hotschke

Использование fswatchвместоentr

Спасибо @Attie за указание fswatch. Следующие работы для меня:

 $ fswatch -e ".*" -i "$PWD/[^.]*\\.gv$" -0 $PWD | xargs -0 -n 1 -I {} sh -c 'F={}; neato -Tpng "$F" -o"$"' 

По умолчанию fswatch рассматривает все файлы: вам нужно использовать фильтры для ограничения определенного типа файлов (см. https://stackoverflow.com/q/34713278/ ).

https://emcrisostomo.github.io/fswatch/ Энрико М. Кризостомо (2013-2017)

1
Hotschke

Использование Makefile

SOURCES:=$(shell find . -maxdepth 1 -name '*.gv')  ifndef OTYPE OTYPE:=png endif # use `make OTYPE=pdf` to generate pdfs  TARGETS:=$(SOURCES:.gv=.$(OTYPE))  .PHONY: all clean  all: $(TARGETS)  clean: rm $(TARGETS)  %.$(OTYPE) : %.gv neato -T$(OTYPE) $< -o$(basename $<).$(OTYPE) 

Теперь вы можете использовать

$ ls *.gv | entr make 

Есть место для улучшения: есть две команды для вывода списка файлов с расширением .gv, что противоречит единственному источнику правды (SSOT).

Vim Notes

Вы также можете использовать Makefile внутри текстового редактора vim

:mak[e] 

Вы можете автоматически вызвать make при сохранении, установив автокоманду с

:au BufWritePost <buffer> make 

Вы можете использовать плагин для запуска make async: посмотрите плагины vim-dispatch (отображение в нормальном режиме m<CR>), neomake или asyncrun.vim .

Однако уже есть определения компилятора для команд dot и neato:

Это означает, что вам не нужно писать Makefile. Вы можете установить makeprg с помощью :comp[iler] neatoили :comp dot. Обратите внимание, что вы видите все определения компилятора :comp <C-d>и можете завершить табуляцию :comp n<Tab>до :comp neatoи :comp d<tab>до :comp dot.

Теперь вам нужно вызвать make с аргументом, чтобы указать формат вывода:

:make png :au BufWritePost <buffer> make png 

Если вы используете vim-dispatch, это выглядит так

:Make png m<Space>png<CR> :au BufWritePost <buffer> Make png 
0
Hotschke

Entr- передать /_в качестве аргумента оболочку

ls *.gv | entr bash -c 'neato -Tpng "$0" -o"$"' /_ 

Этот ответ от https://bitbucket.org/eradman/entr/issues/75/run-command-on-single-file-when-changed#comment-44183153 .

Эта команда молча выполняет команду neato. Если вы хотите получить отзыв о командной строке при entrобнаружении изменения файла, добавьте -xв bash, чтобы увидеть выполненную команду:

ls *.gv | entr bash -x -c 'neato -Tpng "$0" -o"$"' /_