5

Установка переменной окружения перед командой в Bash не работает для второй команды в пайпе

14

Описание проблемы

В определенной оболочке я обычно устанавливаю переменные и затем выполняю команду. Недавно я узнал о концепции добавления определения переменной перед командой:

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 ответ(ов)

5

В данном примере, переменная окружения FOO устанавливается в значение bar для выполнения команды bash -c. Команда, заключенная в одинарные кавычки, это somecommand someargs | somecommand2. Это означает, что сначала выполняется somecommand с аргументами someargs, а затем результат этого выполнения передается на вход команде somecommand2 с помощью конвейера (pipeline).

Таким образом, FOO будет доступна только в рамках этой команды и не повлияет на другие процессы. Если вы хотите использовать FOO только в рамках выполнения данной команды, то такой способ является правильным.

Если у вас есть дополнительные вопросы или требуется больше деталей, пожалуйста, уточните!

0

Используйте команду env.

Например, можно выполнить так: env FOO=BAR команда. Обратите внимание, что переменные окружения будут восстановлены/остановлены в своем первоначальном состоянии после завершения работы команды.

Однако будьте осторожны с заменой переменных оболочки. Например, если вы хотите явно сослаться на $FOO в той же строке команды, вам, возможно, потребуется экранировать его, чтобы ваша интерпретируемая оболочка не выполнила замену до запуска env.

$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR
0

Вы также можете использовать eval:

FOO=bar eval 'somecommand someargs | somecommand2'

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

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

mypipe() {
    somecommand someargs | somecommand2
}

И выполните её с вашими переменными окружения следующим образом:

FOO=bar mypipe
0

Простой подход заключается в использовании ;.

Например:

ENV=prod; ansible-playbook -i inventories/$ENV --extra-vars "env=$ENV" deauthorize_users.yml --check

command1; command2 выполняет command2 после выполнения command1, последовательно. Не имеет значения, были ли команды успешными или нет.

0

Оба приведенных варианта работают одинаково.

Первый вариант:

some_var="some_value" && echo "${some_var}"

использует оператор &&, который выполняет команду справа (в данном случае echo "${some_var}") только в том случае, если команда слева завершилась успешно. В данном случае, поскольку присваивание переменной всегда успешно, echo будет выполнен, и выведет значение переменной.

Второй вариант:

some_var="some_value"; echo "${some_var}"

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

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь