Executar o comando em um único arquivo quando alterado com alguma mágica de shell (por exemplo, substituir extensão)

1

Estou escrevendo vários arquivos .gv ( graphviz ) no mesmo diretório e deseja criar um arquivo png com neato imediatamente quando eu tiver salvo um deles. Eu estou no macOS 10.12.6, com zsh como meu shell padrão, e instalei entr do link para monitorar as alterações nos arquivos. Eu tentei seguir o comando sem qualquer sorte

$ 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

Seguindo os trabalhos

  1. Impressão simples do último arquivo modificado

    $ ls *.gv | entr echo /_
    # Press <Space> to manually trigger event to see last changed file
    /Users/hotschke/complete.gv
    
  2. Usando o mesmo nome de saída para todos os arquivos:

    $ ls *.gv | entr neato -Tpng /_ -oConstantname.png
    
  3. Substitua .gv por .png

    $ F="/Users/hotschke/complete.gv";neato -Tpng "$F" -o"${F/%\.gv/.png}"
    

Observe o argumento especial /_ de entr

The special /_ argument (somewhat analogous to $_ in Perl) provides a quick way to refer to the first file that changed. When a single file is listed this is a handy way to avoid typing a pathname twice:

Seria ótimo ter várias respostas usando diferentes ferramentas (por exemplo, vigia, watchdog, fswatch, entr, launchd (somente para mac); consulte também a discussão link )

    
por Hotschke 24.03.2018 / 12:28

4 respostas

0

Entr - Passar /_ como argumento para um shell

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

Esta resposta é de link .

Este comando executa silenciosamente o comando neato . Se você quiser ter feedback sobre a linha de comando quando entr detectar uma alteração de arquivo, adicione -x ao bash para ver o comando executado:

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

Chame um script com entr

tl; dr : passa /_ como argumento para um script para Do The Thing ™

Em vez de tentar usar argumentos e variáveis especiais, passe /_ para um script simples (que pode ser um liner) para fazer sua geração png:

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

com update.sh ao longo das linhas de:

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

Eu testei a abordagem acima com um script simples para usar o imagemagick em convert uma imagem, que funcionava sem aspas, mas é melhor deixá-las no caso de espaços, etc. em nomes de arquivos.

Como uma nota lateral, eu costumo usar um script de atualização com entr de qualquer maneira, pois mantém as coisas mais claras em minha mente. Por exemplo, eu uso entr para assistir arquivos fonte do LaTeX e gerar um PDF atualizado, o script de atualização nesse caso executa xelatex , biber e também atualiza o visualizador de PDF ( pkill -HUP mupdf ).

    
por 24.03.2018 / 16:34
1

Usando um 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)

Agora você pode usar

$ ls *.gv | entr make

Há espaço para melhorias: há dois comandos para listar arquivos com a extensão .gv que contradiz uma única fonte de verdade (SSOT).

Notas do Vim

Você também pode usar o Makefile dentro do editor de texto vim

:mak[e]

Você pode ligar automaticamente para salvar, configurando um autocommand com

:au BufWritePost <buffer> make

Você pode considerar usar um plugin para runnning make async: veja os plugins vim-dispatch (mapeamento em modo normal m<CR> ), neomake ou asyncrun .vim .

No entanto, já existem definições de compilador para os comandos dot e neato:

Isso significa que você não precisa escrever um Makefile. Você pode definir o makeprg por :comp[iler] neato ou :comp dot . Observe que você vê todas as definições do compilador por :comp <C-d> e pode concluir a guia :comp n<Tab> to :comp neato e :comp d<tab> to :comp dot .

Agora você precisa chamar o make com um argumento para especificar seu formato de saída:

:make png
:au BufWritePost <buffer> make png

Se você usa o vim-dispatch, isso parece

:Make png
m<Space>png<CR>
:au BufWritePost <buffer> Make png
    
por 24.03.2018 / 18:48
1

Usando fswatch em vez de entr

Obrigado a @Attie por apontar fswatch out. A seguir funciona para mim:

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

O fswatch considera, por padrão, todos os arquivos: você precisa usar filtros para limitar a um determinado tipo de arquivo (consulte link ).

link de Enrico M. Crisostomo (2013-2017)

    
por 24.03.2018 / 15:15