Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

444
Visualizações
Bash: How to get a script to rerun itself as a background task?

I'm writing a Bash script that is intended to be used as a daemon. If the user of my script does not pass a --sync option to the script, I want the script to rerun itself as a background task using that option. Here is my code (the last part was stolen from this SO post):

#!/usr/bin/env bash

args=("$@") # capture them here so we can use them if --sync's not passed
async=true

while [ $# -gt 0 ]
do
    case "$1" in
        --sync)
            async=false
            ;;
        # other options
    esac
    shift
done

# if --sync isn't passed, rerun the script as a background task
$async && exec nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null &

For some reason, it doesn't seem to be working. When I do bash -x myscript (which helps debug the script), it seems that it just keeps on going even if $async is true, which I didn't think would happen since exec normally stops execution.

Likewise, if I run this command from my terminal:

exec nohup true 0<&- &> /dev/null &

it also fails to exit the shell, despite the use of exec. Why is this, and what can I do to work around it? (Bonus points: Is there any way to do this without creating a subshell?)

Thanks.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

The & is being applied to the exec command itself, so exec foo & forks a new asynchronous subshell (or equivalent thereto, see below). That subshell immediately replaces itself with foo. If you want the parent (that is, your script) to terminate as well, you'll need to do so explicitly with an exit command.

The exec is probably not buying you anything here. Bash is clever enough to not actually start a subshell for a simple backgrounded command. So it should be sufficient to do:

if $async; then
  nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null &
  exit 0
fi

I don't know of a way to do this without a subshell. But when you write shell scripts, you get subshells. Personally I'd just use a simple variable and test it with something like if [[ $async ]]; instead of executing true or false, but since those are also bash builtins, it's pretty well equivalent. In other shells they might run in subshells.

Now that I think of it, since you're reprocessing all the options in async execution anyway, you might as well just fork and exit from within the case statement, so you don't need the second check at all:

case "$1" in
    --sync)
        nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null &
        exit 0
        ;;
over 4 years ago · Santiago Trujillo Relatório

0

I disagree with rici's answer because the question clearly states background-ing is only wanted when --sync is NOT passed into the script. What was shown appears to be an infinite loop, and isn't checking all the parameters passed. I believe the original code was fine, except for the final "async && exec ...". The following replacement for that line should work:

if [ "$async" = true ]; then
   nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null &
   exit 0
fi

followed by what your code is supposed to do when --sync is passed.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda