AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 406689
Accepted
Philip Kirkbride
Philip Kirkbride
Asked: 2017-11-24 16:20:25 +0800 CST2017-11-24 16:20:25 +0800 CST 2017-11-24 16:20:25 +0800 CST

Silenciosamente matar subshell?

  • 772

Eu quero implementar algo como este Q/A , mas para um sub-shell. Aqui está um exemplo mínimo do que estou tentando:

(subshell=$BASHPID
  (kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)

echo subshell done

Como posso fazer isso apenas subshell doneretorna em vez de:

./test.sh: line 4:  5439 Terminated              ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done

Editar: posso estar errado na terminologia aqui, por subshell, quero dizer o processo dentro do primeiro conjunto de colchetes.

Atualizar:

Quero postar o trecho do programa real para contexto, acima está uma simplificação:

# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then

      # code to setup wpa configurations here

      # If wifi key is wrong kill subshell
      subshell=$BASHPID
      (sudo stdbuf -o0 wpa_supplicant -Dwext -i$wifi -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 \
        | grep -m 1 "pre-shared key may be incorrect" \
        && kill -s PIPE "$subshell") &

      # More code which does the setup necessary for wifi

) && connected=true

# later json will be returned based on if connected is set
kill output
  • 3 3 respostas
  • 3614 Views

3 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2017-11-27T09:19:35+08:002017-11-27T09:19:35+08:00

    Observação:

    • wait $subshellnão funcionará, pois $subshellnão é filho do processo waitem que você está executando. De qualquer forma, você não esperaria o processo fazer waitisso, então não importa muito.
    • kill $subshellvai matar o subshell, mas não sleepse o subshell conseguiu iniciá-lo no momento da killexecução. No entanto, você pode executar sleepo mesmo processo comexec
    • você pode usar SIGPIPE em vez de SIGTERM para evitar a mensagem
    • deixar uma variável sem aspas em contextos de lista tem um significado muito especial em bash.

    Então, tendo dito tudo isso, você pode fazer:

    (
      subshell=$BASHPID
      kill -s PIPE "$subshell" &
      sleep 600
    )
    echo subshell done
    

    (substitua sleep 60por exec sleep 60se quiser killmatar sleepe não apenas o subshell, que neste caso pode nem ter tempo de ser executado sleepno momento em que você o matar).

    De qualquer forma, não tenho certeza do que você deseja alcançar com isso.

    sleep 600 &
    

    seria uma maneira mais confiável de iniciar sleepem segundo plano se fosse isso que você queria fazer (ou (sleep 600 &)se quisesse ocultar esse sleepprocesso do shell principal)

    Agora com o seu real

    sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf
    

    comando, observe que sudogera um processo filho para executar o comando (apenas porque pode ser necessário registrar seu status ou executar algumas tarefas de sessão PAM posteriormente). stdbufno entanto, executará wpa_supplicantno mesmo processo, portanto, no final, você terá três processos (além do restante do script) na wpa_supplicantancestralidade de:

    1. o subshell
    2. sudo como filho de 1
    3. wpa_supplicant (que estava executando stdbuf anteriormente) como filho de 2

    Se você matar 1, isso não mata 2 automaticamente. Se você matar 2, no entanto, a menos que seja com um sinal como SIGKILL que não pode ser interceptado, isso matará 3 como sudoacontece ao encaminhar os sinais que recebe para o comando que executa .

    De qualquer forma, esse não é o subshell que você gostaria de matar aqui, são 3 ou pelo menos 2.

    Agora, se estiver executando como roote o restante do script não, você não poderá eliminá-lo tão facilmente.

    Você precisaria que o killfosse feito como root, então você precisaria:

    sudo WIFI="$wifi" bash -c '
      (echo "$BASHPID" &&
       exec stdbuf -o0 wpa_supplicant -Dwext -i"$WIFI" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1
      ) | {
        read pid &&
          grep -m1 "pre-shared key may be incorrect" &&
          kill -s PIPE "$pid"
      }'
    

    Dessa forma, wpa_supplicantestará rodando no mesmo $BASHPIDprocesso que o subshell que estamos fazendo com exec.

    Pegamos o pid pelo pipe e rodamos killcomo root.

    Observe que, se você estiver pronto para esperar um pouco mais,

    sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 |
      grep -m1 "pre-shared key may be incorrect"
    

    Teria wpa_supplicantmatado automaticamente com um SIGPIPE (pelo sistema, portanto, sem problema de permissão) na próxima vez que gravar algo naquele canal depois que grepele se for.

    Algumas implementações de shell não esperariam pelo retorno de sudodepois grep(deixando-o rodando em segundo plano até obter SIGPIPEd), e com bash, você também pode fazer isso usando a grep ... <(sudo ...)sintaxe, onde bashnão espera por sudonenhum dos dois retornos grep.

    Mais em Grep lento para sair depois de encontrar correspondência?

    • 7
  2. J_H
    2017-11-27T09:18:42+08:002017-11-27T09:18:42+08:00

    Subshell refere-se a um comando shell que é filho de algum shell, como filho do bash -ishell de login interativo que oferece um $prompt. Você não precisa executar seu comando em um subshell - você pode optar por executá-lo como um processo independente. Parece que isso pode ser apropriado porque você não quer que seu stdout / stderr atrapalhe a aparência de sua barra de progresso e porque você não quer que o shell pai relate ou mesmo perceba a morte de seu filho.

    Existem ferramentas padrão para realizar isso, como daemonize e nohup. (Consulte também as páginas de manual .) Você pode se sair melhor com nohup . Aqui está um exemplo de como usá-lo para executar um programa trivial, que não cria nohup.out:

    $ nohup true 2>&1 > /dev/null &
    

    Faça com que seu programa, ou um script wrapper para seu programa, registre seu PID em /tmp/my.pid -- o bash disponibiliza isso como $$variável. Então o processo de monitoramento com a barra de progresso pode

    $ kill `cat /tmp/my.pid`
    

    quando não precisar mais desse programa para fazer mais processamento. Alternativamente, você pode preferir dar o nome do seu programa para killall.

    • 2
  3. Chris Hill
    2017-11-27T15:36:53+08:002017-11-27T15:36:53+08:00

    Você pode estar procurando por isso

    #!/bin/bash
    (subshell=$BASHPID
      (kill $subshell & wait $subshell 2>/dev/null) &
    sleep 600) &
    wait $! 2>/dev/null
    
    echo subshell done
    

    aqui o subshell é colocado em segundo plano, então o shell pai espera, mas com a saída de espera enviada para /dev/null. Isso captura a Terminatedmensagem.

    Observe que, se você alterar a espera para capturar a saída para o arquivo, por exemplo wait $! 2>wait_output, verá

     ./foo.sh: line 5:  1939 Terminated              ( subshell=$BASHPID; ( kill $subshell & wait $subshell 2> /dev/null ) & sleep 600 )
    

    mostrando que Terminatedé do shell pai.

    Uma pequena verificação para ver se funciona se houver alguma atividade antes de matar é

    #!/bin/bash
    (subshell=$BASHPID
     (sleep 1; kill $subshell & wait $subshell 2>/dev/null) &
    sleep 600) & wait 2>wait_output
    
    echo subshell done
    

    Este exemplo fará uma pausa por um segundo antes de imprimir subshell done. Este exemplo também mostra como colocar em segundo plano e esperar tudo na mesma linha, por exemplo & wait 2>wait_output. Não tenho certeza se isso tem alguma vantagem/desvantagem sobre o exemplo com wait $!.

    O principal a observar aqui é que as Terminatedmensagens vêm do controle de trabalho do shell pai de nível superior. Isso é o que vê o subshell terminar e gera a mensagem. Então é aí que você deseja capturar a saída. Redirecionar a waitsaída do comando faz isso.

    • 1

