Bash-Scripting stderr и stdout - PullRequest
       18

Bash-Scripting stderr и stdout

0 голосов
/ 19 марта 2012

Я новичок в bash-скриптинге и пытаюсь понять, как все работает. Это все немного странно ..
У меня есть два сценария. Сначала этот:

#!/usr/bin/bash
#name: stderrtest0.sh
echo "on ${1}: this is an error" >&2
echo "on ${1}: this is an info" >&1
echo "on ${1}: this is just text"


И этот второй скрипт называет первый:

#!/usr/bin/bash
#name: stderrtest1.sh
echo "invoking: stderrtest0.sh test1 >&2 ~output:"
./stderrtest0.sh test1 >&2

echo "invoking: stderrtest0.sh test2 >&1 ~output:"
./stderrtest0.sh test2 >&1

echo "invoking: stderrtest0.sh test3 2>&1 ~output:"
./stderrtest0.sh test3 2>&1

echo "invoking: stderrtest0.sh test4 1>&2 ~output:"
./stderrtest0.sh test4 1>&2

echo "invoking: stderrtest0.sh test5 ~output:"
./stderrtest0.sh test5


Вот мои тесты ( debian squeeze ) с выводом:

METATEST1) invoke stderrtest1.sh

$ ./stderrtest1.sh
invoking: stderrtest0.sh test1 >&2 ~output:
on test1: this is an error
on test1: this is an info
on test1: this is just text
invoking: stderrtest0.sh test2 >&1 ~output:
on test2: this is an error
on test2: this is an info
on test2: this is just text
invoking: stderrtest0.sh test3 2>&1 ~output:
on test3: this is an error
on test3: this is an info
on test3: this is just text
invoking: stderrtest0.sh test4 1>&2 ~output:
on test4: this is an error
on test4: this is an info
on test4: this is just text
invoking: stderrtest0.sh test5 ~output:
on test5: this is an error
on test5: this is an info
on test5: this is just text

Это как я и ожидал. Поскольку по умолчанию stderr & stdout отправляется на терминал.


METATEST2) invoke stderrtest1.sh и перенаправить вывод на out

$ ./stderrtest1.sh >out
on test1: this is an error
on test1: this is an info
on test1: this is just text
on test2: this is an error
on test4: this is an error
on test4: this is an info
on test4: this is just text
on test5: this is an error

$ cat out
invoking: stderrtest0.sh test1 >&2 ~output:
invoking: stderrtest0.sh test2 >&1 ~output:
on test2: this is an info
on test2: this is just text
invoking: stderrtest0.sh test3 2>&1 ~output:
on test3: this is an error
on test3: this is an info
on test3: this is just text
invoking: stderrtest0.sh test4 1>&2 ~output:
invoking: stderrtest0.sh test5 ~output:
on test5: this is an info
on test5: this is just text

Так вот:

  • все stdout отправляется в файл out
  • все stderr отправляется на терминал

Это не совсем так, как я ожидаю. Я как-то думал, что все может закончиться в out


METATEST3) invoke stderrtest1.sh и перенаправить stdout на inf.out

$ ./stderrtest1.sh 1>inf.out
on test1: this is an error
on test1: this is an info
on test1: this is just text
on test2: this is an error
on test4: this is an error
on test4: this is an info
on test4: this is just text
on test5: this is an error

$ cat inf.out
invoking: stderrtest0.sh test1 >&2 ~output:
invoking: stderrtest0.sh test2 >&1 ~output:
on test2: this is an info
on test2: this is just text
invoking: stderrtest0.sh test3 2>&1 ~output:
on test3: this is an error
on test3: this is an info
on test3: this is just text
invoking: stderrtest0.sh test4 1>&2 ~output:
invoking: stderrtest0.sh test5 ~output:
on test5: this is an info
on test5: this is just text

Результаты идентичны METATEST2 :

  • все stdout отправляется в файл inf.out
  • все stderr отправляется на терминал

Ok. Теперь я понимаю METATEST2 . Перенаправление без спецификации по умолчанию stdout.


METATEST4) invoke stderrtest1.sh и перенаправить stderr в err.out

$ ./stderrtest1.sh 2>err.out
invoking: stderrtest0.sh test1 >&2 ~output:
invoking: stderrtest0.sh test2 >&1 ~output:
on test2: this is an info
on test2: this is just text
invoking: stderrtest0.sh test3 2>&1 ~output:
on test3: this is an error
on test3: this is an info
on test3: this is just text
invoking: stderrtest0.sh test4 1>&2 ~output:
invoking: stderrtest0.sh test5 ~output:
on test5: this is an info
on test5: this is just text

$ cat err.out
on test1: this is an error
on test1: this is an info
on test1: this is just text
on test2: this is an error
on test4: this is an error
on test4: this is an info
on test4: this is just text
on test5: this is an error

И тут я запутался. Потому что в METATEST3 test1:
все выходные данные stderrtest0.sh перенаправляются на stderr и поступают на терминал, но не на inf.out

И все же здесь, в METATEST4 test2:
все выходные данные stderrtest1.sh перенаправляются на stdout ~ НО stderr, испускаемый stderrtest0.sh , каким-то образом выходит?


Так что это, кажется, подразумевает:

  • любой / все выходные данные какой-либо вызываемой программы могут быть перенаправлены в stderr вызывающего.
  • stderr вывод из вызываемой программы не перенаправляется в stdout.


Это тот случай?

Ответы [ 2 ]

2 голосов
/ 19 марта 2012

Обычно оболочка открывает два отдельных файловых дескриптора для stdout (1) и stderr (2).Чтобы перенаправить вывод из программы, отправленной одной в другую, достаточно скопировать FD из другой.

$ { echo "foo" >&2 ; } > /dev/null
foo
$ { echo "foo" 2>&1 >&2 ; } > /dev/null
$ { echo "foo" >&2 ; } > /dev/null 2>&1
$
0 голосов
/ 19 марта 2012

Хорошо!Спасибо Игнасио !

Я думаю, что я был одержим нотацией s / h и значением перенаправления .Понимание этого с точки зрения копирования дескриптора файла делает его более понятным для меня.Потому что я немного толстая, я собираюсь разобраться с этим, и, может быть, вы можете исправить меня, если я все еще не понимаю ...

Во-первых:echo "foo" >&2Это не перенаправляет какой-либо / весь вывод echo на stderr;это как / ч эквивалент echo "foo" 1>&2.Он устанавливает stdout FD процесса echo таким же, как FD для stderr.

Итак, для:{ echo "foo" 2>&1 >&2 ; } > /dev/nullЗдесь stderr FD для процесса echo устанавливается на stdout FD ;тогда stdout FD устанавливается на stderr FD ~, не выполняющего ничего, поскольку новое назначение совпадает с текущим значением.И в терминал ничего не попадает, потому что функция stdout FD установлена ​​на / dev / null

А потом для:{ echo "foo" >&2 ; } > /dev/null 2>&1Здесь для stdout FD процесса echo установлено значение stderr FD .Функция stdout FD установлена ​​на / dev / null , а функция stderr FD установлена ​​на значение stdout FD ~, что, конечно, / dev / null .& Так что в терминал ничего не попадает.

Или, говоря по-другому:

$ { echo "phew"; echo "bah" >&2; }
phew
bah
$ { echo "phew"; echo "bah" >&2; } 2>/dev/null
phew
$ { echo "phew"; echo "bah" >&2; } 1>/dev/null
bah
$ { echo "phew"; echo "bah" >&2; } 1>/dev/null 2>&1
$

Я наглый.

И кстати, мне нравится, как вы используете {функцию} вместо того, чтобы писать целые глупые сценарии.Намного аккуратнее;)

...