Учитывая следующий синтаксис:
x=(-a 2);echo "${x[@]}";x=(-e 2 -e); echo "${x[@]}"
Вывод:
-a 2
2 -e
Требуемый вывод
-a 2
-e 2 -e
Почему это происходит? Как я могу исправить?
Учитывая следующий синтаксис:
x=(-a 2);echo "${x[@]}";x=(-e 2 -e); echo "${x[@]}"
Вывод:
-a 2
2 -e
Требуемый вывод
-a 2
-e 2 -e
Почему это происходит? Как я могу исправить?
printf "%s\n" "${x[*]}"
echo
принимает 3 варианта:
$ help echo
[…]
Options:
-n do not append a newline
-e enable interpretation of the following backslash escapes
-E explicitly suppress interpretation of backslash escapes
Итак, если вы запустите:
$ echo -n
$ echo -n -e
$ echo -n -e -E
Вы ничего не получите. Даже если вы поместите каждую опцию в кавычки, она по-прежнему выглядит так же, как и bash:
$ echo "-n"
$ echo "-n" "-e"
Последняя команда запускает echo
с двумя аргументами: -n
и -e
. Теперь сравните это с:
$ echo "-n -e"
-n -e
Мы выполнили echo
с одним аргументом: -n -e
. Поскольку bash не распознает (комбинированный) вариант -n -e
, он, наконец, перекликается с единственным аргументом терминала, как мы хотим.
Во втором случае массив x
начинается с элемента -e
. После того, как bash расширяет массив ${x[@]}
, вы эффективно выполняете:
$ echo "-e" "2" "-e"
2 -e
Поскольку первый аргумент -e
, он интерпретируется как опция (вместо эхо-сигнала для терминала), как мы уже видели.
Теперь сравним это с другим стилем расширения массива ${x[*]}
, который эффективно выполняет следующее:
$ echo "-e 2 -e"
-e 2 -e
bash видит единственный аргумент -e 2 -e
- и поскольку он не распознает это как опцию - он перекликается с аргументом терминала.
Обратите внимание, что ${x[*]}
расширение стиля вообще не безопасно. Возьмем следующий пример:
$ x=(-e)
$ echo "${x[*]}"
Ничего не печатается, хотя мы ожидали, что -e
будет отображаться эхом. Если вы обратили внимание, вы уже знаете, почему это так.
Решение состоит в том, чтобы избежать любых аргументов команды echo
. К сожалению, в отличие от других команд, которые предлагают какой-то способ сказать: "Эй, следующий аргумент не должен интерпретироваться как опция" (как правило, аргумент --
), bash не обеспечивает такого экранирования механизм для echo
.
К счастью, существует команда printf
, которая обеспечивает надстройку функциональности, предлагаемой echo
. Следовательно, мы приходим к решению:
printf "%s\n" "${x[*]}"
Хороший!
Что происходит, первый -e
интерпретируется как опция для эха (чтобы включить escape-последовательности)
Обычно вы делаете что-то вроде echo -- "-e"
, и оно должно просто печатать -e
, но echo с удовольствием ведет себя по-другому и просто выводит -- -e
как целую строку.
echo не интерпретирует - значит конец опций.
Решение проблемы также можно найти на страницах руководства:
Из-за псевдонимов оболочки и встроенной команды
echo
, используя незакрашенныеecho
в интерактивном режиме или в script может получить различную функциональность чем описано здесь. Вызовите его черезenv
(т.е.env echo ...
) чтобы избежать помех от оболочки.
Итак, что-то вроде этого должно работать:
x=(-a 2);echo "${x[@]}";x=(-e 2 -e); env echo "${x[@]}"
Ответ @MichaelKropat дает достаточные объяснения.
В качестве альтернативы echo
(и printf
), cat
и bash here-string можно использовать:
$ x=(-a 2);cat <<< "${x[@]}";x=(-e 2 -e); cat <<< "${x[@]}"
-a 2
-e 2 -e
$