У меня есть этот код, который работает:
# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>/dev/null
else
# Get silly error messages when running from terminal
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
fi
Если я попытаюсь сократить это так:
# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" "$HideErrors"
Я получаю сообщения об ошибках:
[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)
Почему жестко закодированный аргумент работает, а не аргумент как переменная?
Изменить 2:
В настоящее время я нашел успех с альтернативным предложением второго ответа:
# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"
Изменить 1:
Исходя из первого ответа, я должен отметить, что заголовок программы уже содержит:
[[ $fCron != true ]] &&
exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
command-line
bash
redirect
WinEunuuchs2Unix
источник
источник
[[ $fCron == true ]] && exec 2>/dev/null
вместо этогоОтветы:
Причина, по которой вы не можете вызвать перенаправление при расширении,
"$HideErrors"
заключается в том, что подобные символы>
не обрабатываются специально после создания расширения параметра . На самом деле это очень хорошо, потому что такие символы появляются в тексте, который вы можете расширить и использовать буквально.Это касается того, цитируете ли вы или нет
$HideErrors
. Результат раскрытия параметров может быть разбит на слова и выделен, когда расширение не заключено в кавычки, но это так.Что касается того, что с этим делать, существует множество способов добиться условного перенаправления. Для очень простой команды, может быть разумно написать целую команду дважды, один раз в каждой ветви
case
илиif
-else
конструкт. Однако вскоре это становится обременительным, и команда, которую вы показали, безусловно, является идеальной.Из подходов, которые позволяют избежать повторения , есть два, которые я особенно рекомендую, потому что они довольно чистые и их легко понять. Вы хотели бы использовать только один из них, а не одновременно для одной и той же команды и перенаправления.
Сохраните команду вместо перенаправления. Вместо того, чтобы пытаться сохранить перенаправление в переменной и применять расширение параметра, сохраните команду в функции оболочки . Затем напишите a
case
илиif
-else
, в котором функция вызывается с перенаправлением на одной ветви и без нее на другой.Если вы представляете свою команду как код, который вы хотите написать один раз, но выполнить при нескольких обстоятельствах, то функция является естественным решением. Это то, что я обычно делаю. Преимущество в том, что он не требует ни вложенной оболочки, ни ручного хранения и сброса состояния.
С вашим кодом:
Вы можете применить любой интервал, который вам нравится, или
if
-else
вместо этого, если вы предпочитаете. Обратите внимание, чтоlaunch
автоматически используются вызывающаяRobWebAddress
иDownloadName
переменные, даже если они являются локальными переменными, потому что Bash динамически ограничен , в отличие от большинства языков программирования с лексической областью.Запустите команду в подоболочке и условно примените перенаправление к
exec
. Это то, что прокомментировал Steeldriver , но внутри,(
)
чтобы сохранить эффект локальным . Когда встроенный запускаются без аргументов, она не заменяет текущую оболочку с новым процессом, но вместо этого применяет какое - либо из его перенаправлений к текущей оболочке.exec
(Также возможно отследить, что было стандартной ошибкой, и восстановить ее, не используя подоболочку и, следовательно, не жертвуя возможностью изменять среду текущей оболочки. Однако я оставлю подробности об этом другим ответам.)
С вашим кодом:
После закрытия
)
стандартная ошибка фактически восстанавливается до того, что было раньше, потому что она действительно перенаправляется только в подоболочку, а не в родительскую оболочку. Это также хорошо работает с существующими переменными оболочки, так как подоболочки получают их копию. Хотя я предпочитаю использовать функцию оболочки, я допускаю, что этот метод может потребовать меньше кода.Оба метода работают независимо от того, с какого файла начинается стандартная ошибка файла или устройства, в том числе в случае перенаправлений, применяемых к функциям оболочки, которые вызывают код, содержащий условное поведение, а также в случае (упоминавшемся в вашем редактировании), где стандартная ошибка для весь сценарий уже был перенаправлен предыдущим или . То, что путь был создан путем подстановки процесса, не проблема.
exec 2>&fd
exec 2> path
источник
exec
не знаю, планирует ли он ответ на этот вопрос ...exec
. Но, как я уже упоминал в скобках, я не рассматривал более сложные приложения, в которых старый файловый дескриптор хранится и восстанавливается без подоболочки. Я также не рассмотрел менее сложные приложения, такие как просто сохранение перенаправления, если это конец сценария. Другой ответ, если он будет опубликован, может охватить и то, и другое.exec
который, я думаю, не должен влиять на ваш ответ.RobWebAddress
определенно является глобальным контекстом.DownloadName
был определен локально, но должен иметь глобальный контекст. По какой-то причине дочерние функции наследуют локальные определения родителей (чтобыDownloadName
была виднаDownloadAsHTML ()
функция, вызываемаяUpdateOne ()
функцией, которая определяла ее как локальную. Это былПотому что элементы синтаксиса не интерпретируются из расширенных значений переменных. То есть расширение переменной - это не то же самое, что замена ссылки на переменную текстом переменной в командной строке. ( Такие вещи , как
;
,|
,&&
и цитаты и т.д., также не спец в значениях переменных.)То, что вы могли бы сделать, это использовать псевдонимы или использовать переменную, чтобы удерживать только цель перенаправления.
Псевдонимы - это просто замена текста, поэтому они могут содержать синтаксические элементы, такие как операторы и ключевые слова. В сценарии это необходимо
shopt expand_aliases
, поскольку по умолчанию они отключены в неинтерактивных оболочках. Итак, это печатает2
(только):(А также вы могли бы
alias jos=if niin=then soj=fi
и тогда написать все свои операторы if на финском языке. Я уверен, что любой, кто читает сценарий, полюбит вас.)В качестве альтернативы всегда пишите перенаправление, но управляйте только целью с помощью переменной. Вам понадобится неоперативная цель для случая, когда вы не хотите менять направление вывода,
ноНа самом деле, добавление/dev/stderr
должны работать в этом случае.2> /dev/stderr
не является запретом из-за того, как Linux рассматривает открытые файлы/proc/<pid>/fd
как независимые от оригинала. Это влияет на расположение позиции записи и испортит вывод, если он перейдет в обычный файл.Однако он должен работать в режиме добавления (или если stderr идет в канал или в терминал):
Так что повторюсь:
2> /dev/stderr
может сломаться.источник
expand_aliases
том, страшно, потому что~/.bashrc
я думаю, что ваша программа может быть заложником .expand_aliases
это немного страшно. Но это~/.bashrc
не должно быть проблемой, поскольку он читается только интерактивными оболочками,.profile
а друзья, которые могут его вызывать, читаются только оболочками входа в систему. Неинтерактивные оболочки без входа в систему, такие как сценарии, не должны запускать ни одну из них. (Но есть и$BASH_ENV
, по-видимому.bashrc
, читается, если stdin подключен к сетевому сокету. Насколько запутанным он может быть ...)2>> "$dst"
трюк, но я только что понял, что он не работает в общем случае, поэтому лучше быть осторожным с этим.Заголовок вопроса: «Как передать 2> / dev / null в качестве переменной?» Это может быть сделано с помощью
eval
Таким образом, мы можем переписать как
Где косвенный доступ к переменным предотвращает слишком быстрое расширение в остальной части командной строки.
Двойные кавычки в переменных работают просто отлично.
источник
DownloadName
- и буквенный текстRobWebAddress
всегда используется для URL. Вы используете$"
"
цитаты . Я думаю, что это может быть непреднамеренным, и вы можете захотеть$
внутри"
"
, но вы сделали это таким образом в обоих местах, так что я не уверен. Я думаю, что просто> "$DownloadName"
должен это исправить. Но я понимаю, что вам это может не понравиться, поскольку случайное смешение аргументов и не-аргументовeval
является одной из причин, по которой так опасно и не рекомендуется использоватьeval
конкатенирующее поведение.eval
объединяются перед оценкой. Но я думаю, что другой способ выразить это - это запутанный способ написания,eval 'google-chrome --headless --disable-gpu --dump-dom "$RobWebAddress" > "$DownloadName" '"$HideErrors"
который напоминает внешний вид кода OP. И вообще, использоватьeval
для задач, которые не нужны, это плохо . (Ничего из этого не оправдывает - и даже не объясняет - ошибочность и враждебность моего старого ответа.)