Различное поведение eval "command \" $ @ \ "", "$ @" и "$ (echo $ @)" при использовании в качестве аргументов

Я хотел бы передать несколько аргументов в браузер Tor (firefox) программно через функцию, произвольно tor . Это так, чтобы командовать tor search terms и вуаля! Мои поисковые запросы. При использовании этих трех вариантов,

 ~/tor-browser_en-US/Browser/start-tor-browser -search "$(echo $@)" eval "~/tor-browser_en-US/Browser/start-tor-browser -search \"$@\"" ~/tor-browser_en-US/Browser/start-tor-browser -search "$@" 

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

Почему это поведение?

Позвольте пояснить. Я не ищу обходных решений, а просто интересуюсь объяснением в отношении bahviour.

  • Объединить ассоциативные массивы Bash
  • Авторизация в SSH-соединении в OneLine
  • Печать цветного текста с использованием скрипта
  • Получить путь к текущему отмеченному файлу
  • Источник «gsed: не может читать: нет такого файла или каталога»?
  • Сохранение целочисленных значений из строки в rrd
  • Заменить несколько строк в текстовом файле фиксированным шаблоном
  • Основной скрипт в Angstrom Linux работает на Beaglebone Black
  • 2 Solutions collect form web for “Различное поведение eval "command \" $ @ \ "", "$ @" и "$ (echo $ @)" при использовании в качестве аргументов”

    Для третьей версии вы хотите "$*" не "$@" .

    объяснение

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

     $ set -- arg1 arg2 arg3 

    Теперь давайте прочитаем их с вашей формулировкой echo :

     $ printf "%s\n" "$(echo $@)" arg1 arg2 arg3 

    Посмотрим, что с ними "$@" :

     $ printf "%s\n" "$@" arg1 arg2 arg3 

    Разница в том, что "$@" расширяется до трех слов, а "$(echo $@)" расширяется до одной строки. Если вам нужно поведение типа "$(echo $@)" , вы должны использовать "$*" :

     $ printf "%s\n" "$*" arg1 arg2 arg3 

    Документация

    От man bash :

    "$*" создает одну строку:

    «$ *» эквивалентен «$ 1c $ 2c …», где c – первый символ значения переменной IFS.

    Напротив, man bash утверждает, что $@ создает ряд слов:

    «$ @» эквивалентен «$ 1» «$ 2» …

    Использование eval

    Заметим:

     $ echo 'printf "%s\n" "' "$@" '"' printf "%s\n" " arg1 arg2 arg3 " 

    Когда bash оценивает команду echo , "$@" расширяется для разделения слов. echo принимает эти отдельные слова и объединяет их в одну строку. Мы видели это раньше, когда смотрим на "$(echo $@)" . Аналогично работает eval . Он выводит одну строку из всех своих аргументов и оценивает эту строку. Таким образом:

     $ eval 'printf "%s\n" "' "$@" '"' arg1 arg2 arg3 

    Это также документировано man bash :

    eval [arg …]
    Аргенты считываются и объединяются вместе в одну команду. Затем эта команда считывается и выполняется оболочкой, …

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

     $ set "ab" c "de" $ printf "%s\n" "$@" ab c de 

    Предыдущее – это то, что вы должны использовать; это просто, легко понять и исправить.

     $ printf "%s\n" "$(echo $@)" abcde 

    Здесь $@ сначала расшифровывается без кавычек (кавычки, связанные с подстановкой команд, являются отдельными и еще не применены), поэтому он эквивалентен $(echo abcde) , а printf имеет один дополнительный аргумент после строки формата.

     $ eval "printf \"%s\n\" \"$@\"" abcde 

    Здесь цитируется $@ , но расширение создает 3 отдельных аргумента для eval ( printf "%s\n" ab , c и de ), которые объединены в одну команду, которая производит тот же вывод, что и номер 2 выше.

    Linux и Unix - лучшая ОС в мире.