Quando sei alleato di alligatori, è facile dimenticare che l'obiettivo era drenare la palude.
- detto popolare
La domanda è circa echo
, eppure la maggior parte delle risposte finora si è concentrata su come intrufolare un set +x
comando. C'è una soluzione molto più semplice e diretta:
{ echo "Message"; } 2> /dev/null
(Riconosco che potrei non aver pensato al { …; } 2> /dev/null
se non l'avessi visto nelle risposte precedenti.)
Questo è un po 'ingombrante, ma, se hai un blocco di echo
comandi consecutivi , non è necessario farlo singolarmente:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Nota che non hai bisogno di punti e virgola quando hai nuove righe.
Puoi ridurre l'onere della digitazione usando l'idea
di kenorb di aprirsi /dev/null
permanentemente su un descrittore di file non standard (ad es. 3) e poi dire 2>&3
invece che 2> /dev/null
sempre.
Le prime quattro risposte al momento della stesura di questo articolo richiedono di fare qualcosa di speciale (e, nella maggior parte dei casi, ingombrante)
ogni volta che lo fai echo
. Se vuoi davvero che tutti i echo
comandi sopprimano la traccia dell'esecuzione (e perché non lo faresti?), Puoi farlo a livello globale, senza mungere molto codice. Innanzitutto, ho notato che gli alias non vengono tracciati:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Si noti che i seguenti frammenti di script funzionano se lo shebang lo è #!/bin/sh
, anche se /bin/sh
è un collegamento a bash. Ma, se lo è lo shebang #!/bin/bash
, è necessario aggiungere un shopt -s expand_aliases
comando per far funzionare gli alias in uno script.)
Quindi, per il mio primo trucco:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Ora, quando diciamo echo "Message"
, chiamiamo l'alias, che non viene tracciato. L'alias disattiva l'opzione di traccia, mentre sopprime il messaggio di traccia dal set
comando (utilizzando la tecnica presentata prima nella risposta dell'utente 5071535 ), quindi esegue il echo
comando effettivo . Questo ci consente di ottenere un effetto simile a quello della risposta dell'utente 5071535 senza la necessità di modificare il codice ad ogni echo
comando. Tuttavia, questo lascia la modalità di traccia disattivata. Non possiamo inserire a set -x
nell'alias (o almeno non facilmente) perché un alias consente solo di sostituire una stringa con una parola; nessuna parte della stringa di alias può essere iniettata nel comando
dopo gli argomenti (es., "Message"
). Quindi, ad esempio, se lo script contiene
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
l'output sarebbe
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
quindi è ancora necessario riattivare l'opzione di traccia dopo aver visualizzato i messaggi, ma solo una volta dopo ogni blocco di echo
comandi consecutivi :
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Sarebbe bello se potessimo fare l' set -x
automatico dopo un echo
- e possiamo, con un po 'più di inganno. Ma prima di presentarlo, considera questo. L'OP sta iniziando con script che usano un #!/bin/sh -ex
shebang. Implicitamente l'utente potrebbe rimuovere il x
da shebang e avere uno script che funzioni normalmente, senza traccia di esecuzione. Sarebbe bello se potessimo sviluppare una soluzione che mantenga quella proprietà. Le prime poche risposte qui non riescono a quella proprietà perché attivano la traccia "indietro" dopo le echo
istruzioni, incondizionatamente, senza considerare se fosse già attiva.
Questa risposta evidentemente non riesce a riconoscere quel problema, in quanto sostituisce echo
output con output trace; pertanto, tutti i messaggi scompaiono se la traccia è disattivata. Presenterò ora una soluzione che riattiva la traccia dopo echo
un'affermazione condizionata - solo se era già attiva. Il downgrade a una soluzione che riattiva incondizionatamente la traccia è banale e viene lasciato come un esercizio.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
è l'elenco delle opzioni; una concatenazione delle lettere corrispondente a tutte le opzioni impostate. Ad esempio, se sono impostate le opzioni e
e x
, allora $-
sarà un miscuglio di lettere che include e
e x
. Il mio nuovo alias (sopra) salva il valore di $-
prima di disattivare la traccia. Quindi, con la traccia disattivata, passa il controllo in una funzione shell. Tale funzione esegue l'effettivo echo
e quindi verifica se l' x
opzione è stata attivata quando è stato invocato l'alias. Se l'opzione era attiva, la funzione la riattiva; se era spento, la funzione lo interrompe.
Puoi inserire le sette righe sopra (otto, se includi una shopt
) all'inizio dello script e lasciare il resto da solo.
Questo ti permetterebbe
- usare una delle seguenti linee shebang:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
o semplicemente#! / Bin / sh
e dovrebbe funzionare come previsto.
- avere un codice simile
(shebang)
comando 1
comando 2
comando 3
set -x
comando 4
comando 5
comando 6
imposta + x
comando 7
comando 8
comando 9
e
- I comandi 4, 5 e 6 verranno tracciati, a meno che uno di essi non sia un
echo
, nel qual caso verrà eseguito ma non tracciato. (Ma anche se il comando 5 è un echo
, il comando 6 verrà comunque rintracciato.)
- I comandi 7, 8 e 9 non verranno tracciati. Anche se il comando 8 è un
echo
, il comando 9 non verrà ancora tracciato.
- I comandi 1, 2 e 3 verranno tracciati (come 4, 5 e 6) o meno (come 7, 8 e 9) a seconda che includa lo shebang
x
.
PS Ho scoperto che, sul mio sistema, posso tralasciare la builtin
parola chiave nella mia risposta intermedia (quella che è solo un alias per echo
). Questo non è sorprendente; bash (1) afferma che, durante l'espansione dell'alias, ...
... una parola identica a un alias che viene espanso non viene espansa una seconda volta. Questo significa che si può alias ls
a ls -F
, per esempio, e bash non tenta di espandere ricorsivamente il testo di sostituzione.
Non sorprendentemente, l'ultima risposta (quella con echo_and_restore
) fallisce se la builtin
parola chiave viene omessa 1 . Ma stranamente funziona se elimino builtin
e cambio l'ordine:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Sembra dare origine a comportamenti indefiniti. ho visto
- un ciclo infinito (probabilmente a causa della ricorsione illimitata),
- un
/dev/null: Bad address
messaggio di errore e
- una discarica principale.
echo +x; echo "$*"; echo -x
un alias, mi piacerebbe vederlo.