eco che emette su stderr


1116

Esiste uno strumento Bash standard che agisce come l'eco ma genera su stderr anziché su stdout?

So di poterlo fare, echo foo 1>&2ma è un po 'brutto e, sospetto, soggetto a errori (ad esempio, è più probabile che venga modificato in modo errato quando le cose cambiano).


Risposte:


1454

Potresti farlo, il che facilita la lettura:

>&2 echo "error"

>&2copia il descrittore di file n. 2 nel descrittore di file n. 1. Pertanto, dopo aver eseguito questo reindirizzamento, entrambi i descrittori di file faranno riferimento allo stesso file: l'unico descrittore di file n. 2 si riferiva originariamente . Per ulteriori informazioni, consultare il tutorial di reindirizzamento illustrato di Bash Hackers .


2
Ho imparato questo trucco un po 'di tempo fa. Questa pagina contiene alcune buone informazioni. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio,

46
@BCS Non so usare un aliasscript in shell. Probabilmente sarebbe più sicuro da usareerrcho(){ >&2 echo $@; }
Braden Best

3
> & 2 viene normalmente messo alla fine.
Funzionerà

159
Nei quasi 40 anni in cui ho usato sistemi simili a Unix, non mi è mai venuto in mente che potresti reindirizzare ovunque ma alla fine. Metterlo in primo piano in questo modo lo rende molto più ovvio (o "facilita la lettura" come dice @MarcoAurelio). +1 per avermi insegnato qualcosa di nuovo.
Efesto,

Cordiali saluti: se vuoi formattare o fare qualcosa oltre a far eco alla stringa, dovrai spostare il reindirizzamento alla fine. Ad esempio errcho(){ >&2 echo $@|pr -To5;}non funzionerà. Per fare una cosa del genere dovrai mettere il reindirizzamento da qualche parte dopo l'ultima pipa come:errcho(){ echo $@|>&2 pr -To5;}
Jon Red

424

È possibile definire una funzione:

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

Questo sarebbe più veloce di uno script e non ha dipendenze.

Il suggerimento specifico di bash di Camilo Martin usa una "stringa qui" e stamperà tutto ciò che gli passa, inclusi argomenti (-n) che l'eco normalmente inghiottirebbe:

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

La soluzione di Glenn Jackman evita anche l'argomento deglutizione argomento:

echoerr() { printf "%s\n" "$*" >&2; }

7
Devo dire che l'eco non è affidabile. echoerr -ne xtnon stampa "-ne xt". Meglio usare printfper quello.
Camilo Martin,

10
Oh, puoi davvero usare anche il gatto:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin,

2
Non ne ero a conoscenza. Aggiunto.
James Roth,

4
Oppure,printf "%s\n" "$*" >&2
Glenn Jackman,

4
@GKFX Naturalmente funziona correttamente solo durante la quotazione. Il motivo per cui le persone non citano le loro corde è oltre me. (quando non citate, tutto ciò che è separato da uno o più $IFSspazi bianchi viene inviato come argomento separato, che nel caso dei echomezzi li concatena con 0x20s, ma i pericoli di non quotare superano di gran lunga la comodità di 2 caratteri in meno da digitare) .
Camilo Martin,

252

Poiché 1è l'output standard, non è necessario nominarlo esplicitamente di fronte a un reindirizzamento dell'output come, >ma invece è sufficiente digitare:

echo Questo messaggio va a stderr> & 2

Dal momento che sembri preoccupato che 1>&2sarà difficile digitare in modo affidabile, l'eliminazione del ridondante 1potrebbe essere un leggero incoraggiamento per te!


59

Un'altra opzione

echo foo >>/dev/stderr

4
Questa opzione è portatile? Qualcuno sa se questo non funziona per un po 'di sapore unix?
Dacav,

7
Non funziona in alcuni chroot, che non possono accedere a / dev / stderr.
Zachary Vance,

12
Se lo script che esegue questa linea - chiamiamolo foo- ha il suo reindirizzamento stderr - ad esempio foo >foo.log 2>&1- allora echo foo >/dev/stderrbloccherà tutto l'output prima di esso. >>dovrebbe essere usato invece:echo foo >>/dev/stderr
doshea,

Allo stesso modo, hai /dev/fd/2.
jbruni,

@Dacav questo è certo portatile: /proc/self/fd/2. Vedi la mia risposta di seguito :)
Sebastian

31

No, questo è il modo standard per farlo. Non dovrebbe causare errori.


9
Non dovrebbe causare errori, ma potrei essere più probabile. OTOH non è un grosso problema.
BCS

6
@Mike DeSimone: se qualcun altro fa pasticciare con il codice, mescola l'output e in realtà non conosce bash, potrebbe facilmente rilasciare (o digitare male) il file 1>&2. Tutti desideriamo che ciò non accada, ma sono sicuro che siamo stati tutti posti dove succede.
Cascabel,

2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logOops.
BCS

29
IMHO, se qualcuno sbaglia il codice e non conosce bash, questo potrebbe essere l'ultimo dei tuoi problemi.
Mike DeSimone,

7
Penso che se questo è probabilmente un problema, dovresti iniziare a usare una lingua diversa: provare a rendere bash infallibile è un'impresa da pazzi.
intuito il

17

Se non ti dispiace registrare il messaggio anche su syslog, il modo not_so_ugly è:

logger -s $msg

L'opzione -s significa: "Invia il messaggio all'errore standard e al registro di sistema".


1
è fantastico! quanto è portatile?
code_monk,

@code_monk: il comando logger dovrebbe essere compatibile con IEEE Std 1003.2 ("POSIX.2"), il comando logger fa parte del pacchetto util-linux ed è disponibile dall'archivio del kernel Linux ⟨kernel.org/pub/linux/utils / util- linux⟩.
Miku,

12

Questa è una semplice funzione STDERR, che reindirizza l'input della pipe su 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

2
Penso che puoi fare la stessa cosa con l'alias ed essere molto più compatto
BCS

oppure puoi semplicemente reindirizzare direttamente al file del dispositivo echo what | /dev/stderr...
ardnew,

11

