Установка переменной окружения перед командой в Bash не работает для второй команды в пайпе
Описание проблемы
В определенной оболочке я обычно устанавливаю переменные и затем выполняю команду. Недавно я узнал о концепции добавления определения переменной перед командой:
FOO=bar somecommand someargs
Это работает... в целом. Однако, это не работает, когда вы пытаетесь изменить переменную типа LC_*
, которая влияет на команду, но не на её аргументы (например, диапазоны символов [a-z]
), или когда вы направляете вывод одной команды в другую:
FOO=bar somecommand someargs | somecommand2 # somecommand2 не знает о FOO
Я могу также добавить FOO=bar
перед somecommand2
, и это будет работать, но появляется нежелательное дублирование, и это не помогает с аргументами, которые интерпретируются в зависимости от переменной (например, [a-z]
).
Какой хороший способ сделать это в одну строку?
Я думал о варианте вроде:
FOO=bar (somecommand someargs | somecommand2) # Это не работает
Я получил много хороших ответов! Цель состоит в том, чтобы сохранить это в одной строке, предпочтительно без использования export
. Метод с вызовом Bash оказался в целом лучшим, хотя вариант с подстановкой и export
был немного компактнее. Метод использования перенаправления вместо конвейера также интересен.
5 ответ(ов)
В данном примере, переменная окружения FOO
устанавливается в значение bar
для выполнения команды bash -c
. Команда, заключенная в одинарные кавычки, это somecommand someargs | somecommand2
. Это означает, что сначала выполняется somecommand
с аргументами someargs
, а затем результат этого выполнения передается на вход команде somecommand2
с помощью конвейера (pipeline).
Таким образом, FOO
будет доступна только в рамках этой команды и не повлияет на другие процессы. Если вы хотите использовать FOO
только в рамках выполнения данной команды, то такой способ является правильным.
Если у вас есть дополнительные вопросы или требуется больше деталей, пожалуйста, уточните!
Используйте команду env
.
Например, можно выполнить так: env FOO=BAR команда
. Обратите внимание, что переменные окружения будут восстановлены/остановлены в своем первоначальном состоянии после завершения работы команды.
Однако будьте осторожны с заменой переменных оболочки. Например, если вы хотите явно сослаться на $FOO
в той же строке команды, вам, возможно, потребуется экранировать его, чтобы ваша интерпретируемая оболочка не выполнила замену до запуска env
.
$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR
Вы также можете использовать eval
:
FOO=bar eval 'somecommand someargs | somecommand2'
Поскольку этот ответ с использованием eval
не всем кажется приемлемым, позвольте мне прояснить один момент: когда используется указанный синтаксис — с одинарными кавычками, это абсолютно безопасно. Так как данный подход не запускает внешние процессы (в отличие от принятого ответа) и не выполняет команды в дополнительной подсистеме (как в другом ответе).
Поскольку мы получаем несколько стандартных просмотров, было бы неплохо предложить альтернативу eval
, которая устроит всех и имеет все преимущества (а, возможно, даже больше!) этого быстрого "трика" с eval
. Просто используйте функцию! Определите функцию со всеми вашими командами:
mypipe() {
somecommand someargs | somecommand2
}
И выполните её с вашими переменными окружения следующим образом:
FOO=bar mypipe
Простой подход заключается в использовании ;
.
Например:
ENV=prod; ansible-playbook -i inventories/$ENV --extra-vars "env=$ENV" deauthorize_users.yml --check
command1; command2
выполняет command2 после выполнения command1, последовательно. Не имеет значения, были ли команды успешными или нет.
Оба приведенных варианта работают одинаково.
Первый вариант:
some_var="some_value" && echo "${some_var}"
использует оператор &&
, который выполняет команду справа (в данном случае echo "${some_var}"
) только в том случае, если команда слева завершилась успешно. В данном случае, поскольку присваивание переменной всегда успешно, echo
будет выполнен, и выведет значение переменной.
Второй вариант:
some_var="some_value"; echo "${some_var}"
просто отделяет две команды точкой с запятой. Здесь обе команды выполняются последовательно, и переменная также будет выведена.
Таким образом, оба метода корректны и дают одинаковый результат. Вы можете использовать любой из них в зависимости от ваших предпочтений или контекста, в котором они используются.
Установить переменные окружения из файла с парами ключ/значение
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?
Передача параметров в функцию Bash
Как разделить большой текстовый файл на меньшие файлы с равным количеством строк?