В зш
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 { … }
группирует команды только для какой-то цели (в нашем случае цель — перенаправление). Это не значит, что при использовании никогда не бывает подоболочки { … }
; например, в конвейере все части, кроме последней, в любом случае являются подоболочками (в некоторых оболочках: все части, включая последнюю). Эти технические детали не имеют значения в контексте только нашей проблемы, но в целом они могут иметь значение.