eco que gera para stderr

1116

Existe uma ferramenta Bash padrão que age como eco, mas gera stderr em vez de stdout?

Eu sei que posso fazer, echo foo 1>&2mas é meio feio e, suspeito, propenso a erros (por exemplo, é mais provável que seja editado errado quando as coisas mudam).

BCS
fonte

Respostas:

1454

Você poderia fazer isso, o que facilita a leitura:

>&2 echo "error"

>&2copia o descritor de arquivo nº 2 para o descritor de arquivo nº 1. Portanto, depois que esse redirecionamento é realizado, os dois descritores de arquivo se referem ao mesmo arquivo: o descritor de arquivo nº 2 estava originalmente se referindo. Para obter mais informações, consulte o Tutorial de redirecionamento ilustrado do Bash Hackers .

Marco Aurelio
fonte
2
Eu aprendi esse truque há algum tempo. Esta página contém algumas informações boas. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio
46
@BCS Eu não sei sobre o uso de um aliasscript em shell. Provavelmente seria mais seguro usarerrcho(){ >&2 echo $@; }
Braden Melhor
3
> & 2 é normalmente colocado no final. Isto irá funcionar, mas o seu usado com menos frequência
Iskren Ivov Chernev
159
Nos quase 40 anos em que eu uso sistemas semelhantes ao Unix, nunca me ocorreu que você pudesse colocar o redirecionamento em qualquer lugar, exceto no final. Colocá-lo na frente assim torna muito mais óbvio (ou "facilita a leitura", como @MarcoAurelio diz). +1 por me ensinar algo novo.
Hefesto
FYI: se você deseja formatar ou fazer qualquer coisa além de simplesmente ecoar a string, precisará mover o redirecionamento de volta ao final. Por exemplo errcho(){ >&2 echo $@|pr -To5;}, não vai funcionar. Para fazer algo assim, você terá que colocar o redirecionamento em algum lugar após o último canal, como:errcho(){ echo $@|>&2 pr -To5;}
Jon Red
424

Você pode definir uma função:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Isso seria mais rápido que um script e não terá dependências.

A sugestão específica do bash de Camilo Martin usa uma "string aqui" e imprime qualquer coisa que você passar, incluindo argumentos (-n) que o eco normalmente engoliria:

echoerr() { cat <<< "$@" 1>&2; }

A solução de Glenn Jackman também evita o problema da deglutição:

echoerr() { printf "%s\n" "$*" >&2; }
James Roth
fonte
7
Devo dizer que o eco não é confiável. echoerr -ne xtnão vai imprimir "-ne xt". Melhor uso printfpara isso.
Camilo Martin
10
Oh, você pode realmente usar gato também:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin
2
Eu não estava ciente disso. Adicionado.
James Roth.
4
Ou,printf "%s\n" "$*" >&2
Glenn Jackman
4
@GKFX É claro que só funciona corretamente ao citar. Por que as pessoas não citam suas cordas está além de mim. (quando você não cita, tudo separado por um ou mais $IFSespaços em branco é enviado como um argumento separado, que, no caso deecho concatená-los com 0x20s, mas os perigos de não citar superam em muito a conveniência de digitar menos dois caracteres) .
Camilo Martin
252

Como 1é a saída padrão, você não precisa nomeá-la explicitamente na frente de um redirecionamento de saída, >mas sim, simplesmente digitar:

eco Esta mensagem vai para stderr> & 2

Como você parece estar preocupado com a 1>&2dificuldade de digitar com segurança, a eliminação do redundante 1pode ser um pequeno incentivo para você!

Brandon Rhodes
fonte
59

Outra opção

echo foo >>/dev/stderr
Steven Penny
fonte
4
Esta opção é portátil? Alguém sabe se isso não está funcionando para algum sabor unix?
Dacav
7
Ele não funciona em certos chroots, que não podem acessar / dev / stderr.
Zachary Vance
12
Se o script que executa esta linha - vamos chamá-lo foo- tem seu próprio stderr redirecionado - por exemplo foo >foo.log 2>&1-, então echo foo >/dev/stderrirá sobrecarregar toda a saída anterior. >>deve ser usado:echo foo >>/dev/stderr
doshea
Da mesma forma, você tem /dev/fd/2.
precisa saber é o seguinte
@Dacav este é com certeza portátil: /proc/self/fd/2. Veja minha resposta abaixo :)
Sebastian
31

Não, essa é a maneira padrão de fazer isso. Não deve causar erros.

Matthew Flaschen
fonte
9
Não deve causar erros, mas é mais provável que eu o faça. OTOH não é grande coisa.
BCS
6
@ Mike DeSimone: Se alguém mexer com o código, embaralhar a saída e realmente não souber o bash, ele poderá facilmente soltar (ou digitar errado) o 1>&2. Todos desejamos que isso não aconteça, mas tenho certeza de que todos já fomos lugares onde isso acontece.
Cascabel
2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logOpa.
BCS
29
IMHO, se alguém mexe com o código e não sabe bash, este pode ser o menor dos seus problemas.
Mike DeSimone
7
Acho que, se é provável que isso seja um problema, você deve começar a usar um idioma diferente: tentar tornar o bash infalível é um empreendimento de tolos.
intuited
17

Se você não se importa de registrar a mensagem também no syslog, a maneira not_so_ugly é:

logger -s $msg

A opção -s significa: "Envie a mensagem para o erro padrão e também para o log do sistema".

Grzegorz Luczywo
fonte
1
isso é ótimo! quão portátil é?
Code_monk 28/07
@code_monk: O comando logger é esperado para ser IEEE Std 1003.2 ( "POSIX.2") compatível, o comando logger é parte do pacote util-linux e está disponível a partir do Linux Kernel Archive ⟨ kernel.org/pub/linux/utils / util- linux⟩.
Miku
12

Essa é uma função STDERR simples, que redireciona a entrada do tubo para STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err
erselbst
fonte
2
Eu acho que você pode fazer a mesma coisa com alias e ser muito mais compacto
BCS
ou você pode simplesmente canalizar diretamente para o arquivo do dispositivo echo what | /dev/stderr...
ardnew
11

Nota: Estou respondendo à pergunta pós-não-enganosa / vaga "eco que gera stderr" (já respondida pelo OP).

Use uma função para mostrar a intenção e obter a implementação que você deseja. Por exemplo

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

E error_handlingsendo:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Razões que tratam das preocupações no OP:

  • sintaxe mais agradável possível (palavras significativas em vez de símbolos feios)
  • mais difícil cometer um erro (especialmente se você reutilizar o script)
  • não é uma ferramenta Bash padrão, mas pode ser uma biblioteca shell padrão para você ou sua empresa / organização

Outras razões:

  • clareza - mostra a intenção de outros mantenedores
  • speed - as funções são mais rápidas que os scripts shell
  • reutilização - uma função pode chamar outra função
  • configurabilidade - não é necessário editar o script original
  • depuração - é mais fácil encontrar a linha responsável por um erro (especialmente se você está lidando com uma tonelada de saída de redirecionamento / filtragem)
  • robustez - se uma função estiver ausente e você não puder editar o script, poderá voltar a usar uma ferramenta externa com o mesmo nome (por exemplo, log_error pode ser um alias para o logger no Linux)
  • alternando implementações - você pode alternar para ferramentas externas removendo o atributo "x" da biblioteca
  • agnóstico de saída - você não precisa mais se preocupar se vai para STDERR ou outro local
  • personalização - você pode configurar o comportamento com variáveis ​​de ambiente
Cezary Baginski
fonte
10

Minha sugestão:

echo "my errz" >> /proc/self/fd/2

ou

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2vai efetivamente saída para stderrporque /proc/selfé um link para o processo atual, e /proc/self/fddetém o processo aberto descritores de arquivo, e em seguida, 0, 1e 2representam stdin, stdoutestderr respectivamente.

O /proc/selflink não funciona no MacOS, no entanto, /proc/self/fd/*está disponível no Termux no Android, mas não /dev/stderr. Como detectar o SO de um script Bash? pode ajudar se você precisar tornar seu script mais portátil, determinando qual variante usar.

Sebastian
fonte
5
O /proc/selflink não funciona no MacOS, portanto, continuarei com o /dev/stderrmétodo mais direto . Além disso, como observado em outras respostas / comentários, provavelmente é melhor usar >>para acrescentar.
MarkHu
4
/proc/self/fd/*está disponível no Termux no Android, mas não /dev/stderr.
Go2null
9

Não use, catpois alguns são mencionados aqui. caté um programa while echoe printfsão bash (shell) embutidos. Iniciar um programa ou outro script (também mencionado acima) significa criar um novo processo com todos os seus custos. Usando builtins, as funções de escrita são bastante baratas, porque não há necessidade de criar (executar) um processo (ambiente).

O opner pergunta "existe alguma ferramenta padrão para enviar ( pipe ) ao stderr", a resposta do schort é: NÃO ... por quê? ... rediredcting pipes é um conceito elemantário em sistemas como o unix (Linux ...) e o bash (sh) se baseia nesses conceitos.

Eu concordo com o abridor de que redirecionar com notações como esta: &2>1não é muito agradável para programadores modernos, mas isso é uma loucura. O Bash não teve a intenção de escrever programas enormes e robustos, mas sim ajudar os administradores a trabalhar com menos pressionamentos de tecla ;-)

E pelo menos, você pode colocar o redirecionamento em qualquer lugar da linha:

$ echo This message >&2 goes to stderr 
This message goes to stderr
return42
fonte
1
Dizer aos desenvolvedores para não usarem programas apenas por motivos de desempenho é uma otimização prematura. As abordagens elegantes e fáceis de seguir devem ser preferidas ao código difícil de entender, com melhor desempenho (da ordem de milissegundos).
18719 GuyPaddock
@GuyPaddock desculpe, você não leu isso corretamente. Abetos; É sobre o redirecionamento de pipes, que é bem tratado pelo bash. Se alguém não gostar da sintaxe (feia) de como o bash é redirecionado, deve parar de implementar os scripts do bash ou aprender o caminho do bash. Segundo; você deve saber o quanto é caro lançar um novo processo em comparação com o chamado de bash builtin.
return42
1
Há uma diferença entre informar alguém sobre as vantagens e desvantagens do desempenho do Bash vs cate instruir alguém a não usar gato porque é lento. Existem inúmeros casos de uso em que gato é a escolha certa, por isso oponho-me à sua resposta.
22819 GuyPaddock
@GuyPaddock O abridor pediu uma echosubstituição. Mesmo se ele usar cat, ele precisará usar um redirecionamento do bash. de qualquer forma. Portanto, não há absolutamente nenhum sentido em usar cataqui. BTW eu uso cat100 vezes por dia, mas nunca no contexto que a abertura pediu ... você entendeu?
return42
8

Outra opção que encontrei recentemente é a seguinte:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Isso usa apenas os integrados do Bash e, ao mesmo tempo, torna a saída de erro de várias linhas menos propensa a erros (já que você não precisa se lembrar de adicionar &>2a todas as linhas).

GuyPaddock
fonte
1
Não posso acreditar, você me rejeita quando recomendo usar o bash-redirect e, em sua própria resposta, você está usando o bash-redirect.
return42
1
@ return42 Votei sua resposta para baixo, porque tudo o que fez foi dizer ao OP que não há resposta melhor do que a que eles começaram .. não é realmente uma resposta. Também não vejo uma sugestão subconcha na sua resposta ... sua resposta realmente aconselha o OP a não usar catou qualquer outro utilitário, o que é fora de tópico para a pergunta.
GuyPaddock
6

read é um comando interno do shell que imprime no stderr e pode ser usado como eco sem executar truques de redirecionamento:

read -t 0.1 -p "This will be sent to stderr"

A -t 0.1é um tempo de espera que desactiva de funcionalidade principal ler, armazenar uma linha de entrada padrão para uma variável.

Douglas Mayle
fonte
5
Bash no OS X não permite que o "0.1"
James Roth
2

Faça um script

#!/bin/sh
echo $* 1>&2

essa seria sua ferramenta.

Ou crie uma função se você não quiser ter um script em arquivo separado.

n0rd
fonte
6
Melhor que seja uma função (como a resposta de James Roth) e melhor transmitir todos os argumentos, não apenas o primeiro.
Cascabel
2
Por que uma função seria melhor? (Ou, alternativamente: "Melhor explicar por que seria melhor ...")
Ogre Salmo33
3
@ OgrePsalm33 Uma razão pela qual uma função seria melhor é que, ao chamar um script, geralmente uma nova instância do shell é criada para fornecer um ambiente no qual o script é executado. Uma função, por outro lado, é colocada no ambiente do shell atualmente em execução. Chamar uma função, nesse caso, seria uma operação muito mais eficiente, pois a criação de outra instância de um shell seria evitada.
destenson
-10

Mac OS X: Tentei a resposta aceita e algumas outras respostas, e todas resultaram na criação de STDOUT e não de STDERR no meu Mac.

Aqui está uma maneira portátil de gravar em erro padrão usando o Perl:

echo WARNING! | perl -ne 'print STDERR'
Noah Sussman
fonte
lol diminuiu o voto para tudo o que você quer, mas esta é a solução que eu realmente uso no meu código!
Noah Sussman