Я только что столкнулся с несколькими ответами, такими как разбор текстового файла с разделителями ... который использует конструкцию:
while IFS=, read xx yy zz;do
echo $xx $yy $zz
done < input_file
где IFS
переменная устанавливается перед read
командой.
Я читал ссылку на bash, но не могу понять, почему это законно.
Я пытался
$ x="once upon" y="a time" echo $x $y
из командной строки bash, но ничего не получил. Может кто-то указать мне, где этот синтаксис определен в ссылке, которая позволяет переменной IFS быть установленным таким образом? Это особый случай или я могу сделать что-то подобное с другими переменными?
bash
shell
environment-variables
Майк Липперт
источник
источник
Ответы:
Это под Грамматика Shell, Простые команды (выделение добавлено):
Таким образом, вы можете передать любую переменную, какую захотите. Ваш
echo
пример не работает, потому что переменные передаются команде, а не задаются в оболочке. Оболочка раскрывается$x
и$y
до вызова команды. Это работает, например:источник
man bash
в своей системе ...Определенные переменные становятся похожими на переменные среды в разветвленном процессе.
Если вы бежите
затем колотить первым расширяется
$A
в ,""
а затем запускаетВот правильный путь:
Обратите внимание на одинарные кавычки, в
bash -c
противном случае у вас та же проблема, что и выше.Так что ваш пример цикла допустим, потому что встроенная команда bash 'read' будет искать IFS в своих переменных окружения и находит
,
. Следовательно,распечатает
TEST is and I is test
Наконец, что касается синтаксиса, в цикле for ожидается строка. Поэтому я должен был использовать обратные кавычки, чтобы превратить это в команду. Однако в то время как циклы ожидают командного синтаксиса, такого как
IFS=, read xx yy zz
.источник
A
переменной bash расширяется$A
до пустой строки, но во избежание путаницы я бы не стал использовать,""
потому что код не эквивалентенA="b" echo ""
. Там не будет никаких аргументовecho
.man bash
Переменные раскрываются перед назначением переменной. По очевидной причине,
var=x
это сработало бы и другим способом, ноvar=$othervar
не сработало. Т.е. ваш$x
нужен прежде чем он станет доступен. Но это не главная проблема. Основная проблема заключается в том, что командная строка может быть изменена только средой оболочки, но назначение не становится частью среды оболочки.Вы смешиваетесь с функциями: вы хотите заменить командную строку, но поместите определение переменной в командную среду. Замены командной строки должны быть сделаны оболочкой. Окружение должно быть явно использовано вызываемой командой. То, как и как это сделать, зависит от команды.
Преимущество такого использования заключается в том, что вы можете установить среду для подпроцесса, не влияя на среду оболочки.
работает так, как вы ожидаете, потому что в этом случае обе функции объединяются: замена командной строки выполняется не вызывающей оболочкой, а оболочкой подпроцесса.
источник
x="once upon" y="a time" eval 'echo $x $y'
когда не задействован подпроцесс, поскольку онeval
является встроенным. Я думаю, что соответствующая цитата из справочной страницыThe environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments
. Рассматривая пример вопроса, он должен быть таким, посколькуread
он также является встроенным и работает с временно измененным состояниемIFS
.Команда вы предоставите отличается тем , что
$x
и$y
расширена до того вecho
запуске команды, поэтому их значение в текущей оболочке используется, а не значение , которыеecho
будут видеть в своей среде , если бы это было смотреть.источник
x
иy
предназначены для среды, в которойecho
выполняется, а не для среды, в которойecho
раскрываются аргументы . ИбоIFS=, read xx yy zz
вся строка читается, не разбираетсяread
командой. Затем , эта строка разделена в соответствии со значениемIFS
, с соответствующими частями , присвоенныхxx
,yy
иzz
.bash
сначала анализируется данная командная строка, распознается, что есть две переменные назначения для применения к среде поступающей команды, идентифицируется команда для run (echo
), расширяются все параметры, найденные в аргументах, затем запускается командаecho
с расширенными аргументами.echo
я не был уверен, сможет ли он «увидеть» переменную, поскольку это встроенная команда, и поэтому она не запускается в подоболочке, которая может иметь свою собственную среду. Но я попробовал его,eval
который также является встроенным, и он действительно знает об этом. Например, попытка,a=xyz eval 'echo $BASHPID $a; grep -z ^a /proc/$BASHPID/{,task/*}/environ'; echo $BASHPID $a
которая показывает, чтоa
устанавливается только внутри,eval
даже если pid одинаков и среда не изменяется во время eval! (Чтобы получить доступ,/proc
вам нужно запустить это под Linux.) Кажется, bash делает здесь дополнительную магию.Я собираюсь для большей картины " почему это законно"
Ответ: чтобы вы могли вызывать или вызывать программу, и для этого вызова используйте только переменную с определенной переменной.
Например: у вас есть параметр для соединения с базой данных, называемый 'db_connection', и обычно вы передаете 'test' в качестве имени для вашего тестового соединения с базой данных. На самом деле вы можете даже установить его как значение по умолчанию, которое вам не нужно передавать явно. Однако иногда вы хотите работать с базой данных ci. Таким образом, вы передаете параметр как 'ci', а затем вызываемая программа использует этот параметр базы данных в качестве имени базы данных для использования во всех вызовах базы данных. Для следующего запуска, если вы не повторяете подход и просто вызываете программу, переменная вернется к своему предыдущему значению по умолчанию.
источник
Вы также можете использовать
;
. Он будет оценен раньше, потому что это разделитель команд.источник