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

StackOverflow https://stackoverflow.com/questions/102049

  •  01-07-2019
  •  | 
  •  

Вопрос

например.

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

Это было полезно?

Решение

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

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

Другие советы

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

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

ДЛИННЫЙ ОТВЕТ

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

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

  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, но во втором примере "\*" был результат предыдущего расширения параметра, поэтому он НЕ удаляется.В результате echo получает «\*» и печатает именно это.

Обратите внимание на разницу между первым примером: «*» не входит в число символов, которые будут удалены при удалении кавычек.

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

Полное объяснение расширений BASH см. в разделе:

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

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

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

$ 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
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"

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

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

FOO="BAR * BAR"
printf %s "$FOO"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top