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

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

$ echo $0
-zsh
$ ls *.gv | entr 'F="/_";neato -Tpng "$F" -o"${F/%\.gv/.png}"'
entr: exec F="/_";neato -Tpng "$F" -o"${F/%\.gv/.png}": 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"${F/%\.gv/.png}"
    

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

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

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

4 ответа

Решение

Entr - Проходить /_ в качестве аргумента к раковине

ls *.gv | entr bash -c 'neato -Tpng "$0" -o"${0/%\.gv/.png}"' /_

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

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

ls *.gv | entr bash -x -c 'neato -Tpng "$0" -o"${0/%\.gv/.png}"' /_

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

TL; Dr: Pass /_ в качестве аргумента для сценария Do The Thing ™

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

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

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

neato -Tpng "$1" -o"${1/%\.gv/.png}"

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

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

Использование 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

С помощью fswatch вместо entr

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

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

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

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

Другие вопросы по тегам