bash: usa una variabile per memorizzare il reindirizzamento stderr | stdout


17

Esiste un modo per reindirizzare stdout e stderr tramite una variabile come l'aggiunta di opzioni di comando nello script?

Ad esempio ho uno script:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

Vedo che OPT viene sostituito -psenza problemi e Bash lo interpreta come opzione. Ma il reindirizzamento interpreta il nome delle directory.

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

C'è un modo per dire bash, che $ VAR è il reindirizzamento, non i nomi di una directory.

PS. Forse sto sbagliando, ma voglio fare un output dettagliato o non dettagliato dal mio script. Ma ho bisogno di un output anche in modalità non dettagliata, quindi non posso semplicemente reindirizzare l'intero stdout e stderr, solo da alcuni comandi all'interno del mio script.

Risposte:


18

Un'altra soluzione potrebbe essere la seguente:

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

Quindi aggiungere 1>&3 2>&4solo ai comandi di cui si desidera vedere l'output.


Grande. Questa è esattamente la cosa che ho cercato. Grazie.
precipita il

Ho scritto un articolo per spiegare come funziona
tradotto il

5

Il "come" è stato ben spiegato in altre risposte; Voglio affrontare il "perché" il codice del PO non funziona.

Il keynote è che i reindirizzamenti di output sono contrassegnati prima dell'espansione variabile. I reindirizzamenti vengono effettivamente eseguiti dopo l'espansione delle variabili (quindi perché è possibile reindirizzare l'output su un nome file memorizzato in una variabile), ma la shell identifica i reindirizzamenti per l'elaborazione successiva prima dell'espansione delle variabili.

In altre parole, una volta espanse le variabili è "troppo tardi" per considerare un carattere di reindirizzamento ( <o >, ecc.), Poiché la shell ha già identificato quali parti della stringa di comando gestirà come reindirizzamenti.

Per ulteriori letture, vedere i passaggi 1 e 3 elencati sotto:

LESS='+/^SIMPLE COMMAND EXPANSION' man bash

3

Non lo sta interpretando come un "nome di directory", >viene citato, quindi viene trattato alla lettera (in particolare, si sta inviando la stringa >dev/null 2>&1. L'unico modo per aggirare il problema è usare evalo generare una nuova shell.

Per quanto riguarda il problema "dettagliato" a cui si fa riferimento nella domanda, basta invece fare questo:

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi

1

Hai molti spazi nelle tue variabili, che non saranno valutate correttamente. Ti consigliamo di usarlo evalper configurarlo.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

Ciò consentirà di dividere $ OPT in due argomenti ( -pe -v) anziché in uno ( -p -v) e lo stesso con $ TEST. Anche cambiato per usare /dev/nullpoiché è molto improbabile che tu abbia una devdirectory nella directory corrente.


0

La risposta di enzotib usa un po 'di magia descrittore di file buono, ma una soluzione più semplice sarebbe quella di utilizzare solo evalla linea (che fa in testa processo di aggiunta, però):

$ rm /tmp/foo
$ ll /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
$ FOO=">/tmp/foo"
$ date $FOO
date: invalid date '>/tmp/foo'
$ cat /tmp/foo
cat: /tmp/foo: No such file or directory
$ eval date $FOO
$ cat /tmp/foo
Thu Dec 13 14:08:17 EST 2018
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.