Что это за синтаксис оболочки / Bash: someVariable = someValue someCommand [duplicate]

Я "сломал" свою систему, добавив записи в FSTAB для моих локальных томов, например:

# /etc/fstab
#
#    This file is read once by the first process in a Cygwin process tree.
#    To pick up changes, restart all Cygwin processes.  For a description
#    see https://cygwin.com/cygwin-ug-net/using.html#mount-table

# This is default anyway:
none /cygdrive cygdrive binary,posix=0,user 0 0

c:/ /c ntfs text,posix=0 0 0
d:/ /d ntfs text,posix=0 0 0
f:/ /f ntfs text,posix=0 0 0
g:/ /g ntfs text,posix=0 0 0

Я «отремонтировал» его, изменив fstab на:

none /cygdrive cygdrive binary,posix=0,user 0 0
none /tmp usertemp binary,posix=0 0 0

c:/  /c  ntfs binary,posix=0,cygexec 0 0
d:/  /d  ntfs binary,posix=0,cygexec 0 0
f:/  /f  ntfs binary,posix=0,cygexec 0 0
g:/  /g  ntfs binary,posix=0,cygexec 0 0

Я думаю, что произошло то, что, не монтируя 4 диска (c, d, f, g) как «exec», каждый раз, когда cygwin искал внешний it открыл и прочитал большое количество файлов в поисках «волшебных» байтов, чтобы узнать, является ли файл исполняемым.

Между тем, mintty буферизовала то, что я ввел как «тип вперед», пока я не вышел с Ctrl-C, убивая все еще выполняющийся поиск моей команды.

Добавив "cygexec" к параметрам, поиск теперь обращается только к исполняемым флагам в каталогах и выполняется на полной скорости.

27
13.08.2018, 19:48
4 ответа

Это эквивалентно:

( export someVariable=something; command )

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

Вот соответствующие части руководства по bash:

Простые команды

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

(...)

Простое расширение команд

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

Примечание: имейте в виду, что это не специфично для bash, а определено POSIX.


Редактировать - Обобщенное обсуждение из комментариев в ответе

Причина, по которой BAZ=JAKE echo $BAZ, не выводит JAKE, заключается в том, что подстановка переменных выполняется до всего остального. Если обойти подстановку переменных, то все будет как ожидалось:

$ echo_baz() { echo "[$BAZ]"; }
$ BAZ=Jake echo_baz
[Jake]
$ echo_baz
[]
39
27.01.2020, 19:39

Здесь происходит несколько ключевых вещей:

  • Как объясняется в справочном руководстве bash , Простая команда Расширение, раздел «Если имя команды не дается, присвоение переменных влияет на текущую среду оболочки. В противном случае переменные добавляются в среду выполняемой команды и не влияют на текущую среду оболочки». Таким образом, когда вы говорите var = "something" command arg1 arg2 , команда будет выполняться, когда var находится в среде команды и исчезает после выхода команды . Демонстрация этого проста - доступ к среде команды из команды:

     $ BAZ = "jake" python -c "import os; print os.environ ['BAZ']" 
    jake {{1 }} 

    Ничего удивительного. Такой синтаксис часто используется для запуска программ в модифицированной среде. Мои коллеги, пользователи unix.stackexchange.com и askubuntu.com, узнают этот пример: если пользователь использует немецкий язык, а вы говорите только по-английски, вы можете попросить их воспроизвести любую проблему, с которой они столкнулись, и получить вывод на английском языке следующим образом:

     LC_ALL = команда C 
     

    Обратите внимание, что доступ к среде не является специфическим для python . Это можно сделать с помощью C или любого другого языка программирования.Так уж получилось, что сейчас он был моим «любимым оружием» и использовался только для этой демонстрации.

  • Расширение переменной происходит перед запуском чего-либо. Таким образом, когда вы запускаете что-то вроде BAZ = "foo" echo $ BAZ , оболочка сначала просматривает свою среду, не находит там переменной BAZ и, таким образом, оставляет $ BAZ пустым. Простая демонстрация этого:

     $ BAZ = "jake" python -c "import sys; print 'ARG:', sys.argv [1]" $ BAZ 
    ARG: 
    Traceback (последний вызов последним): 
    Файл "", строка 1, в  
    IndexError: список индекса вне допустимого диапазона 
     

Также важно обратите внимание, отличие от BAZ = jake; echo $ BAZ , который представляет собой два отдельных командных оператора, и здесь BAZ = jake останется в среде оболочки. Вариант использования зависит от ваших намерений. Если вы намереваетесь запустить несколько программ, которым нужна такая переменная, может быть желательно экспортировать такую ​​переменную. Если вам это нужно только в этот конкретный момент, то предыдущее присвоение переменных может быть предпочтительнее.

5
27.01.2020, 19:39

Простыми словами:

BAZ=jake echo $BAZ

ничего не выводит, потому что подстановка переменной выполняется первой в команде. Это означает, что первое, что происходит в этой командной строке, - это $ BAZ будет заменено любым фактическим значением, с которым ранее была определена переменная BAZ (если таковая имеется). Учтите, что это происходит еще до того, как оболочка считает BAZ = jake в той же командной строке.

Перед выполнением нашей команды, поскольку BAZ не имеет присвоенного значения и поскольку BAZ = jake рассматривается только после разрешения $ BAZ , $ BAZ не принимает никакого значения. Следовательно, echo $ BAZ ничего не выводит.

BAZ = jake - это только часть данной команды (оболочка не будет рассматривать / устанавливать ее как переменную среды). Это наиболее полезно, если некоторый процесс, выполняемый как часть той же командной строки, использует эту переменную BAZ . Значение BAZ , jake является непостоянным после завершения выполнения команды.

Например: ] # LD_LIBRARY_PATH = "new_path" ldconfig , где команда ldconfig внутренне ссылается на переменную LD_LIBRARY_PATH , и в этой команде нет расширения переменной линия в отличие от выше.

Для другого случая:

BAZ=jake; echo $BAZ  

Это две разные команды, указанные в одной строке. Это так же хорошо, как выполнять одно за другим.

3
27.01.2020, 19:39

Это назначения переменных в контексте простых команд. Как упоминал xhienne, для внешних команд они эквивалентны экспорту присвоенного значения (значений) на время выполнения команды.

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

 BAZ=jake echo $BAZ

shell сначала расширяет $BAZ (в результате ничего не получается), затем устанавливает BAZ в jake, и, наконец, выполняет

 echo

которая печатает пустую строку. (Затем оболочка забывает BAZ, как показывает последующее echo $BAZ).

 BAZ=jake; echo $BAZ

интерпретируется как две команды: сначала переменная BAZ устанавливается в текущем окружении, затем echo $BAZ расширяется до echo jake и выполняется.

18
27.01.2020, 19:39

Теги

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