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 / 483744
Accepted
kjo
kjo
Asked: 2018-11-24 10:37:55 +0800 CST2018-11-24 10:37:55 +0800 CST 2018-11-24 10:37:55 +0800 CST

Como escrever uma função que saia de forma confiável (com um status especificado) do processo atual?

  • 772

O script abaixo é uma ilustração mínima (embora artificial) do problema.

## demo.sh

exitfn () {
    printf -- 'exitfn PID: %d\n' "$$" >&2
    exit 1
}

printf -- 'script PID: %d\n' "$$" >&2

exitfn | :

printf -- 'SHOULD NEVER SEE THIS (0)\n' >&2

exitfn

printf -- 'SHOULD NEVER SEE THIS (1)\n' >&2

Neste script de exemplo, exitfnrepresenta uma função cujo trabalho envolve encerrar o processo atual 1 .

Infelizmente, conforme implementado, exitfnnão cumpre essa missão de forma confiável.

Se alguém executar este script, a saída será assim:

% bash ./demo.sh
script PID: 26731
exitfn PID: 26731
SHOULD NEVER SEE THIS (0)
exitfn PID: 26731

(Claro, o valor mostrado para PID será diferente com cada chamada.)

O ponto-chave aqui é que, na primeira invocação da exitfnfunção, o exit 1comando em seu corpo falha ao encerrar a execução do script de inclusão (como evidenciado pela execução do primeiro printfcomando imediatamente a seguir). Em contraste, na segunda invocação de exitfn, esse exit 1comando encerra a execução do script (como evidenciado pelo fato de que o segundo printfcomando não é executado).

A única diferença entre as duas invocações de exitfné que a primeira ocorre como o primeiro componente de um pipeline de dois componentes, enquanto a segunda é uma chamada "independente".

Estou intrigado com isso. Eu esperava que exitisso tivesse o efeito de matar o processo atual (ou seja, aquele com PID fornecido por $$). Obviamente, isso nem sempre é verdade.

Seja como for, existe uma maneira de escrever exitfnpara que ele saia do script ao redor, mesmo quando invocado em um pipeline?


Aliás, o script acima também é um script zsh válido e produz o mesmo resultado:

% zsh ./demo.sh
script PID: 26799
exitfn PID: 26799
SHOULD NEVER SEE THIS (0)
exitfn PID: 26799

Eu estaria interessado na resposta a esta pergunta para zsh também.


Finalmente, devo salientar que implementar exitfnassim não funciona:

exitfn () {
    printf -- 'exitfn PID: %d\n' "$$" >&2
    exit 1
    kill -9 "$$"
}

...porque, em todas as circunstâncias, o exit 1comando é sempre a última linha daquela função que é executada. ( Substituir exit 1 por kill -9 $$não é aceitável: quero controlar o status de saída do script e sua saída para stderr.)


1 Na prática, essa função executaria outras tarefas, como log de diagnóstico ou operações de limpeza, antes de encerrar o processo atual.

bash shell-script
  • 1 1 respostas
  • 76 Views

1 respostas

  • Voted
  1. Best Answer
    Gilles 'SO- stop being evil'
    2018-11-24T14:13:09+08:002018-11-24T14:13:09+08:00

    Eu esperava que exitisso tivesse o efeito de matar o processo atual (ou seja, aquele com PID fornecido por $$)

    “O processo atual” não é a mesma coisa que “o processo com PID dado por $$”. exitsai do subshell atual ou do shell original se não for chamado em um subshell.

    Certas construções, como o conteúdo de ( … )(agrupamento com subshell), substituições de comando ( $(…)ou `…`) e cada lado de um pipe (ou apenas o lado esquerdo em alguns shells), são executados em um subshell. Um subshell se comporta como se fosse um processo separado criado com fork(), e geralmente é implementado dessa maneira (alguns shells não usam subprocessos em algumas circunstâncias, como otimização de desempenho). O subshell tem sua própria cópia de variáveis, seus próprios redirecionamentos, etc. A chamada exitsai do subshell, assim como a exit()função na biblioteca C padrão sai do processo. Para saber mais sobre subshells, consulte O que é um subshell (no contexto da documentação do make)? , Qual é a diferença exata entre um "subshell" e um "processo filho"?e $() é um subshell? .

    $$é sempre o ID do processo do shell original. Ele não muda em um subshell. Alguns shells têm uma variável que muda em um subshell, por exemplo $BASHPIDem bash e mksh, ou ${.sh.subshell}em ksh ou $ZSH_SUBSHELLou $sysparams[pid]em zsh¹.

    existe uma maneira de escrever exitfnpara que ele saia do script circundante mesmo quando invocado em um pipeline?

    Não exatamente. Você precisará trabalhar mais, no ponto em que o script cria o subshell, no nível superior ou em ambos. Consulte o script de shell de saída de um subshell para obter aproximações.


    ¹ cuidado, porém, ao contrário de outros shells, zshrealiza expansões em pipelines no processo pai (da esquerda para a direita), não em cada um dos membros dos pipelines: zsh -c 'echo $ZSH_SUBSHELL | cat'saídas 0(mesmo que seja echoexecutada em um processo filho) e zsh -c 'n=0; echo $((++n)) | echo $((++n))'saídas 2.

    • 3

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • MySQL Select com função IN () com array bash

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

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

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

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 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

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 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
    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
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +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