Как избежать символа подстановки/звездочки в bash?

например.

me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR

и используя escape-символ "\":

me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR

Я, очевидно, делаю что-то глупое.

Как получить выход "BAR * BAR"?

Ответ 1

Цитата при установке $FOO недостаточно. Вы также должны указать ссылку на переменную:

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR

Ответ 2

SHORT ANSWER

Как и другие, вы всегда должны указывать переменные, чтобы предотвратить странное поведение. Поэтому вместо echo $foo используйте echo "$ foo".

ДОЛГОЙ ОТВЕТ

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

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

  • Расширение параметров
  • Расширение имени файла

Итак, из вашего первого примера:

me$ FOO="BAR * BAR"
me$ echo $FOO

После расширения параметра эквивалентно:

me$ echo BAR * BAR

И после расширения имени файла эквивалентно:

me$ echo BAR file1 file2 file3 file4 BAR

И если вы просто наберете echo BAR * BAR в командной строке, вы увидите, что они эквивалентны.

Итак, вы, вероятно, подумали о себе: "если я уйду из *, я могу предотвратить расширение имени файла"

Итак, из вашего второго примера:

me$ FOO="BAR \* BAR"
me$ echo $FOO

После расширения параметра должно быть эквивалентно:

me$ echo BAR \* BAR

И после расширения имени файла должно быть эквивалентно:

me$ echo BAR \* BAR

И если вы попытаетесь ввести "echo BAR\* BAR" непосредственно в командной строке, он действительно напечатает "BAR * BAR", потому что расширение файла предотвращается побегом.

Так почему же использование $foo не работает?

Это потому, что есть третье расширение, которое имеет место - Снятие цитаты. Из bash удаления цитаты вручную:

После предыдущих расширений все неупорядоченные вхождения символов '\,' 'И' ', что не привело из одного из указанных выше расширений удалены.

Итак, что происходит, когда вы вводите команду непосредственно в командную строку, escape-символ не является результатом предыдущего расширения, поэтому bash удаляет его перед отправкой в ​​команду echo, но во втором примере "\ *" был результатом предыдущего расширения параметра, поэтому он НЕ удаляется. В результате эхо получает "\ *" и то, что он печатает.

Обратите внимание, что разница между первым примером - "*" не включена в символы, которые будут удалены с помощью удаления цитаты.

Надеюсь, это имеет смысл. В заключение вывод в том же - просто используйте цитаты. Я просто подумал, что я объясню, почему ускользает, что логически должно работать, если играется только параметр и имя файла, не работает.

Для полного объяснения разложений bash см.:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

Ответ 3

Я немного добавлю этот старый поток.

Обычно вы используете

$ echo "$FOO"

Однако у меня были проблемы даже с этим синтаксисом. Рассмотрим следующее script.

#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"

* необходимо передать дословно curl, но будут возникать те же проблемы. Вышеприведенный пример не будет работать (он будет расширяться до имен файлов в текущем каталоге), и не будет \*. Вы также не можете процитировать $curl_opts, потому что он будет признан одним (недопустимым) параметром curl.

curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information

Поэтому я бы рекомендовал использовать переменную bash $GLOBIGNORE, чтобы предотвратить расширение имени файла вообще при применении к глобальному шаблону или использовать встроенный флаг set -f.

#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"  ## no filename expansion

Применение к исходному примеру:

me$ FOO="BAR * BAR"

me$ echo $FOO
BAR file1 file2 file3 file4 BAR

me$ set -f
me$ echo $FOO
BAR * BAR

me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR

Ответ 4

FOO='BAR * BAR'
echo "$FOO"

Ответ 5

echo "$FOO"

Ответ 6

Возможно, стоит привыкнуть использовать printf, а не echo в командной строке.

В этом примере это не приносит большой пользы, но может быть более полезным при более сложном выходе.

FOO="BAR * BAR"
printf %s "$FOO"