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 / ubuntu / Perguntas / 1168750
Accepted
WinEunuuchs2Unix
WinEunuuchs2Unix
Asked: 2019-08-27 16:51:14 +0800 CST2019-08-27 16:51:14 +0800 CST 2019-08-27 16:51:14 +0800 CST

Como passar 2>/dev/null como uma variável?

  • 772

Eu tenho esse código que funciona:

# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName" 2>/dev/null
else
    # Get silly error messages when running from terminal
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
fi

Se eu tentar encurtar assim:

# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"

google-chrome --headless --disable-gpu --dump-dom \
    "$RobWebAddress" > "$DownloadName" "$HideErrors"

Recebo mensagens de erro:

[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)

Por que um argumento codificado funciona, mas não um argumento como variável?


Edição 2:

Atualmente, obtive sucesso com a sugestão alternativa da segunda resposta:

# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null

google-chrome --headless --disable-gpu --dump-dom \
                "$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"

Editar 1:

Com base na primeira resposta, devo salientar que o cabeçalho do programa já contém:

[[ $fCron != true ]] &&
    exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
command-line bash redirect
  • 3 3 respostas
  • 5349 Views

3 respostas

  • Voted
  1. Best Answer
    Eliah Kagan
    2019-08-27T17:27:42+08:002019-08-27T17:27:42+08:00

    A razão pela qual você não pode causar redirecionamento ao expandir "$HideErrors"é que símbolos como >não são tratados especialmente depois de serem produzidos pela expansão de parâmetro . Isso é realmente muito bom, porque esses símbolos aparecem no texto que você pode querer expandir e usar literalmente.

    Isso vale independentemente de você citar ou não $HideErrors. O resultado da expansão de parâmetros está sujeito a divisão de palavras e globbing quando a expansão não está entre aspas, mas é isso.


    Quanto ao que fazer a respeito, existem várias maneiras de obter o redirecionamento condicional. Para um comando muito simples, pode ser razoável escrever o comando inteiro duas vezes, uma vez em cada ramo de uma construção caseou if- else. Isso logo se torna oneroso, no entanto, e o comando que você mostrou é certamente um caso em que isso não seria o ideal.

    Das abordagens que permitem evitar a repetição , há duas que recomendo especialmente, porque são bastante limpas e fáceis de acertar. Você gostaria de usar apenas um deles, não os dois ao mesmo tempo para o mesmo comando e redirecionamento.

    Armazene o comando em vez do redirecionamento. Em vez de tentar armazenar o redirecionamento em uma variável e aplicar a expansão de parâmetros, armazene o comando em uma função shell . Em seguida, escreva um caseou if- else, no qual a função é chamada com o redirecionamento em um ramo e sem ele no outro.

    Se você conceituar seu comando como código que deseja escrever uma vez, mas executado em várias circunstâncias, uma função é a solução natural. Isso é o que eu costumo fazer. Ele tem o benefício de não exigir um subshell nem armazenamento manual e redefinição de estado.

    Com seu código:

    launch() {
        google-chrome --headless --disable-gpu --dump-dom \
            "$RobWebAddress" > "$DownloadName"
    }
    
    case $fCron in
    true)  launch 2>/dev/null;;
    *)     launch;; # Get silly error messages when running from terminal
    esac
    

    Você pode aplicar o espaçamento que quiser, ou if- elsese preferir. Observe que usa automaticamente as variáveis ​​e launchdo chamador , mesmo que sejam variáveis ​​locais, porque o Bash tem escopo dinâmico , ao contrário da maioria das linguagens de programação que têm escopo lexical.RobWebAddressDownloadName

    Execute o comando em um subshell e aplique condicionalmente o redirecionamento para exec. Foi sobre isso que o steeldriver comentou , mas por dentro ( )para manter o efeito local . Quando o execbuiltin é executado sem argumentos, ele não substitui o shell atual por um novo processo, mas aplica qualquer um de seus redirecionamentos ao shell atual.

    (Também é possível acompanhar qual foi o erro padrão e restaurá-lo, sem usar um subshell e, portanto, sem sacrificar a capacidade de modificar o ambiente do shell atual. No entanto, deixarei os detalhes disso para outras respostas.)

    Com seu código:

    (
        # Suppress silly error messages unless running from terminal
        case $fCron in true) exec 2>/dev/null;; esac
    
        google-chrome --headless --disable-gpu --dump-dom \
            "$RobWebAddress" > "$DownloadName"
    )
    

    Após o fechamento ), o erro padrão é de fato restaurado para o que era antes, porque ele está realmente sendo redirecionado apenas no subshell, e não no shell pai. Isso também funciona bem com as variáveis ​​de shell existentes, pois os subshells obtêm uma cópia delas. Embora eu prefira usar uma função shell, admito que esse método pode exigir menos código.

    Ambos os métodos funcionam independentemente de como o erro padrão de arquivo ou dispositivo começa, inclusive no caso de redirecionamentos aplicados a funções de shell que chamam o código que contém o comportamento condicional, bem como o caso (mencionado em sua edição) em que erro padrão para todo o script já foi redirecionado por um arquivo anterior ou . Que o caminho foi produzido por substituição de processo não é problema.exec 2>&fdexec 2> path

    • 20
  2. ilkkachu
    2019-08-28T07:18:53+08:002019-08-28T07:18:53+08:00

    Por que um argumento codificado funciona, mas não um argumento como variável?

    Porque os itens de sintaxe não são interpretados a partir de valores de variáveis ​​expandidas. Ou seja, expansão de variável não é o mesmo que substituir a referência de variável pelo texto da variável na linha de comando. (Coisas como ;, |, &&e aspas etc. também não são especiais nos valores das variáveis.)

    O que você pode fazer é usar aliases ou usar a variável para manter apenas o destino do redirecionamento.

    Os aliases são apenas uma substituição de texto, para que possam conter itens sintáticos, como operadores e palavras-chave. Em um script, você precisaria shopt expand_aliases, pois por padrão eles estão desabilitados em shells não interativos. Então, isso imprime 2(somente):

    #!/bin/bash
    shopt -s expand_aliases
    
    alias redir='> /dev/null'
    redir echo 1
    alias redir=''
    redir echo 2
    

    (E você também pode alias jos=if niin=then soj=fiescrever todas as suas declarações if em finlandês. Tenho certeza de que qualquer pessoa que leia o roteiro adoraria você.)

    Como alternativa, escreva o redirecionamento sempre, mas controle apenas o destino com uma variável. Você precisará de um destino sem operação para o caso em que não deseja alterar para onde a saída vai, mas /dev/stderrdeve funcionar nesse caso. Na verdade, adicionar 2> /dev/stderrnão é uma operação proibida por causa da maneira como o Linux trata os fd's abertos /proc/<pid>/fdcomo independentes do original. Isso afeta o posicionamento da posição de gravação e atrapalha a saída se for para um arquivo normal.

    No entanto, deve funcionar no modo de acréscimo (ou se stderr for para um pipe ou para um terminal):

    #!/bin/sh
    exec 2>/tmp/error.log
    dst=/dev/null
    ls -l /nosuchfile-1 2>> "$dst"     # this doesn't print
    dst=/dev/stderr
    ls -l /nosuchfile-2 2>> "$dst"
    ls -l /nosuchfile-3 2>> "$dst"
    

    Então, para repetir: 2> /dev/stderrpode quebrar.

    • 5
  3. Joshua
    2019-08-28T18:04:44+08:002019-08-28T18:04:44+08:00

    Título da pergunta: "Como passar 2>/dev/null como uma variável?" Isso pode realmente ser feito usandoeval

    joshua@nova:/tmp$ X=">/dev/null"
    joshua@nova:/tmp$ echo $X
    >/dev/null
    joshua@nova:/tmp$ eval echo $X
    joshua@nova:/tmp$ eval echo hi
    hi
    joshua@nova:/tmp$ eval echo hi $X
    joshua@nova:/tmp$ echo hi $X
    hi >/dev/null
    joshua@nova:/tmp$ 
    

    Então podemos reescrever como

    # Hide irrelevant errors so chrome doesn't email us in cron
    local HideErrors
    local RobWebAddress2
    local DownloadName2
    [[ $fCron == true ]] && HideErrors="2>/dev/null"
    RobWebAddress2='"$RobWebAddress"'
    DownloadName2='>"$DownloadName"'
    
    eval google-chrome --headless --disable-gpu --dump-dom \
        $RobWebAddress2 $DownloadName2 "$HideErrors"
    

    Onde o acesso à variável indireta impede que a expansão aconteça muito cedo no restante da linha de comando.

    Aspas duplas em variáveis ​​funcionam bem.

    joshua@nova:/tmp$ X='"'
    joshua@nova:/tmp$ Y='$X'
    joshua@nova:/tmp$ eval echo $Y
    "
    joshua@nova:/tmp$ 
    
    • 2

