Zdaję sobie sprawę, że !
ma to szczególne znaczenie w wierszu poleceń w kontekście historii wiersza poleceń, ale poza tym w wykrywającym skrypcie wykrzyknik może czasami powodować błąd analizy.
Myślę, że ma to coś wspólnego z event
, ale nie mam pojęcia, co to za wydarzenie lub co robi. Mimo to to samo polecenie może zachowywać się inaczej w różnych sytuacjach.
Ostatni przykład poniżej powoduje błąd; ale dlaczego, kiedy ten sam kod działał poza podstawieniem polecenia? .. używając 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
źródło
źródło
protected
Byłoby bardziej odpowiednie. (chronione przez „pojedyncze cudzysłowy”)var=$(…)
(bez podwójnych cudzysłowów) i będzie działać tak, jak oczekuję. Jest jeszcze „bezpieczne”, ponieważ część wartość przypisania prostego nie podlega podziałowi na słowa lub globbing (choć może to nie być prawdą zadań wykonanych przez poleceń wbudowanych (npexport
,local
itp) we wszystkich muszli). Niestety, nie wykracza to poza proste przypisania, ponieważ podwójne cudzysłowy są sposobem ochrony przed dzieleniem słów i dzieleniem tekstu, a jednocześnie zapewniają inne rodzaje ekspansji w innych kontekstach.Odpowiedzi:
!
Charakter przywołuje historię podstawienie atakujących za. Po którym następuje ciąg znaków (jak w twoim przypadku, w którym nie powiodło się), próbuje rozwinąć się do ostatniego zdarzenia historii, które rozpoczęło się od tego ciągu. Podobnie jak$var
zostanie rozwinięty do wartości tego ciągu,!echo
rozwinąłby się do ostatniego polecenia echa w twojej historii.W takich rozszerzeniach przestrzeń jest przełomową postacią. Pierwsza uwaga, jak to by działało ze zmiennymi:
To samo stanie się z rozszerzeniem historii. Znak huku (
!
) rozpoczyna sekwencję zastępującą historię, ale tylko wtedy, gdy następuje po nim ciąg znaków. Podążając za spacją, uczyń to dosłownie hukiem zamiast częścią sekwencji zastępowania.Można uniknąć tego rodzaju zamiany zarówno dla zmiennej, jak i historii, używając pojedynczych cudzysłowów. Twoje pierwsze przykłady używały pojedynczych cudzysłowów, więc działały dobrze. Twoje ostatnie przykłady są w podwójnych cudzysłowach, dlatego bash skanował je w poszukiwaniu sekwencji ekspansji, zanim zrobił cokolwiek innego. Jedynym powodem, dla którego pierwszy się nie potknął, jest to, że spacja jest znakiem przerwania, jak pokazano powyżej.
źródło
var=word; echo "test '$var'"; echo 'test "$var"'
Jak już powiedział Caleb ,
!
służy do wywołania podstawienia historii basha.Jeśli tak jak ja czujesz, że nie potrzebujesz takiej funkcji, możesz ją wyłączyć, wstawiając następujący wiersz
~/.bashrc
:Nie potrzebuję tego, ponieważ historię można odzyskać za pomocą strzałki w górę i Ctrl- rprzyrostowego wyszukiwania wstecznego. Zobacz stronę podręcznika bash, sekcja Polecenia do manipulowania historią, aby uzyskać szczegółową listę skrótów.
źródło
!!
?set +H
w skrypcie działa równie dobrze :) +1twój pierwszy przykład:
można zredukować do
W pojedynczych cudzysłowach wszystkie znaki zachowują swoje dosłowne wartości. W
!
ten sposób utraciło swoje szczególne znaczenie, a ekspansja historii nie jest przeprowadzana.twój drugi i trzeci przykład:
można zredukować do
'! p'
i'!p'
są zasadniczo częściami podwójnie cytowanych ciągów.Wewnątrz cudzysłowów wszystkie znaki zachować ich wartości literalne except
$
,`
,\
i!
.Oznacza to, że pojedyncze cytaty
'! p'
i'!p'
utraciły swoje specjalne znaczenie (tj. „Niezdolność do ucieczki”!
), ale!
nadal zachowują swoje specjalne znaczenie, dlatego następuje ekspansja historii.Jednak
!
po znaku spacji rozszerzenie historii nie jest wykonywane.Cytowanie z
man bash
:źródło