Skrypt Bash-przechowuje stderr w zmiennej [duplikat]

To pytanie ma już odpowiedź tutaj:

Piszę skrypt do tworzenia kopii zapasowej bazy danych. Mam następujący wiersz:

mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb | gzip > $filename

Chcę przypisać stderr do zmiennej, tak, że wyśle do mnie e-mail z informacją, co się stało, jeśli coś pójdzie nie tak. Znalazłem rozwiązania przekierowujące stderr na stdout, ale nie mogę tego zrobić, ponieważ stdout jest już wysyłany (przez gzip) do pliku. Jak mogę oddzielnie przechowywać stderr w zmiennej $result ?

Author: codeforester, 2010-06-28

4 answers

Spróbuj przekierować stderr na stdout i użyj $(), aby to przechwycić. Innymi słowy:

VAR=$((your-command-including-redirect) 2>&1)

Ponieważ twoje polecenie przekierowuje gdzieś stdout, nie powinno zakłócać stderr. Może jest lepszy sposób na napisanie tego, ale to powinno zadziałać.

Edit:

To naprawdę działa. Testowałem:
#!/bin/bash                                                                                                                                                                         
BLAH=$((
(
echo out >&1
echo err >&2
) 1>log
) 2>&1)

echo "BLAH=$BLAH"

Wydrukuje BLAH=err, a Plik log zawiera out.

 68
Author: Adam Crume,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 06:29:45

Dla dowolnego ogólnego polecenia w Bash, możesz zrobić coś takiego:

{ error=$(command 2>&1 1>&$out); } {out}>&1

Zwykłe wyjście wygląda normalnie, wszystko na stderr jest przechwytywane w $error (cudzysłów jako "$error" podczas używania go do zachowania nowych linii). Aby przechwycić stdout do pliku, po prostu dodaj przekierowanie na końcu, na przykład:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output

Rozbicie go, Czytanie z zewnątrz w, to:

  • tworzy opis pliku $out dla całego bloku, duplikując stdout
  • przechwytuje stdout z Cała komenda w $error (patrz niżej)
  • samo polecenie przekierowuje stderr do stdout (który jest przechwytywany powyżej), a następnie stdout do oryginalnego stdout spoza bloku, więc tylko stderr jest przechwytywany
 13
Author: Joat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-12 00:44:58

Możesz zapisać referencję stdout przed przekierowaniem do innego numeru pliku (np. 3), a następnie przekierować stderr do tego:

result=$(mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename)

Więc 3>&1 przekieruje plik numer 3 na stdout (zauważ, że jest to zanim stdout zostanie przekierowany z rurką). Następnie 2>&3 przekierowuje stderr do pliku numer 3, który teraz jest taki sam jak stdout. W końcu stdout jest przekierowywany przez wprowadzenie do rury, ale nie ma to wpływu na numery Plików 2 i 3 (zauważ, że przekierowanie stdout z gzip nie jest powiązane do wyjść z polecenia mysqldump).

Edit: zaktualizowałem polecenie, aby przekierować stderr z mysqldump, a nie gzip, byłem zbyt szybki w pierwszej odpowiedzi.

 4
Author: hlovdal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 06:58:40

dd zapisuje zarówno stdout jak i stderr:

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in
50+0 records out

Oba strumienie są niezależne i osobno przekierowywalne:

$ dd if=/dev/zero count=50 2> countfile | wc -c
25600
$ cat countfile 
50+0 records in
50+0 records out
$ mail -s "countfile for you" thornate < countfile

Jeśli naprawdę potrzebujesz zmiennej:

$ variable=`cat countfile`
 0
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-28 06:22:07