relate perguntas

Sidebar

Stats

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

    Existe um comando para listar todos os usuários? Também para adicionar, excluir, modificar usuários, no terminal?

    • 9 respostas
  • Marko Smith

    Como excluir um diretório não vazio no Terminal?

    • 4 respostas
  • Marko Smith

    Como descompactar um arquivo zip do Terminal?

    • 9 respostas
  • Marko Smith

    Como instalo um arquivo .deb por meio da linha de comando?

    • 11 respostas
  • Marko Smith

    Como instalo um arquivo .tar.gz (ou .tar.bz2)?

    • 14 respostas
  • Marko Smith

    Como listar todos os pacotes instalados

    • 24 respostas
  • Martin Hope
    Flimm Como posso usar o docker sem sudo? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    led-Zepp Como faço para salvar a saída do terminal em um arquivo? 2014-02-15 11:49:07 +0800 CST
  • Martin Hope
    ubuntu-nerd Como descompactar um arquivo zip do Terminal? 2011-12-11 20:37:54 +0800 CST
  • Martin Hope
    TheXed Como instalo um arquivo .deb por meio da linha de comando? 2011-05-07 09:40:28 +0800 CST
  • Martin Hope
    Ivan Como listar todos os pacotes instalados 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    David Barry Como determino o tamanho total de um diretório (pasta) na linha de comando? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher "Os seguintes pacotes foram retidos:" Por que e como resolvo isso? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford Como os PPAs podem ser removidos? 2010-07-30 01:09:42 +0800 CST

Hot tag

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

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