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 / 786058
Accepted
HappyFace
HappyFace
Asked: 2024-11-04 00:34:00 +0800 CST2024-11-04 00:34:00 +0800 CST 2024-11-04 00:34:00 +0800 CST

Impedir a propagação do SIGINT do subshell para o shell pai no Zsh

  • 772

Preciso evitar que SIGINT (Ctrl-C) se propague de um subshell para suas funções de shell pai no Zsh.

Aqui está um exemplo mínimo:

function sox-record {
    local output="${1:-$(mktemp).wav}"
    (
        rec "${output}" trim 0 300  # Part of sox package
    )
    echo "${output}"  # Need this to continue executing after Ctrl-C
}

function audio-postprocess {
    local audio="$(sox-record)"
    # Process the audio file...
    echo "${audio}"
}

function audio-transcribe {
    local audio="$(audio-postprocess)"
    # Send to transcription service...
    transcribe_audio "${audio}"  # Never reached if Ctrl-C during recording
}

A solução alternativa atual requer capturar SIGINT em todos os níveis, o que leva a um código repetitivo e sujeito a erros:

function sox-record {
    local output="${1:-$(mktemp).wav}"
    setopt localtraps
    trap '' INT
    (
        rec "${output}" trim 0 300
    )
    trap - INT
    echo "${output}"
}

function audio-postprocess {
    setopt localtraps
    trap '' INT
    local audio="$(sox-record)"
    trap - INT
    # Process the audio file...
    echo "${audio}"
}

function audio-transcribe {
    setopt localtraps
    trap '' INT
    local audio="$(audio-postprocess)"
    trap - INT
    # Send to transcription service...
    transcribe_audio "${audio}"
}

Quando o usuário pressiona Ctrl-C para parar a gravação, eu quero: 1. Que o recsubprocesso termine (funcionando) 2. Que as funções pai continuem executando (requer captura de SIGINT em cada chamador)

Eu sei que:

  • SIGINT é enviado a todos os processos no grupo de processos em primeiro plano
  • O uso setsidcria um novo grupo de processos, mas impede que os sinais cheguem ao filho
  • Adicionar trap '' INTo pai requer que todos os chamadores também capturem SIGINT para evitar propagação.

Existe uma maneira de isolar SIGINT apenas para o subshell sem exigir tratamento de sinal em todas as funções pai? Ou isso é fundamentalmente impossível devido a como os grupos de processos Unix e a propagação de sinal funcionam?


Dei uma olhada nesta pergunta e tentei isto:

function sox-record {
    local output="${1:-$(mktemp).wav}"

    zsh -mfc "rec "${output}" trim 0 300" </dev/null >&2 || true

    echo "${output}"
}

Embora isso funcione quando eu apenas chamo sox-record, quando eu chamo uma função pai como audio-postprocess, Ctrl-C não faz nada. (E eu tenho que usar pkillto kill rec.)

function audio-postprocess {
    local audio="$(sox-record)"

    # Process the audio file...
    echo "${audio}"
}

