Как мне избежать подстановочного знака / звездочки в bash? - PullRequest
120 голосов
/ 19 сентября 2008

например.

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"?

Ответы [ 6 ]

118 голосов
/ 19 сентября 2008

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

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
91 голосов
/ 19 сентября 2008

КОРОТКИЙ ОТВЕТ

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

ДОЛГО ОТВЕТ

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

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

  1. Расширение параметра
  2. Расширение имени файла

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

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

46 голосов
/ 21 ноября 2012

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

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

$ echo "$FOO"

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

#!/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 голосов
/ 19 сентября 2008
FOO='BAR * BAR'
echo "$FOO"
3 голосов
/ 19 сентября 2008

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

В этом примере это не дает большого преимущества, но может быть более полезным при более сложном выводе.

FOO="BAR * BAR"
printf %s "$FOO"
3 голосов
/ 19 сентября 2008
echo "$FOO"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...