Execução Condicional - Lançando Sub-Processos Persistentes e Coroutines

3

A execução condicional é usada no Bash para controlar o fluxo de um script com base no status de saída de um subprocesso. No entanto, há situações em que um subprocesso (aplicativo) é iniciado em segundo plano, para ser usado para fins interativos, para que não haja saída nem status de saída, até que seja fechado.

Considere alguns exemplos, por exemplo, lançando um visualizador de pdf, mupdf . Considere o primeiro caso com um arquivo que existe, example.pdf:

$ mupdf example.pdf &
[1] 16220

Isso funciona, então vamos tentar a execução condicional:

$ mupdf example.pdf & && echo TRUE
bash: syntax error near unexpected token '&&'

Hmmm. Ok, vamos tentar outra maneira (inventada), tentando evitar erros:

$ if mupdf example.pdf &; then echo TRUE; fi
bash: syntax error near unexpected token ';'

Que tal:

$ if (mupdf example.pdf &); then echo TRUE; fi
TRUE

Isso parece promissor, mas depois tentamos o segundo caso, com um arquivo que não existe:

$ mupdf nofile.pdf &
[1] 16282
$ error: cannot open nofile.pdf
error: cannot load document 'nofile.pdf'
mupdf: error: cannot open document

$ if (mupdf nofile.pdf &); then echo TRUE; fi
TRUE
$  error: cannot open nofile.pdf
error: cannot load document 'nofile.pdf'
mupdf: error: cannot open document

Essa construção também não está funcionando. Portanto, a abordagem usual para a execução condicional não funciona porque não há status de saída. Mas notei que um pid é criado inicialmente em casos bem-sucedidos e malsucedidos (o mupdf não abre no segundo caso - o lançamento falha).

Então tente outra abordagem, espere para ver o que acontece com o pid de fundo, então montamos o seguinte script:

#!/usr/bin/env bash

# usage: ./show <file>.pdf

mupdf "$1" &>/dev/null &
sleep 2
if kill -0 $! &>/dev/null
then 
  echo TRUE
else
  echo FALSE
fi

# end file

E teste o primeiro caso:

$ ./show example.pdf  # case 1
[1] 16602
TRUE

Tudo bem. Agora o segundo caso:

$ ./show nofile.pdf   # case 2
[2] 16699
[2]+  Exit 1                  mupdf nofile.pdf &> /dev/null
FALSE

Bem, isso funciona também. Mas isso parece uma maneira muito confusa de checar o processo e pode falhar se o lançamento demorar mais (mais de 2 segundos). Então minha pergunta se torna, existe uma maneira melhor (mais limpa) de resolver este problema?

    
por AsymLabs 16.10.2015 / 14:42

2 respostas

1

Eu localizei vários tópicos semelhantes a este que considera o uso de xdotool e wmctl para testar o lançamento de um aplicativo persistente em janelas ou outro subprocesso persistente. Mas usá-los parece ser uma complicação desnecessária. A solução abaixo permitiria a execução condicional de um subprocesso persistente. Utiliza uma duração de sono de meio segundo. Se o subprocesso de interesse exigir mais tempo para o lançamento bem-sucedido, essa duração precisará ser aumentada de acordo.

Arquivo de origem do Bash lançamento

#/usr/bin/env bash

# launch : will allow launching a windowed application or persistent
# sub-process in the background so that conditional execution can be
# applied to determine whether or not it has launched successfully -
# dependencies: GNU coreutils (sleep), util-Linux (kill)

# usage: ./launch process arg_1 .. arg_n && echo TRUE || echo FALSE

$@ &>/dev/null & sleep 0.5 && kill -0 $! 2>/dev/null

# end file

Para que:

$ ./launch mupdf example.pdf && echo TRUE || echo FALSE
TRUE

$ ./launch mupdf nofile.pdf && echo TRUE || echo FALSE
FALSE

Como pós-escrito para essa informação, achei que seria útil incluir o conselho de mikeserv nos comentários para o post de abertura.

Considerando que a construção acima realiza a tarefa imediata, mikeserv aponta que poderia levar a outros problemas, pois não propaga o sinal para o script de chamada; Em vez disso, ele ignora e descarta. Esta é uma observação muito importante.

Os sinais são um elemento-chave da comunicação entre processos e podem levar à possibilidade de scripts orientados por eventos. Portanto, para scripts mais robustos e eficazes, mikeserv sugere o seguinte para capturar o sinal para que ele possa ser propagado:

{ mupdf some.pdf || kill -"$(($?&127))" "$$"; } &

onde $?&127 permite a ação de 1 a 128 sinais possíveis (POSIX), meu sistema Debian possui 64, então a máscara de sinal pode ser $?&63 .

Assim como uma observação final, para scripts muito simples, onde a comunicação entre processos não é de interesse, o lançamento proposto pode ser útil, mas para qualquer coisa mais, especialmente onde a comunicação entre processos é importante, e propagar) o sinal, conforme recomendado por mikeserv .

    
por 19.10.2015 / 00:51
-1

Como um verso:

mupdf example.pdf & echo mupdf is now in the background; wait $! && echo FINISHED successfully
    
por 16.02.2018 / 05:26