zsh
  • 1 1 respostas
  • 14 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2024-11-04T01:24:35+08:002024-11-04T01:24:35+08:00

    SIGINT não se propaga para os pais . Após ^C, o kernel envia o SIGINT para o grupo de processos em primeiro plano do terminal.

    Quando esse script zsh for iniciado em um terminal, seu shell interativo terá criado um grupo de processos (um job) para ele, tornado-o o grupo de processos em primeiro plano do terminal e executado o script. Todos os processos iniciados por esse script, incluindo os subshells e o que está sendo executado, recestarão nesse grupo e todos receberão SIGINT em ^C.

    Se você quiser que apenas o processo em execução recreceba esse sinal, ignore SIGINT globalmente no nível superior com trap '' INTe restaure-o somente reccom (trap - INT; rec...).

    function transcribe_audio {
        print -r Would transcribe $1
    }
    function sox-record {
        local output="${1-$(mktemp).wav}"
        (trap - INT; rec -- "$output" trim 0 300)
        print -r -- "$output"
    }
    function audio-postprocess {
        local audio="$(sox-record)"
        # Process the audio file...
        print -r -- "$audio"
    }
    function audio-transcribe {
        local audio="$(audio-postprocess)"
        transcribe_audio "$audio"
    }
    trap '' INT
    audio-transcribe
    trap - INT
    
    # rest of the script not immune to SIGINT
    

    Você também pode mover o trap's para dentro audio-transcribe, mas precisa se lembrar de não executá-lo em um subshell, ou então ignorar o SIGINT só será aplicado àquele subshell e seus descendentes, não ao processo pai.

    ...
    function audio-transcribe {
        trap '' INT
        local audio="$(audio-postprocess)"
        transcribe_audio "$audio"
        trap - INT
    }
    audio-transcribe         # OK
    (audio-transcribe)       # not OK
    blah=$(audio-transcribe) # not OK
    audio-transcribe | blah  # not OK
    

    Ter o script fazendo o controle de tarefas sozinho, ou seja, colocando-o recem seu próprio grupo de processos e tornando-o o grupo de processos em primeiro plano, é uma abordagem que também pode funcionar, mas no zsh (pelo menos 5.9), você não pode fazer isso apenas com a monitoropção (conforme definida por set -m), pois em invocações não interativas, ele cria grupos de processos para comandos, mas não altera o grupo de processos em primeiro plano do terminal, então teria o efeito oposto ao que você deseja.

    Para zshestar disposto a fazer o controle de trabalho terminal, você precisa interactive( -i) em vez disso.

    $ zsh -fc 'ps -o pid,pgid,tpgid,args; exit'
        PID    PGID   TPGID COMMAND
      32962   32962   32977 /bin/zsh
      32977   32977   32977 zsh -fc ps -o pid,pgid,tpgid,args; exit
      32978   32977   32977 ps -o pid,pgid,tpgid,args
    

    Nem -inem -m, psno mesmo grupo de processos que o pai e em primeiro plano.

    $ zsh -m -fc 'ps -o pid,pgid,tpgid,args; exit'
        PID    PGID   TPGID COMMAND
      32962   32962   32987 /bin/zsh
      32987   32987   32987 zsh -m -fc ps -o pid,pgid,tpgid,args; exit
      32988   32988   32987 ps -o pid,pgid,tpgid,args
    

    Sozinho -m, psestá em um novo grupo de processos, mas não foi transformado no grupo de processos de primeiro plano do terminal (tpgid), então ele está em segundo plano e não receberá o SIGINT ^C.

    $ zsh -i -fc 'ps -o pid,pgid,tpgid,args; exit'
        PID    PGID   TPGID COMMAND
      32962   32962   32997 /bin/zsh
      32996   32996   32997 zsh -i -fc ps -o pid,pgid,tpgid,args; exit
      32997   32997   32997 ps -o pid,pgid,tpgid,args
    

    Com -i, o que implica -m, psestá em um novo grupo de processos que está em primeiro plano desta vez, enquanto zshele próprio está em segundo plano.

    Brincar com controle de trabalho em scripts é, no entanto, geralmente uma má ideia, pois é fonte de todos os tipos de comportamentos desagradáveis ​​inesperados, então eu não faria isso. Se fizer isso, certifique-se de escrevê-lo:

    zsh -ifc 'rec -- "$1" trim 0 300' zsh "$output"
    

    Não incorpore a expansão no código zsh, pois isso a tornaria uma vulnerabilidade de injeção de comando .$output

    • 1

relate perguntas

  • Listar arquivos que não possuem outro arquivo com sufixo

  • Em que circunstâncias o executável encontrado primeiro no caminho não será usado

  • Symlinking para todos os arquivos de ponto e diretórios

  • Como incrementar uma variável nomeada dinamicamente em `zsh`

  • Por que não consigo definir uma variável somente leitura chamada path no zsh?

Sidebar

Stats

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

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

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

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +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

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