Подтвердить что ты не робот

Перенаправление ввода-вывода - свопинг stdout и stderr

Для оболочки script:

#!/bin/sh

echo "I'm stdout";
echo "I'm stderr" >&2;

Есть ли способ вызвать этот script такой, что только stderr будет распечатываться, когда последняя часть команды равна 2 > /dev/null, т.е.

$ > sh myscript.sh SOME_OPTIONS_HERE 2>/dev/null
I'm stderr

Или, альтернативно:

$ > sh myscript.sh SOME_OPTIONS_HERE >/dev/null
I'm stdout

Это вопрос в конце набора лекционных слайдов, но после почти дня работы над этим я почти уверен, что это своего рода опечатка. Поворот не работает. 2 > & - не работает. У меня нет идей!

4b9b3361

Ответ 1

% (sh myscript.sh 3>&2 2>&1 1>&3) 2>/dev/null
I'm stderr
% (sh myscript.sh 3>&2 2>&1 1>&3) >/dev/null 
I'm stdout

Ответ 2

Для полноты, основанной на комментарии от @200_success выше, вероятно, лучше переместить файловый дескриптор 3 с помощью 1>&3-

$ (sh myscript.sh 3>&2 2>&1 1>&3-) 2>/dev/null
I'm stderr
$ (sh myscript.sh 3>&2 2>&1 1>&3-) >/dev/null 
I'm stdout

Вместо того, чтобы обменивать файловые дескрипторы на основе каждого процесса, используя exec, вы можете менять stdin и stderr для всех следующих команд, запущенных текущей оболочкой:

$ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) 2>/dev/null
I'm stderr
I'm stderr
$ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) >/dev/null 
I'm stdout
I'm stdout

Ответ 3

Перемещение дескриптора файла (1>&3-) не является переносимым, не все его реализации POSIX поддерживают его. Это ksh93-ism и bash -ism. (подробнее здесь https://unix.stackexchange.com/questions/65000/practical-use-for-moving-file-descriptors)

Также можно закрыть FD 3 после выполнения перенаправления.

ls 3>&2 2>&1 1>&3 3>&-

выводит содержимое текущего рабочего каталога из stderr.

Синтаксис 3>&- или 3<&- закрывает дескриптор файла 3.

Ответ 4

bash хакерская вики может быть очень полезной в таких вещах. Там есть способ сделать это, который не упоминается среди этих ответов, поэтому Я поставлю свои два цента.

Семантика >&N, для числового N, означает перенаправление на цель файловый дескриптор N. Слово target важно, поскольку дескриптор может изменить цель позже, но как только мы скопировали эту цель, нам все равно. Причина, по которой порядок, в котором мы заявляем о перенаправлении, имеет значение.

Итак, вы можете сделать это следующим образом:

./myscript.sh 2>&1 >/dev/null

Это означает:

  • перенаправить stderr в цель stdout, то есть выходной поток stdout. Теперь stderr скопировал цель stdout

  • Измените stdout на /dev/null. Это не повлияет на stderr, так как он "скопировал" цель, прежде чем мы ее изменили.

Нет необходимости в третьем файловом дескрипторе.

Интересно, как я просто не могу сделать >&- вместо >/dev/null. Это фактически закрывает stdout, поэтому я получаю сообщение об ошибке (на stderr target, то есть фактическое stdout, конечно: D)

line 3: echo: write error: Bad file descriptor

Вы можете видеть, что этот порядок имеет значение, пытаясь заменить перенаправления:

./myscript.sh >/dev/null 2>&1

Это не сработает, потому что:

  • Мы устанавливаем цель stdout в /dev/null
  • Мы устанавливаем цель stderr в цель stdout, то есть /dev/null снова.