relate perguntas

  • Sair do script de um processo em segundo plano?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Matriz JSON para bash variáveis ​​usando jq

    • 4 respostas
  • Marko Smith

    A data pode formatar a hora atual para o fuso horário GMT? [duplicado]

    • 2 respostas
  • Marko Smith

    bash + lê variáveis ​​e valores do arquivo pelo script bash

    • 4 respostas
  • Marko Smith

    Como posso copiar um diretório e renomeá-lo no mesmo comando?

    • 4 respostas
  • Marko Smith

    conexão ssh. Conexão X11 rejeitada devido a autenticação incorreta

    • 3 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Marko Smith

    comando systemctl não funciona no RHEL 6

    • 3 respostas
  • Marko Smith

    rsync porta 22 e 873 uso

    • 2 respostas
  • Marko Smith

    snap /dev/loop em 100% de utilização -- sem espaço livre

    • 1 respostas
  • Marko Smith

    chave de impressão jq e valor para todos no subobjeto

    • 2 respostas
  • Martin Hope
    EHerman Matriz JSON para bash variáveis ​​usando jq 2017-12-31 14:50:58 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Drux A data pode formatar a hora atual para o fuso horário GMT? [duplicado] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC Como posso copiar um diretório e renomeá-lo no mesmo comando? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve Como as permissões de arquivo funcionam para o usuário "root"? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe Altere o editor padrão para vim para _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey Como baixar o pacote não instalá-lo com o comando apt-get? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao Por que os diretórios /home, /usr, /var, etc. têm o mesmo número de inode (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg — o comando list-keys gera uid [ desconhecido ] depois de importar a chave privada para uma instalação limpa 2017-11-26 18:26:02 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve