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 / 525203
Accepted
kjo
kjo
Asked: 2019-06-16 16:21:50 +0800 CST2019-06-16 16:21:50 +0800 CST 2019-06-16 16:21:50 +0800 CST

Como capturar stderr da função que modifica o ambiente atual?

  • 772

A modulefunção do pacote Environment Modules 1 faz seu trabalho modificando várias variáveis ​​de ambiente do processo shell atual .

Infelizmente, essa função retorna 0 se for bem-sucedida ou não 2 , o que torna difícil para um script de cliente responder adequadamente a falhas.

Eu gostaria de implementar um wrapper de função mymoduleque modulepassa todos os seus argumentos diretamente para modulee retorna corretamente um valor diferente de zero se modulefalhar.

A única maneira de mymoduledetectar se modulefalhou é inspecionar a função de saída modulegrava em stderr, se houver.

O problema é que não consigo encontrar uma maneira razoável mymodulede obter essa saída sem anular moduleas ações de . Mais especificamente, quase todas as maneiras em que posso pensar para capturar moduleo stderr de 's em uma variável envolvem a execução moduleem um processo filho, impedindo-o de fazer seu trabalho (o que requer a modificação do shell atual).

A única exceção ao acima seria redirecionar moduleo stderr de 's para um arquivo temporário, mas eu odeio a ideia de criar um arquivo toda vez que a modulefunção for executada.

Existe alguma maneira de mymoduleinvocar moduleno ambiente atual e ao mesmo tempo capturar seu stderr em uma variável?

Estou interessado em respostas para ambos zshe bash.


1 Não confundir com o pacote de módulos de ambiente Lmod , que possui uma interface muito semelhante.

2 Pelo menos este é o caso da versão antiga 3.2.9 com a qual devo trabalhar. Eu não tenho controle sobre isso.

bash shell-script
  • 3 3 respostas
  • 386 Views

3 respostas

  • Voted
  1. Best Answer
    Michael Homer
    2019-06-16T18:54:26+08:002019-06-16T18:54:26+08:00

    Tanto o Bash quanto o zsh têm coprocessos (infelizmente um pouco diferentes), que basicamente encerram uma pipechamada e geram um subprocesso com sua entrada e saída padrão disponíveis para o shell de chamada. Em essência, eles permitem que o shell seja reproduzido xem , mas com todos y, e executando a partir do processo atual e não em um ambiente de execução de pipeline.x | cmd | yxycmd

    Isso nos permitirá executar module 2>&...alguns ..., moduleexecutando a partir do shell atual. Se usarmos catcomo nosso coprocesso (ou seja cmd, ), ele apenas repetirá tudo de volta novamente e, em seguida, poderemos ler a saída de volta no shell atual novamente y <&...mais tarde.

    Outra opção é redirecionar o erro padrão para outro processo em segundo plano e waitpara seu código de retorno. Vou abordar ambos abaixo.


    Vou usar esta modulefunção falsa para testar para que eu possa ativar e desativar erros à vontade. If modifica o ambiente shell atual para que possamos vê-lo e gera "err" para stderr; Estarei comentando essa linha dentro e fora conforme necessário:

    module() {
            sleep 1
            FOO=$(date)
            echo err >&2
    } 
    

    Se eu executar um catcoprocesso no Bash, posso redirecionar moduleo stderr de 's para isso e ler cato stdout de 's para fazer o que eu quiser:

    coproc cat
    module 2>&${COPROC[1]}
    exec {COPROC[1]}>&-
    if grep -q err <&${COPROC[0]}
    then
            echo got an error
    else
            echo no error
    fi
    

    Em zsh precisa ser

    module 2>&p
    exec 4<&p
    coproc :
    if grep -q err <&4
    

    no meio em vez disso.

    Em ambos os casos, posso executar o modulecomando no shell atual e ler a saída de erro lá. Uma função pode retornar dentro do ifnormal.

    Tudo, exceto catestá sendo executado a partir do ambiente de execução atual: os redirecionamentos FD não criam ambientes independentes como os pipelines. Podemos echo $FOOno final verificar isso, e ver se a data foi atualizada porque moduleexecutou no ambiente atual.


    Alternativamente, o processo em segundo plano poderia fazer todo o trabalho. Isso funciona no Bash:

    exec 2> >( if grep -q . ; then exit 7 ; else exit 0 ; fi )
    PID=$!
    module
    exec 2>&-
    wait $PID
    echo $?
    

    O resultado acima será 7ou 0de acordo com o que o subprocesso no topo disse - você pode ajustar para fazer o que quiser sobre o código de retorno. Sob zsh, não, porque $!não está definido para substituições de processos; isso deveria ser solucionável, mas eu parei de tentar. Um fifo fixo, em vez de um arquivo temporário, também funcionaria aqui.

    Nesse caso, você provavelmente deseja salvar e restaurar o FD 2 em ambos os lados também.

    • 4
  2. mosvy
    2019-06-16T18:57:46+08:002019-06-16T18:57:46+08:00

    Não sei como os "Módulos de ambiente" funcionam, mas assumirei pela sua descrição que são funções de shell que definem variáveis ​​de ambiente e sua saída stderr deve ser capturada / correspondida sem executá-las em um processo separado.

    A resposta, goste ou não, é que a única maneira robusta e óbvia é redirecionar seu stderr para um arquivo temporário. Usar pipes nomeados é tão complicado (você ainda precisa criar um arquivo temporário!), além de ser muito mais complicado. E o uso de coprocessos é oneroso, incômodo e não portátil .

    Em bash(e bashapenas em) você pode tirar proveito de um recurso não documentado ( $!sendo definido para o PID de uma >(...)substituição de processo) e se safar com algo como:

    module 2> >(grep error)
    wait $! && echo failed
    

    Este exemplo assume que moduleele próprio não está gerando nenhum filho que possa confundir $!.

    • 4
  3. Stéphane Chazelas
    2019-06-17T22:34:34+08:002019-06-17T22:34:34+08:00

    No Linux, com bash e zsh, você deve ser capaz de fazer:

    my_module() {
      chmod u+w /dev/fd/3 # only needed in bash 5+
      module 2> /dev/fd/3 3>&-
      ! grep -q err /dev/fd/3
    } 3<<< ''
    

    O 3<<< ''é uma string here contendo inicialmente uma linha vazia. Ambos zshe bashimplementam here-strings e here-documents como arquivos temporários excluídos. No Linux (e Cygwin, mas geralmente não em outros sistemas), a abertura /dev/fd/3abre o arquivo apontado pelo fd 3, mesmo que já tenha sido excluído (em outros sistemas, duplica o fd 3), por isso é uma maneira muito limpa de trabalhar com arquivos temporários lá. O arquivo já foi deletado, você não precisa se preocupar com sua limpeza, e ele só fica visível no FS por um tempo muito curto (desde a versão 5, no entanto, bashremove as permissões de gravação para ele com as quais precisamos trabalhar chmod).

    Aqui, você precisa de um arquivo temporário se for executar modulee grepem sequência (em oposição a em paralelo em processos separados). Fazer isso com tubos (como nas abordagens de Michael, mas ao contrário do @mosvy) levaria a bloqueios se houver saída de dados suficiente para preencher os tubos.

    • 4

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

    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