КОРОТКИЙ ОТВЕТ
Как уже говорили другие - вы всегда должны заключать в кавычки переменные, чтобы избежать странного поведения. Поэтому используйте 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», потому что расширение имени файла предотвращается с помощью escape.
Так почему же использование $ foo не работает?
Дело в том, что происходит третье расширение - удаление цитаты. Из bash ручное удаление цитаты это:
После предыдущих расширений все
вхождения без кавычек персонажей
‘\’, ‘'’ И ‘" ’, которые не привели
из одного из приведенных выше расширений
удален.
Так что происходит, когда вы вводите команду непосредственно в командной строке, escape-символ не является результатом предыдущего раскрытия, поэтому BASH удаляет его перед отправкой в команду echo, но во 2-м примере, "\ * "был результатом предыдущего расширения параметра, поэтому он НЕ удаляется. В результате эхо получает «\ *», и это то, что он печатает.
Обратите внимание на разницу между первым примером - "*" не входит в символы, которые будут удалены с помощью удаления цитаты.
Надеюсь, это имеет смысл. В конце концов вывод тот же - просто используйте кавычки. Я просто подумал, что объясню, почему экранирование, которое по логике должно сработать, если в игру включены только расширения параметров и имен файлов,
Для полного объяснения расширений BASH обратитесь к:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions