Alguém pode explicar em detalhes o que "set -m" faz?

16

Na página do manual , apenas diz:

-m O controle do trabalho está ativado.

Mas o que isso realmente significa?

Encontrei esse comando em uma pergunta SO , tenho o mesmo problema do OP, que é "a tela não pode iniciar o tomcat". E set -mresolveu isso. O OP explicou um pouco, mas eu não entendo direito:

O problema estava em tarefas em segundo plano, pois elas serão eliminadas quando o comando terminar.

A solução é simples: basta adicionar "set -m;" prefixo antes do comando.

laike9m
fonte

Respostas:

10

Citando a documentação do bash (de man bash):

JOB CONTROL
       Job  control  refers to  the  ability  to selectively  stop
       (suspend) the execution of  processes and continue (resume)
       their execution at a later point.  A user typically employs
       this facility via an interactive interface supplied jointly
       by the operating system kernel's terminal driver and bash.

Então, simplesmente, ter set -m(o padrão para shells interativos) permite que você use built-ins como fge bg, que seriam desativados em set +m(o padrão para shells não interativos).

No entanto, não é óbvio para mim qual é a conexão entre o controle de tarefas e a eliminação de processos em segundo plano na saída, mas posso confirmar que existe um: a execução set -m; (sleep 10 ; touch control-on) &criará o arquivo se alguém sair do shell logo após digitar esse comando, mas set +m; (sleep 10 ; touch control-off) &não o fará.

Eu acho que a resposta está no restante da documentação para set -m:

-m      Monitor  mode. [...]                     Background pro‐
        cesses run in a separate process group and a  line  con‐
        taining  their exit status is printed upon their comple‐
        tion.

Isso significa que os trabalhos em segundo plano iniciados em set +mnão são "processos em segundo plano" reais ("Processos em segundo plano são aqueles cujo ID do grupo de processos difere do do terminal"): eles compartilham o mesmo ID do grupo de processos que o shell que os iniciou, em vez de ter seus próprios grupo de processos como processos adequados em segundo plano. Isso explica o comportamento observado quando o shell é encerrado antes de alguns de seus trabalhos em segundo plano: se eu entendi corretamente, ao sair, um sinal é enviado aos processos no mesmo grupo de processos que o shell (eliminando, assim, os trabalhos em segundo plano iniciados em set +m), mas não àqueles de outros grupos de processos (deixando assim apenas os processos de segundo plano verdadeiros iniciados em set -m).

Portanto, no seu caso, o startup.shscript provavelmente inicia um trabalho em segundo plano. Quando esse script é executado de maneira não interativa, como no SSH, como na pergunta à qual você vinculou, o controle da tarefa é desabilitado, a tarefa "em segundo plano" compartilha o grupo de processos do shell remoto e, portanto, é eliminada assim que o shell sai. Por outro lado, ao ativar o controle da tarefa nesse shell, a tarefa em segundo plano adquire seu próprio grupo de processos e não é eliminada quando o shell pai sai.

dhag
fonte
Obrigado pela sua resposta, mas como está tomcat/bin/startup.shrelacionado a fg/ bg?
precisa saber é o seguinte
1
Não está diretamente relacionado; Eu estava tentando responder "O controle do trabalho está ativado / o que isso realmente significa?" de uma maneira geral. Talvez eu não tenha deixado claro, mas seu script parece iniciar um trabalho em segundo plano, ao qual o restante da minha resposta se aplica.
dhag
2

Encontrei isso na lista de problemas do github e acho que isso realmente responde à sua pergunta.

Não é realmente um problema de SSH, é mais o comportamento sutil dos modos não interativos / interativos do BASH e a propagação de sinais para grupos de processos.

A seguir, é baseado em /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 e http: //www.itp.uzh.ch/~dpotter/howto/daemonize , com algumas suposições não totalmente validadas, mas testes sobre como isso funciona parecem confirmar.

pty / tty = falso

O shell bash lançado se conecta ao stdout / stderr / stdin do processo iniciado e é mantido em execução até que não haja nada anexado aos soquetes e as crianças tenham saído. Um bom processo de deamon garantirá que não espere seus filhos saírem, bifurque um processo filho e saia. Quando neste modo, nenhum SIGHUP será enviado ao processo filho pelo SSH. Acredito que isso funcionará corretamente para a maioria dos scripts que executam um processo que lida com a desononização e não precisa ser em segundo plano. Onde os scripts init usam '&' para colocar em segundo plano um processo, é provável que o principal problema seja se o processo em segundo plano tenta ler do stdin, pois isso acionará um SIGHUP se a sessão for encerrada.

pty / tty = verdadeiro *

Se o script init colocar em segundo plano o processo iniciado, o shell BASH pai retornará um código de saída para a conexão SSH, que, por sua vez, procurará sair imediatamente, pois não está aguardando o término de um processo filho e não está bloqueado no stdout / stderr / stdin. Isso fará com que um SIGHUP seja enviado ao grupo de processos pai do shell bash, que, como o controle da tarefa está desativado no modo não interativo no bash, incluirá os processos filhos recém-lançados. Onde um processo daemon inicia explicitamente uma nova sessão de processo ao fazer uma bifurcação ou no processo de bifurcação, então ou seus filhos não receberão o SIGHUP do processo pai do BASH saindo. Observe que isso é diferente dos trabalhos suspensos, que verão um SIGTERM. Suspeito que os problemas em torno disso só funcionem às vezes tenham a ver com uma ligeira condição de corrida. http://www.itp.uzh.ch/~dpotter/howto/daemonize , você verá que no código a nova sessão é criada pelo processo bifurcado, que pode não ser executado antes da saída do pai, resultando em uma aleatória comportamento de sucesso / falha mencionado acima. Uma declaração de suspensão permitirá tempo suficiente para o processo bifurcado criar uma nova sessão, e é por isso que funciona em alguns casos.

pty / tty = true e o controle do trabalho é explicitamente ativado no bash

O SSH não se conectará ao stdout / stderr / stdin do shell bash ou a qualquer processo filho iniciado, o que significa que ele será encerrado assim que o shell bash pai começar a executar os comandos solicitados. Nesse caso, com o controle da tarefa ativado explicitamente, todos os processos iniciados pelo shell bash com '&' para colocá-los em segundo plano serão colocados em uma sessão separada imediatamente e não receberão o sinal SIGHUP quando o processo pai da sessão BASH terminar ( Conexão SSH neste caso).

O que é necessário para corrigir

Acho que as soluções precisam ser mencionadas explicitamente na documentação de operações run / sudo como um caso especial ao trabalhar com processos / serviços em segundo plano. Basicamente, use 'pty = false' ou, quando isso não for possível, ative explicitamente o controle de tarefas como o primeiro comando, e o comportamento estará correto.

Em https://github.com/fabric/fabric/issues/395

pootow
fonte