Bash - Запуск нескольких команд с использованием оценки строки
Я пытаюсь создать сценарий оболочки, который объединяет несколько команд в строку, а затем выполняет команды.
Следующее успешно (Создает файлы 'y' и 'z' и печатает вывод ls):
$ /bin/touch /z && ls && /bin/touch /y
Но следующее не удается (создает файлы 'y' и 'z', но также файлы '&&' и 'ls')
$ A="/bin/touch /z && ls && /bin/touch /y"
$ $A
Кажется, что при выполнении строки с помощью $A
двоичный файл touch
получает остальную часть строки в качестве параметров и &&
Оператор не выполняется как задумано.
(Я тоже пробовал переключаться &&
с ;
, ||
и такой но получил такой же результат)
Я узнал eval $A
делает трюк, но мне все еще интересно, почему это происходит.
(И, возможно, хотите пропустить необходимость оценки)
Спасибо!
1 ответ
Вообще говоря, есть две стадии оценки командной строки: разбор и расширение.
Когда вы вводите
/bin/touch /z && ls && /bin/touch /y
строка сначала разбирается в предварительную серию слов, разделенных пробелами:
/bin/touch
/z
&&
ls
&&
/bin/touch
/y
На этом этапе он признает &&
s как разделение списка простых команд, состоящих из следующих слов:
/bin/touch
,/z
ls
/bin/touch
,/y
Теперь он применяет набор расширений к каждому слову, пытаясь создать больше слов. В этом случае расширять нечего, и каждая простая команда проверяется снова, чтобы определить саму команду и ее аргументы:
- команда
/bin/touch
аргумент/z
- команда
ls
без аргументов - команда
/bin/touch
аргумент/y
В случае $A
Парсинг прост: есть одно слово $A
в предварительной серии. Это слово затем подвергается расширению; единственное релевантное - это расширение параметров, которое создает тот же список слов, который был идентифицирован на шаге разбора первого примера. Разница здесь в том, что список не подвергается дальнейшему расширению; не время определять имя команды и ее аргументы.
команда
/bin/touch
с аргументами.../z
&&
ls
&&
/bin/touch
/y
Строка практически никогда не является правильным способом связать набор команд. Что вы хотите сделать, это определить функцию
a () {
/bin/touch /z && ls && /bin/touch /y
}
который вы затем используете как обычную команду:
$ a
/z
$ ls
/z
/y