Chcę wyszukać wiersze zawierające dowolny z następujących znaków:
:
/
/
?
#
[
]
@
!
$
&
"
(
)
*
+
,
;
=
%
Odpowiedź
grep "[]:/?#@\!\$&"()*+,;=%[]"
W wyrażeniu w nawiasach kwadratowych, [...]
, jest bardzo mało znaków ” specjalny ” (tylko bardzo mały podzbiór, na przykład ]
, -
i ^
oraz trzy kombinacje [=
, [:
i [.
). Włączając ]
do [...]
, ]
musi znajdować się na pierwszym miejscu (prawdopodobnie po ^
). Zdecydowałem się umieścić ]
jako pierwsze, a [
na końcu dla symetrii.
Jedyną inną rzeczą do zapamiętania jest że pojedynczy cudzysłów nie może zawierać pojedynczego cudzysłowu, więc używamy podwójnych cudzysłowów wokół wyrażenia. Ponieważ używamy łańcucha w podwójnych cudzysłowach, powłoka będzie w nim przeszukiwać, aby coś się rozszerzyć. Z tego powodu pomijamy $
jako \$
, co spowoduje, że powłoka nada literał $
do grep
i uciekamy z !
jako \!
, bo to też historia rozwijanie w bash
(choć tylko w interaktywnych bash
powłokach).
Czy chcesz dołączyć ukośnik odwrotny do ustaw, musisz zmienić jego znaczenie jako \\
, tak aby powłoka nadała pojedynczy ukośnik odwrotny do grep
. Ponadto, jeśli chcesz uwzględnić odwrotny znacznik `
, również musi być zapisany jako \`
, ponieważ w przeciwnym razie rozpoczyna zastępowanie polecenia.
Polecenie powyżej wyodrębniłby każdy wiersz, który zawierał co najmniej jeden ze znaków w wyrażeniu w nawiasach.
Użycie pojedynczego cudzysłowu zamiast podwójnego cudzysłowu, co pozwala obejść większość niedogodności jakie znaki interpretuje powłoka:
grep "[]:/?#@!$&"""""()*+,;=%[]"
Tutaj jedyna rzecz do zapamiętania oprócz umieszczenia ]
jest taki, że pojedynczy cytowany ciąg nie może zawierać pojedynczego cudzysłowu, więc zamiast tego używamy konkatenacji trzech ciągów:
-
"[]:/?#@!$&"
-
"""
-
"()*+,;=%[]"
Innym podejściem byłoby użycie klasy znaków POSIX [[:punct:]]
. Dopasowuje pojedynczy znak ze zbioru !"#$%&"()*+,-./:;<=>?@[\]^_`{|}~
, który jest większym zestawem niż to, co podano w pytaniu (dodatkowo zawiera "-.<>^_`{|}~
), ale to wszystkie ” znaki interpunkcyjne „, które definiuje POSIX.
LC_ALL=C grep "[[:punct:]]"
Komentarze
Odpowiedź
Możesz użyć klasy znaków [:punct:]
, jeśli nie ważne, że pasuje również do innych znaków interpunkcyjnych i specjalnych:
grep "[[:punct:]]" file
Komentarze
-
punct
klasa znaków (nie makro) pasuje do!"#$%&'()*+,-./:;<=>?@[\]^_
{|} ~ `w języku C, który jest nieco większym zestawem znaków niż co ma użytkownik, ale może być wystarczająco dobre.
Odpowiedź
Możesz użyć pełnego wyrażenia regularnego, aby znaleźć znaki specjalne w nawiasach kwadratowych, jeśli szukasz jednego znaku, który jest znakiem specjalnym. Świetnym źródłem ćwiczenia, nauki i sprawdzania wyrażeń regularnych jest regex101.com .
Używa wyrażeń regularnych Perla, których można używać z GNU grep z opcją -P
:
grep -P "(\:|\/|\?|\#|\@|\!|\\$|\&|\"|\(|\)|\*|\+|\,|\;|\=|\%|\[|\])" ^^^
Zauważ, że potrzebujesz dwóch backsl popiół przed znakiem dolara, ponieważ ma on specjalne znaczenie w powłoce, a pierwszy lewy ukośnik zostanie usunięty z powłoki. (Z tylko jednym ukośnikiem odwrotnym na początku, powłoka usuwałaby ukośnik odwrotny, grep
widziałby znak dolara bez znaku zmiany znaczenia oznaczający koniec wiersza i pasowałby do dowolnego wiersza wprowadzania.)
Jeśli twój terminal obsługuje kolory, włącz również kolory,
grep --color=auto -P "(\:|\/|\?|\#|\@|\!|\\$|\&|\"|\(|\)|\*|\+|\,|\;|\=|\%|\[|\])"
Oto wyjaśnienie mojego wyrażenia regularnego z regex101.com
/(\:|\/|\?|\#|\@|\!|\$|\&|\"|\(|\)|\*|\+|\,|\;|\=|\%|\[|\])/gm 1st Capturing Group (\:|\/|\?|\#|\@|\!|\$|\&|\"|\(|\)|\*|\+|\,|\;|\=|\%|\[|\]) \: matches the character : literally (case sensitive) \/ matches the character / literally (case sensitive) \? matches the character ? literally (case sensitive) \# matches the character # literally (case sensitive) \@ matches the character @ literally (case sensitive) \! matches the character ! literally (case sensitive) \$ matches the character $ literally (case sensitive) \& matches the character & literally (case sensitive) \" matches the character " literally (case sensitive) \( matches the character ( literally (case sensitive) \) matches the character ) literally (case sensitive) \* matches the character * literally (case sensitive) \+ matches the character + literally (case sensitive) \, matches the character , literally (case sensitive) \; matches the character ; literally (case sensitive) \= matches the character = literally (case sensitive) \% matches the character % literally (case sensitive) \[ matches the character [ literally (case sensitive) \] matches the character ] literally (case sensitive)
Komentarze
- Nie, w przypadku standardowego ERE nie można ' ominąć zamykającego
]
z odwrotnym ukośnikiem. ukośnik odwrotny nie jest specjalnym wyrażeniem w nawiasach. Aby]
wewnątrz wyrażenia nawiasowego, musi znajdować się jako pierwsze:[]other]
, a nie[ot\]her]
. To ' różni się od PCRE, które domyślnie opisują wyrażenie regularne. - Będzie działać z
pcregrep
lub GNUgrep -P
, chociaż. I w pewnym sensie zachowanie Perla jest prostsze: odwrotny ukośnik zawsze sprawia, że znak specjalny jest normalny. - Poprawiono na -P, przepraszam za to, pomieszano -E i -P
$
tam! Dzięki!bash: !\: event not found
.bash
! 🙂 Ucieknij z!
też … Nie będącbash
użytkownik Zapomniałem o tym. Zaktualizuję …"[\!]"
rozwija się do[\!]
nawet jeśli włączone jest rozwijanie historii, więc będzie pasować po odwrotnym ukośniku. ' d potrzebujesz pojedynczych cudzysłowów lub użyj\!
outsi de of quotes.bash
,zsh
ma również tę irytującą funkcję odziedziczoną z csh. w csh,!
specjalne wewnątrz'...'
, a także gdy nie jest interaktywne. Jednak wcsh
(w przeciwieństwie do bash lub zsh), użycie"\!"
będzie działać tutaj (ukośnik odwrotny jest usuwany).