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 как разделение списка простых команд, состоящих из следующих слов:

  1. /bin/touch, /z
  2. ls
  3. /bin/touch, /y

Теперь он применяет набор расширений к каждому слову, пытаясь создать больше слов. В этом случае расширять нечего, и каждая простая команда проверяется снова, чтобы определить саму команду и ее аргументы:

  1. команда /bin/touchаргумент /z
  2. команда lsбез аргументов
  3. команда /bin/touchаргумент /y

В случае $AПарсинг прост: есть одно слово $A в предварительной серии. Это слово затем подвергается расширению; единственное релевантное - это расширение параметров, которое создает тот же список слов, который был идентифицирован на шаге разбора первого примера. Разница здесь в том, что список не подвергается дальнейшему расширению; не время определять имя команды и ее аргументы.

  1. команда /bin/touchс аргументами...

    1. /z
    2. &&
    3. ls
    4. &&
    5. /bin/touch
    6. /y

Строка практически никогда не является правильным способом связать набор команд. Что вы хотите сделать, это определить функцию

a () {
  /bin/touch /z && ls && /bin/touch /y
}

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

$ a
/z
$ ls
/z
/y
Другие вопросы по тегам