Я понимаю, что это !
имеет особое значение для командной строки в контексте истории командной строки, но, кроме этого, в рабочем скрипте восклицательный знак может иногда вызывать ошибку синтаксического анализа.
Я думаю , что это что - то делать с event
, но я понятия не имею , что такое событие или что он делает. Несмотря на это, одна и та же команда может вести себя по-разному в разных ситуациях.
Последний пример ниже вызывает ошибку; но почему, когда тот же код работал вне подстановки команд? .. используя GNU bash 4.1.5
# This works, with or without a space between ! and p
{ echo -e "foo\nbar" | sed -nre '/foo/! p'
echo -e "foo\nbar" | sed -nre '/foo/!p'; }
# bar
# bar
# This works, works when there is a space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/! p')"; echo "$var"
# bar
# This causes an ERROR, with NO space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/!p')"; echo "$var"
# bash: !p': event not found
bash
command-history
quoting
Peter.O
источник
источник
protected
было бы более подходящим. (защищено «одинарными кавычками»)var=$(…)
(без двойных кавычек), и это будет работать так, как вы думаете. Это все еще «безопасно», потому что часть значения простого присваивания не подвержена разбиению или смещению слов (хотя это может быть не так для присваиваний, выполняемых через встроенные функции (напримерexport
,local
и т. Д.) Во всех оболочках). К сожалению, это не выходит за рамки простых присваиваний, поскольку двойные кавычки - это способ защиты от разбиения и разбивки слов, в то же время получая другие типы раскрытия в других контекстах.Ответы:
!
Персонаж вызывает замену истории в Bash. Когда за ним следует строка (как в вашем неудачном примере), он пытается развернуться до последнего события истории, которое началось с этой строки. Точно так же, как$var
расширяется до значения этой строки,!echo
будет расширяться до последней команды эха в вашей истории.В таких расширениях пробел является символом разрушения. Сначала обратите внимание, как это будет работать с переменными:
То же самое произойдет для расширения истории. Символ взрыва (
!
) начинается с последовательности замены истории, но только если за ней следует строка. После пробела сделайте буквальный удар вместо части последовательности замены.Вы можете избежать такого рода замены для расширения переменных и истории, используя одинарные кавычки. В ваших первых примерах использовались одинарные кавычки, поэтому они работали нормально. Ваши последние примеры в двойных кавычках, и поэтому bash просканировал их на предмет последовательностей расширения, прежде чем что-либо делать. Единственная причина, по которой первая не сработала, заключается в том, что пробел является символом разрыва, как показано выше.
источник
var=word; echo "test '$var'"; echo 'test "$var"'
Как уже сказал Калеб ,
!
используется для вызова подмены истории bash.Если, как и я, вы чувствуете, что вам не нужна такая функция, вы можете отключить ее, вставив следующую строку
~/.bashrc
:Мне это не нужно, потому что история может быть восстановлена с помощью стрелки вверх и Ctrl- rинкрементального обратного поиска. См. Страницу руководства bash, раздел « Команды для манипулирования историей» для подробного списка ярлыков.
источник
!!
?set +H
в сценарии работает так же хорошо :) +1Ваш первый пример:
может быть уменьшено до
В одинарных кавычках все символы сохраняют свои буквальные значения. Таким образом
!
потерял свое особое значение и расширение истории не было сформировано.ваш второй и третий примеры:
может быть уменьшено до
'! p'
и'!p'
по существу являются частями строк в двойных кавычках.В двойных кавычках все символы сохраняют свои буквальные значения , за исключением
$
,`
,\
и!
.Это подразумевает одинарные кавычки
'! p'
и'!p'
утратило их особое значение (т.е. неспособность убежать!
), но!
все еще сохраняет свое особое значение, таким образом, выполняется расширение истории.Однако, когда
!
за ним следует символ пробела, расширение истории не выполняется.Цитирование из
man bash
:источник