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

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

FOO=bar somecommand someargs

Это работает... вроде. Это не работает, когда вы меняете переменную LC_ * (которая, кажется, влияет на команду, но не ее аргументы, например, "[az]" char диапазоны) или когда вывод трубопровода на другую команду:

FOO=bar somecommand someargs | somecommand2  # somecommand2 is unaware of FOO

Я могу добавить somecommand2 с "FOO = bar", который работает, но который добавляет нежелательное дублирование, и это не помогает с аргументами, которые интерпретируются в зависимости от переменной (например, "[az]" )

Итак, какой хороший способ сделать это в одной строке? Я думаю что-то по порядку:

FOO=bar (somecommand someargs | somecommand2)  # Doesn't actually work

Изменить: у меня много хороших ответов! Цель состоит в том, чтобы сохранить это однострочное изображение, предпочтительно без использования "экспорта". Метод, использующий вызов bash, был лучшим в целом, хотя скобковая версия с "export" в нем была немного более компактной. Интересен также метод использования перенаправления, а не трубы.

Ответ 1

FOO=bar bash -c 'somecommand someargs | somecommand2'

Ответ 2

Как экспортировать переменную, но только внутри подоболочки?:

(export FOO=bar && somecommand someargs | somecommand2)

У Keith есть точка для безусловного выполнения команд:

(export FOO=bar; somecommand someargs | somecommand2)

Ответ 3

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

FOO=bar eval 'somecommand someargs | somecommand2'

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

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

mypipe() {
    somecommand someargs | somecommand2
}

и выполните его с такими переменными среды, как это:

FOO=bar mypipe

Ответ 4

Обновление: это неправильно, и я скоро удалю ответ.

Я считаю, что это невозможно сделать, не называя "bash -c" (например, творческое использование круглых скобок)?

for FOO in bar; do echo $FOO; done # put somecommand someargs instead of echo

Хотя это может вызвать тревогу у новичков, это супер чисто, потому что между вашими командами и текущей оболочкой нет bash -c, либо с помощью скобок или bash -c либо каким-либо другим способом.

Единственным недостатком по сравнению с префиксом FOO=bar cmd является необходимость завершить done но это довольно тривиальный недостаток, учитывая, что для всех других решений требуется подселлед, чтобы вызвать команду.

Ответ 5

Используйте env.

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

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

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

Ответ 6

Как насчет использования оболочки script?

#!/bin/bash
# myscript
FOO=bar
somecommand someargs | somecommand2

> ./myscript