"Variabilize" o "e comercial" (processo em segundo plano)


9

Quero saber se existe uma maneira de colocar o e comercial em uma variável e ainda usá-lo para enviar um processo para o plano de fundo.

Isso funciona:

BCKGRND=yes
if [ "$BCKGRND" = "yes" ]; then
    sleep 5 &
else
    sleep 5
fi

Mas não seria legal realizar essas cinco linhas com apenas uma? Igual a:

BCKGRND='&'
sleep 5 ${BCKGRND}

Mas isso não funciona. Se BCKGRND não estiver definido, ele funcionará - mas quando estiver definido, ele será interpretado como um literal '&' e ocorrerá um erro.


depois de usar o e comercial final, echo $!retorna o PID
noobninja 16/01

Respostas:


9

Não é possível usar uma variável para segundo plano a chamada porque a expansão da variável ocorre após a linha de comando ser analisada pelos operadores de controle (como &&e &).

Outra opção seria agrupar as chamadas em uma função:

mayberunbg() {
  if [ "$BCKGRND" = "yes" ]; then
    "$@" &
  else
    "$@"
  fi
}

... e defina a variável conforme necessário:

$ BCKGRND=yes mayberunbg sleep 3
[1] 14137
$
[1]+  Done                    "$@"
# or
$ BCKGRND=yes
$ mayberunbg sleep 3
[1] 14203
$
[1]+  Done                    "$@"
$ BCKGRND=no mayberunbg sleep 3
# 3 seconds later
$

O que não ed? +1 de qualquer maneira, esta é a solução mais limpa.
Stephen Kitt

LOL @StephenKitt; agora as engrenagens estão girando
Jeff Schaller

Gostei da resposta do eval por sua simplicidade, mas o meu comando real do mundo real que eu queria ter em segundo plano era muito complicado com muitas variáveis ​​para ser confortável usando o eval. @ Jeff-Schaller deu a resposta que me apontou na direção que eu fui. Em vez de uma função, porém, coloquei o comando inteiro em uma variável e depois usei o estilo de instrução if para executar o comando com ou sem o &.
BrowncoatOkie

11

Você pode inverter as coisas e variar “em primeiro plano”:

FOREGROUND=fg
sleep 5 & ${FOREGROUND}

Defina FOREGROUNDcomo trueou vazio para executar o processo em segundo plano. (Definir FOREGROUNDpara trueexecução em segundo plano é reconhecidamente confuso! Nomes de variáveis ​​apropriados são deixados como exercício para o leitor.)


4
isso é legal, mas não funcionará em um shell sem controle de trabalho (ou seja, qualquer script, a menos que tenha set -msido usado).
mosvy

9

Você provavelmente teria que usar eval:

eval "sleep 5" "$BCKGRND"

evalfaz com que o shell reavalie os argumentos fornecidos. Um literal &seria, portanto, interpretado como &no final de um comando e não como um argumento para o comando, colocando o comando em segundo plano.


2
Uma resposta que contenha evaldeve conter um aviso de que isso deve ser tratado com cuidado. Veja, por exemplo, esta resposta .
Ralf

Não entendo qual é o problema em "$BCKGRND"avaliar um argumento vazio.
mosvy

2
@ Ralf absolutamente irrelevante neste caso . Não há nada de especial no eval - você pode executar comandos por meio de expansões aritméticas, por exemplo. Talvez deve haver uma tal advertência contra o uso de bash (ou qualquer shell similar) em tudo ;-)
mosvy

1
O @Kusalananda evalunirá seus argumentos com espaços antes de fazer a avaliação real. Basta experimentá-lo: eval printf "'{%s}\n'" foo "" "" "". eval foo "" "" "" ""é completamente semelhante eval foo, não importa o que IFSou outra coisa seja.
mosvy

1
O comando que está sendo avaliado deve estar entre aspas duplas se contiver caracteres especiais, por exemplo eval 'sleep $TIMEOUT' "$BACKGROUND". Caso contrário, você poderá obter expansões duplas se a variável se expandir para outra variável ou contiver caracteres especiais. Além disso, a cotação aninhada pode ser complicada.
Barmar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.