Как передать 2 > / dev / null в качестве переменной?

У меня есть этот код, который работает:

# 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)
13
задан 28 August 2019 в 07:23

3 ответа

Причина Вы не можете заставить перенаправление происходить путем расширения "$HideErrors" это символы как > не рассматриваются, особенно будучи произведенным расширением параметра. Это на самом деле очень хорошо, потому что такие символы появляются в тексте, который Вы могли бы хотеть развернуть и использовать буквально.

Это содержит, заключаете ли Вы в кавычки $HideErrors. Результат расширения параметра подвергается разделению слова и globbing, когда расширение закрывается кавычки, но вот именно.


Что касается того, что делать с этим, существуют многочисленные способы достигнуть условного перенаправления. Для очень простой команды это может быть разумная запись целая команда дважды, однажды в каждом ответвлении a case или if-else создать. Это скоро становится обременительным, однако, и команда, которую Вы показали, является, конечно, случаем, где это не было бы идеально.

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

Сохраните команду вместо перенаправления. Вместо того, чтобы пытаться сохранить перенаправление в переменной и применить расширение параметра, сохраните команду в функции оболочки. Затем запишите a case или if-else, в котором функция вызвана с перенаправлением на одном ответвлении и без него на другом.

Если Вы осмысляете свою команду как код, который Вы хотите написать однажды, но работать при нескольких обстоятельствах, то функция является естественным решением. Это - то, что я обычно делаю. Это не обладает преимуществом требования ни подоболочка, ни ручное устройство хранения данных и сброс состояния.

С Вашим кодом:

launch() {
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
}

case $fCron in
true)  launch 2>/dev/null;;
*)     launch;; # Get silly error messages when running from terminal
esac

Можно применить любой интервал, Вам нравится, или if-else вместо этого, если Вы предпочитаете. Отметьте это launch автоматически использует вызывающую сторону RobWebAddress и DownloadName переменные, даже если они - локальные переменные, потому что Bash динамично ограничен по объему, в отличие от большинства языков программирования, которые лексически ограничены по объему.

Выполните команду в подоболочке и условно примените перенаправление к exec. Это что steeldriver, прокомментированный о, но внутри ( ) сохранять эффект локальным. Когда exec встроенный выполняется без аргументов, это не заменяет текущую оболочку новым процессом, но вместо этого применяет любое из его перенаправлений к текущей оболочке.

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

С Вашим кодом:

(
    # Suppress silly error messages unless running from terminal
    case $fCron in true) exec 2>/dev/null;; esac

    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
)

После закрытия ), стандартная погрешность в действительности восстанавливается тому, чем это было прежде, потому что это только действительно перенаправляется в подоболочке, а не в родительской оболочке. Это также хорошо работает с существующими переменными оболочки, так как подоболочки получают копию тех. Хотя я предпочитаю использовать функцию оболочки, я признаю, что этот метод может потребовать меньшего количества кода.

Оба метода работают независимо от того, включая что стандартная погрешность файла или устройства начинается как, в случае перенаправлений, примененных к функциям оболочки, которые называют код, который содержит условное поведение, а также случай (упомянутый в Вашем редактировании), где стандартная погрешность для целого сценария была уже перенаправлена предыдущим exec 2>&fd или exec 2> path. То, что путь был произведен заменой процесса, не является никакой проблемой.

19
ответ дан 23 November 2019 в 03:15

Почему трудно кодированный аргумент работает, но не аргумент как переменная?

Поскольку объекты синтаксиса не интерпретируются от расширенных значений переменных. Таким образом, переменное расширение не является тем же как заменой ссылки на переменную с текстом переменной в командной строке. (Материал как ;, |, && и кавычки и т.д. являются также не особенными в значениях переменных.)

То, что Вы могли сделать, должно использовать псевдонимы или использовать переменную для содержания просто цели перенаправления.

Псевдонимы являются просто текстовой заменой, таким образом, они могут содержать синтаксические объекты, как операторы и ключевые слова. В сценарии Вы должны были бы shopt expand_aliases, так как по умолчанию они отключены в неинтерактивных оболочках. Так, это печатает 2 (только):

#!/bin/bash
shopt -s expand_aliases

alias redir='> /dev/null'
redir echo 1
alias redir=''
redir echo 2

(И Вы могли также alias jos=if niin=then soj=fi и затем запишите все свои операторы "if" на финском языке. Я уверен, что любой читающий сценарий любил бы Вас.)

С другой стороны, пишите перенаправление всегда, но управляйте просто целью с переменной. Вам не будет нужна никакая-op цель для случая, где Вы не хотите изменяться, куда вывод идет, хотя, но /dev/stderr должен работать в этом случае. На самом деле, добавление 2> /dev/stderr не не из-за способа, от которого Linux рассматривает fd's, открытый /proc/<pid>/fd как независимый от оригинала. Это влияет на расположение положения записи и испортит вывод, если это переходит к регулярному файлу.

Это должно работать в, добавляют режим, хотя (или если stderr переходит к каналу или к терминалу):

#!/bin/sh
exec 2>/tmp/error.log
dst=/dev/null
ls -l /nosuchfile-1 2>> "$dst"     # this doesn't print
dst=/dev/stderr
ls -l /nosuchfile-2 2>> "$dst"
ls -l /nosuchfile-3 2>> "$dst"

Таким образом повторяться: 2> /dev/stderr может повредиться.

4
ответ дан 23 November 2019 в 03:15

Заголовок вопроса: "Как передать 2>/dev/null как переменная?" Это может на самом деле быть сделано с помощью eval

joshua@nova:/tmp$ X=">/dev/null"
joshua@nova:/tmp$ echo $X
>/dev/null
joshua@nova:/tmp$ eval echo $X
joshua@nova:/tmp$ eval echo hi
hi
joshua@nova:/tmp$ eval echo hi $X
joshua@nova:/tmp$ echo hi $X
hi >/dev/null
joshua@nova:/tmp$ 

Таким образом, мы можем переписать как

# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
local RobWebAddress2
local DownloadName2
[[ $fCron == true ]] && HideErrors="2>/dev/null"
RobWebAddress2='"$RobWebAddress"'
DownloadName2='>"$DownloadName"'

eval google-chrome --headless --disable-gpu --dump-dom \
    $RobWebAddress2 $DownloadName2 "$HideErrors"

Где косвенный переменный доступ предотвращает расширение слишком скоро на остальной части командной строки.

Двойные кавычки в переменных работают просто великолепно.

joshua@nova:/tmp$ X='"'
joshua@nova:/tmp$ Y='$X'
joshua@nova:/tmp$ eval echo $Y
"
joshua@nova:/tmp$ 
1
ответ дан 23 November 2019 в 03:15

Другие вопросы по тегам:

Похожие вопросы: