2012-06-01 1 views
233

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

FOO=bar somecommand someargs 

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

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

я могу предварять somecommand2 с «Foo = бар», а также, который работает, но который добавляет нежелательное дублирование, и это не помогает с аргументами, которые интерпретируются в зависимости от переменной (например, «[AZ]»)

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

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

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

+0

'(T = $ (дата) эхо $ T)' будет работать –

+0

В контексте межплатформенных (включая окна) скриптов или проектов на основе npm (js или else), вы можете взглянуть на [кросс-env-модуль] (https://www.npmjs.com/package/cross -env). –

+1

Я надеялся, что один из ответов также объяснит * почему * это только вид работ, то есть почему он не эквивалентен экспорту переменной перед вызовом. –

ответ

202
FOO=bar bash -c 'somecommand someargs | somecommand2' 
+0

Это удовлетворяет моим критериям (однострочный, без необходимости «экспорта») ... Я полагаю, что нет никакого способа сделать это * без * вызова «bash -c» (например, творческое использование круглых скобок)? – MartyMacGyver

+0

@MartyMacGyver: Нет, о чем я могу думать. Он также не будет работать с фигурными фигурными скобками. –

+4

Обратите внимание, что если вам нужно запустить 'somecommand' как sudo, вам нужно передать sudo флаг' -E' для передачи через переменные. Поскольку переменные могут вводить уязвимости. http://stackoverflow.com/a/8633575/1695680 – ThorSummoner

138

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

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

Кита имеет точку, чтобы безоговорочно выполнить команды, выполните следующие действия:

(export FOO=bar; somecommand someargs | somecommand2) 
+0

Это, похоже, работает, хотя это не совсем что я искал (возможно, нет возможности сделать то, что я описываю выше, в одной команде, без явного использования экспорта сначала ...) Мысли? – MartyMacGyver

+7

Я бы использовал ';' а не '&&';, что не будет' export FOO = bar' будет терпеть неудачу. –

+0

@ Keith - Я всегда интересовался разницей между & & and ; (как и большинство вопросов, не связанных с вопросом, поиск не совсем прост ... Я знаю, что Windows поддерживает &&, но, очевидно, ничего подобного «;», FWIW). Я могу найти себя, используя эту конструкцию или конструкцию bash в зависимости от аудитории. – MartyMacGyver

-5

Как насчет используя сценарий оболочки?

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

> ./myscript 
+9

Вам по-прежнему нужен 'export'; иначе '$ FOO' будет переменной оболочки, а не переменной среды, и поэтому не будет отображаться' somecommand' или 'somecommand2'. –

+0

Это сработает, но это победит цель иметь однострочную команду (я пытаюсь изучить более творческие способы избежать многострочных и/или скриптов для относительно простых случаев). И то, что сказал @Keith, хотя, по крайней мере, экспорт остался бы привязан к сценарию. – MartyMacGyver

22

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

FOO=bar eval 'somecommand someargs | somecommand2' 

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

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

mypipe() { 
    somecommand someargs | somecommand2 
} 

и выполнить его с переменными окружения, как это:

FOO=bar mypipe 
+6

@Alfe: Вы также снизили принятый ответ? потому что он проявляет те же «проблемы», что и «eval». –

+7

@Alfe: К сожалению, я не согласен с вашей критикой. Эта команда абсолютно безопасна. Ты действительно выглядишь как парень, который когда-то читал _'eval' злой_, не понимая, что зла в 'eval'. И, может быть, вы вообще не понимаете этот ответ (и в этом нет ничего плохого). На том же уровне: скажете ли вы, что 'ls' является плохим, потому что' для файла в $ (ls) 'is, bad? (и да, вы не спустили принятый ответ, и вы тоже не оставили комментарий). Иногда такое странное и абсурдное место. –

+6

@Alfe: Когда я говорю: «Ты действительно выглядишь как парень, который когда-то читал« eval », злой, не понимая, что зла в« eval », _ Я имею в виду ваше предложение: _В этом ответе не хватает всех предупреждений и объяснений, необходимых при разговоре о 'eval'._' eval' неплохо или опасно; не более, чем 'bash -c'. –

Смежные вопросы