Nota: sto rispondendo al post, non alla domanda fuorviante / vaga "eco che emette a stderr" (già risposta dall'OP).

Utilizzare una funzione per mostrare l' intenzione e ottenere l'implementazione desiderata. Per esempio

#!/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!"

Ed error_handlingessere:

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"; }

Ragioni che gestiscono le preoccupazioni in OP:

  • la sintassi più bella possibile (parole significative anziché simboli brutti)
  • più difficile fare un errore (specialmente se riutilizzi lo script)
  • non è uno strumento Bash standard, ma può essere una libreria shell standard per te o per la tua azienda / organizzazione

Altri motivi:

  • chiarezza - mostra l'intenzione di altri manutentori
  • velocità: le funzioni sono più veloci degli script di shell
  • riusabilità: una funzione può chiamare un'altra funzione
  • configurabilità: non è necessario modificare lo script originale
  • debugging: è più facile trovare la linea responsabile di un errore (specialmente se stai lavorando con un sacco di output di reindirizzamento / filtro)
  • robustezza: se manca una funzione e non è possibile modificare lo script, è possibile ricorrere all'utilizzo di uno strumento esterno con lo stesso nome (ad es. log_error può essere modificato con il logger su Linux)
  • commutazione di implementazioni: è possibile passare a strumenti esterni rimuovendo l'attributo "x" della libreria
  • output agnostico: non devi più preoccuparti se va su STDERR o altrove
  • personalizzazione: è possibile configurare il comportamento con le variabili di ambiente

10

Il mio consiglio:

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

o

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2sarà efficacemente uscita stderrperché /proc/selfè un collegamento al processo corrente, e /proc/self/fdtiene il processo aperto descrittori di file, e poi, 0, 1, e 2riposare stdin, stdoute stderrrispettivamente.

Il /proc/selfcollegamento non funziona su MacOS, tuttavia, /proc/self/fd/*è disponibile su Termux su Android, ma non /dev/stderr. Come rilevare il sistema operativo da uno script Bash? può aiutarti se devi rendere il tuo script più portatile determinando quale variante usare.


5
Il /proc/selfcollegamento non funziona su MacOS, quindi continuerò con il /dev/stderrmetodo più diretto . Inoltre, come notato in altre risposte / commenti, è probabilmente meglio usare >>per aggiungere.
MarkHu,

4
/proc/self/fd/*è disponibile su Termux su Android, ma non /dev/stderr.
go2null

9

Non usare catcome alcuni sono menzionati qui. catè un programma mentre echoe printfsono builtin bash (shell). Lanciare un programma o un altro script (anche menzionato sopra) significa creare un nuovo processo con tutti i suoi costi. Usando i builtin, le funzioni di scrittura sono abbastanza economiche, perché non è necessario creare (eseguire) un processo (-ambiente).

L'opner chiede "esiste uno strumento standard per l'output ( pipe ) su stderr", la risposta schort è: NO ... perché? ... rediredcting pipe è un concetto essenziale in sistemi come unix (Linux ...) e bash (sh) si basa su questi concetti.

Sono d'accordo con l'apri che reindirizza con notazioni come questa: &2>1 non è molto piacevole per i programmatori moderni, ma è bash. Bash non aveva lo scopo di scrivere programmi enormi e robusti, ma ha lo scopo di aiutare gli amministratori a farci lavorare con meno tasti premuti ;-)

E almeno, puoi posizionare il reindirizzamento in qualsiasi punto della linea:

$ echo This message >&2 goes to stderr 
This message goes to stderr

1
Dire agli sviluppatori di non usare i programmi solo per motivi di prestazioni è l'ottimizzazione prematura. Approcci eleganti e facili da seguire dovrebbero preferire il codice difficile da capire che funziona meglio (nell'ordine dei millisecondi).
GuyPaddock,

@GuyPaddock scusa, non hai letto bene questo. Firs; Si tratta di reindirizzare i tubi che sono ben gestiti dalla bash. Se a uno non piace la (brutta) sintassi del reindirizzamento di bash, dovrebbe smettere di implementare gli script di bash o imparare il modo di bash. Secondo; dovresti sapere quanto costa lanciare un nuovo processo rispetto a quello che hai appena chiamato un built-in bash.
ritorno42

1
C'è una differenza tra far conoscere a qualcuno i compromessi prestazionali degli incorporamenti di Bash vs cate istruire qualcuno a non usare cat perché è lento. Ci sono innumerevoli casi d'uso in cui cat è la scelta giusta, quindi è per questo che mi oppongo alla tua risposta.
GuyPaddock,

@GuyPaddock L'apriporta ha chiesto una echosostituzione. Anche se usa cat, deve usare un reindirizzamento bash. Comunque. Quindi, non ha assolutamente senso usare catqui. A proposito lo uso cat100 volte al giorno, ma mai nel contesto che l'apri ha chiesto ... hai capito?
ritorno42

8

Un'altra opzione su cui mi sono imbattuto di recente è questa:

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

Questo utilizza solo i built-in di Bash, rendendo l'output di errori su più righe meno soggetto a errori (poiché non è necessario ricordare di aggiungere &>2ad ogni riga).


1
Non ci posso credere, mi voti in basso quando ti consiglio di usare bash-redirect e nella tua risposta stai usando bash-redirect.
ritorno42

1
@ return42 Ho votato a fondo la tua risposta perché tutto ciò che ha fatto è stato dire all'OP che non esiste una risposta migliore di quella con cui hanno iniziato .. non è proprio una risposta. Inoltre non vedo un suggerimento sotto-shell nella tua risposta ... la tua risposta consiglia davvero all'OP di non usare cato qualsiasi altra utilità, che è fuori tema per la domanda.
GuyPaddock,


6

read è un comando incorporato della shell che stampa su stderr e può essere usato come eco senza eseguire trucchi di reindirizzamento:

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

La -t 0.1è un timeout che disattiva funzionalità principale di leggere, memorizzare una riga di stdin in una variabile.


5
Bash su OS X non consente lo "0.1"
James Roth,

2

Crea una sceneggiatura

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

quello sarebbe il tuo strumento.

Oppure crea una funzione se non vuoi avere uno script in un file separato.


6
Meglio che sia una funzione (come la risposta di James Roth), e meglio trasmettere tutti gli argomenti, non solo il primo.
Cascabel,

2
Perché una funzione sarebbe migliore? (Oppure, in alternativa: "Meglio spiegare perché sarebbe meglio ...")
Ogre Salmo33

3
@ OgrePsalm33 Uno dei motivi per cui una funzione sarebbe migliore è che quando si chiama uno script, di solito viene creata una nuova istanza della shell per fornire un ambiente in cui eseguire lo script. Una funzione, d'altra parte, viene inserita nell'ambiente della shell attualmente in esecuzione. Chiamare una funzione, in questo caso, sarebbe un'operazione molto più efficiente poiché si eviterebbe la creazione di un'altra istanza di una shell.
destenson,

0

Combinazione di soluzioni suggerite da James Roth e Glenn Jackman

  • aggiungi il codice colore ANSI per visualizzare il messaggio di errore in rosso:
echoerr() { printf "\e[31;1m%s\e[0m\n" "$*" >&2; }

# if somehow \e is not working on your terminal, use \u001b instead
# echoerr() { printf "\u001b[31;1m%s\u001b[0m\n" "$*" >&2; }

echoerr "This error message should be RED"

-10

Mac OS X: ho provato la risposta accettata e un paio di altre risposte e tutte hanno portato a scrivere STDOUT e non STDERR sul mio Mac.

Ecco un modo portatile per scrivere sull'errore standard usando Perl:

echo WARNING! | perl -ne 'print STDERR'

lol downvote tutto ciò che vuoi, ma questa è la soluzione che effettivamente uso nel mio codice!
Noah Sussman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.