Как подавить сообщения об ошибках в zsh?

Как подавить сообщения об ошибках в zsh?

В зш

  • rm foo.barотпечатки rm: foo.bar: No such file or directory.
  • rm foo.bar 2>/dev/nullничего не печатает, как я и ожидал.

Но если команда содержит совпадения с шаблоном, ошибка не подавляется 2>/dev/null:

  • rm *.barотпечатки zsh: no matches found: *.bar.
  • rm *.bar 2>/dev/nullпечатает то же самое.

Есть ли общий способ подавления сообщений об ошибках в zsh? Одинпростойметод для всех видов сообщений об ошибках.

решение1

Если вы пытаетесь запустить программу rm *.barи не находите соответствующего файла *.bar, то в основном могут произойти две вещи:

  • Поведение POSIX заключается в том, что оболочка запускается rmс литералом *.barв качестве аргумента. Инструмент пытается удалить файл с литералом *.bar(как если бы вы запустили rm '*.bar'), он терпит неудачу и печатает что-то вроде rm: *.bar: No such file or directory. Так shведут себя оболочка POSIX ( ) и совместимые оболочки.

  • Не-POSIX поведение: оболочка обнаруживает, что совпадений нет, выводит что-то вроде no matches found: *.barи не запускаетсяrm совсем. Так Zsh ведет себя по умолчанию. (Для сравнения: в Bash можно переключиться на это поведение с помощью shopt -s failglob.)

Ошибка из rm(первый случай) выводится в stderr rm. Ошибка из оболочки (последний случай) выводится в stderr оболочки.

Перенаправление в rm *.bar 2>/dev/nullвлияет на stderr rmтолько + . В вашем примере rmдаже не запускается.

Чтобы перенаправить stderr основной оболочки, вам нужно exec. Под "основной оболочкой" я подразумеваю интерактивную оболочку, в которой вы печатаете; или, в случае запуска скрипта, оболочку, интерпретирующую скрипт. Пример:

exec 2>/dev/null

В Zsh его можно даже закрыть:

exec 2>&-

Разумный подход — заранее дублировать исходный stderr, на всякий случай, если вам понадобится использовать (или восстановить) его позже. Пример (обратите внимание, если вы хотите вставить этот код в интерактивный Zsh, то вам следует вызватьsetopt interactive_commentsпервый):

exec 7>&2           # "save" stderr
exec 2>/dev/null    # redirect
rm *.bar
whatever
exec 2>&7           # restore
exec 7>&-           # close descriptor which is no longer needed

Вот 7произвольное однозначное число, в противном случае не используемое как дескриптор файла. Первые две строки можно записать как одну: exec 7>&2 2>/dev/null; аналогично можно записать и последние две строки.

Примечание rmили любая команда (например whatever), вызванная без перенаправления stderr, наследует stderr от оболочки. Это означает, что в приведенном выше примере rm(если он когда-либо запустится) и whateverвыведет свои сообщения об ошибках (если таковые имеются) в /dev/null. После этого exec 2>/dev/nullвы можете вызвать любое количество команд, и все они будут иметь /dev/nullв качестве своего stderr. Если вы действительно хотите подавить все виды сообщений об ошибках, то это способ.

Решение работает во многих оболочках, не только в Zsh. Если вы хотите перенаправить stderr интерактивной оболочки, то имейте в виду, что некоторые менее сложные оболочки используют stderr для вывода своего приглашения.

Обратите внимание, что процесс может перенаправить свой собственный stderr (как это делает наша оболочка с помощью exec 2>…); или он может выводить сообщения об ошибках на stdout или на /dev/tty(он не должен этого делать, но технически может). exec 2>/dev/nullПоэтомунетгарантируем, что вы не увидите сообщений, похожих на сообщения об ошибках.

После этого exec 2>/dev/nullвы все еще можете перенаправить stderr любой команды по требованию. Например, если бы вместо этого whateverу нас было:

whatever 2>&7

то его сообщения об ошибках будут отправляться в исходный stderr, который мы намеренно сохранили как файловый дескриптор 7.


execэто не единственный способ перенаправить stderr (или другой файловый дескриптор) оболочки. Вы можете обращаться с оболочкой (но не со всей основной оболочкой) так же, как вы обращаетесь rmс rm … 2>/dev/null. Вы можете обращаться с подоболочкой так:

( rm *.bar ) 2>/dev/null

или просто некоторый код, интерпретируемый основной оболочкой:

{ rm *.bar; } 2>/dev/null

( ;здесь это необязательно в Zsh, но обязательно в некоторых других оболочках; я просто хотел, чтобы код работал и за пределами Zsh).

Любая из этих строк может решить вашу проблему. В контексте подавления сообщений об ошибках, поступающих из оболочки, эти две строки эквивалентны ++ .

Обратите внимание, что перенаправление начинается с (/ {и заканчивается на )/ }, его область действия ограничена. Тем не менее, вы можете поместить много команд в скобки, поэтому "ограниченная" область действия может фактически быть всем скриптом. Или это может быть просто часть скрипта (включая whateverпредставленные ранее в этом ответе, все, что вы хотите). Тот факт, что перенаправление перестает работать после )/ , }делает этот подход изящной альтернативой сохранению и восстановлению stderr с помощью exec.


+ Строго: это влияет на " rm" до и после того, как он становится (или пытается стать) rm. Потерпите меня. Перенаправление в rm … 2>/dev/nullначинается как перенаправление, выполняемоеразветвленная оболочка, которая собирается заменить себя rmисполняемым файлом. Эта оболочка перенаправляет свой собственный stderr, прежде чем попытается заменить себя на rm. Любая ошибка, о которой она сообщает после выполнения перенаправления, будет отправлена ​​в /dev/null. Например, если rmне будет найдено, то уже выполненное перенаправление подавит command not foundошибку.

++ Технически ( … )создает подоболочку, { … }но не создает. Подоболочка ведет себя как отдельный процесс оболочки, который наследует переменные и текущий рабочий каталог, но не может ничего изменить (например, переменные или текущий рабочий каталог) в своей родительской оболочке. Она может быть реализована или не реализована как действительно отдельный процесс, важно поведение. OTOH { … }группирует команды только для какой-то цели (в нашем случае цель — перенаправление). Это не значит, что при использовании никогда не бывает подоболочки { … }; например, в конвейере все части, кроме последней, в любом случае являются подоболочками (в некоторых оболочках: все части, включая последнюю). Эти технические детали не имеют значения в контексте только нашей проблемы, но в целом они могут иметь значение.

Связанный контент