Dlaczego „grep *” nie działa?

0

W dzisiejszych czasach ucząc się linux, znalazłem coś, co mnie zwierzyło :

$ cat abcd
line One
line Two
line Three
$ cat abcd | grep *
$ _                       //nothing greped
$ cat abcd | grep ""
line One
line Two
line Three
$ cat abcd | grep "*"
$ _                       //nothing greped

„_” to tylko kursor, nie pomyl się :)

kto by to wytłumaczył? Dzięki


źródło
Co to jest _? Na moim komputerze, to daje, _: command not found.
RRob
Co dokładnie miałbyś nadzieję cat abcd | grep *wydrukować?
RRob
to kursor, po prostu nie mrugaj tutaj :)

Odpowiedzi:

2

Glob *jest rozszerzany przez powłokę do alfabetycznej listy wszystkich (bez kropek) plików w bieżącym katalogu. Argumenty do grepto wyrażenie wyszukiwania i lista plików. Tak więc grep *kończy się na użyciu pierwszej nazwy pliku jako wyrażenia wyszukiwania. Szukasz nazwy pierwszego pliku (jako wyrażenia regularnego) w innych plikach.

Grep przeszukuje standardowe dane wejściowe tylko wtedy, gdy nie podasz żadnych jawnych nazw plików. Widzieć:

echo moo | grep . /etc/issue
Handmade Linux for OS/X v 0.001

Nawiasem mówiąc, *nie jest prawidłowym wyrażeniem regularnym. Jak odkryłeś, puste wyrażenie wyszukiwania pasuje do wszystkich linii wejściowych. Wyrażenie regularne pasujące do wszystkich niepustych linii wejściowych to .; w wyrażeniu regularnym kropka jest metaznakiem, który pasuje do jednego znaku, dowolnego znaku z wyjątkiem znaku nowej linii. Gwiazda kleene jest operatorem przyrostka, który pozwala na zero lub więcej powtórzeń poprzedniego wyrażenia regularnego, więc często widzisz regex .*dla „cokolwiek w ogóle”, ale w tym kontekście jest zbędny, ponieważ już nic nie dopasowujesz z pustym ciągiem wyszukiwania.

Wreszcie jest uważany za złą formę catpojedynczego pliku. Zamiast tego cat file | grep ""zapisz proces i być może pogardę , grepczytając plik bezpośrednio;grep "" file

potrójny
źródło
1

grep *Ma zamiar zrobić „masek” przeciw ekspansji plików w bieżącym katalogu.

Nie mogę dokładnie przewidzieć, co się stanie, ale z *pewnością będzie pasować do abcdnazwy pliku. Więc możesz skończyć wyszukiwanie „abcd” w abcdpliku. Lub może skończyć się wyszukiwaniem nazwy (leksykograficznie) pierwszego pliku w innych plikach.

Jeśli bieżący katalog byłby pusty, skończyłbyś na wyszukiwaniu *. Ale to też nie zadziała, ponieważ pierwszy argument wiersza poleceń jest wyrażeniem regularnym, a „*” nie jest poprawnym wyrażeniem regularnym.

Aby zapobiec globowaniu, napisz to:

$ cat abcd | grep "*"

... ale to nie ma sensu z podanego powyżej powodu.

Aby wyszukać dosłowny znak „*”:

$ cat abcd | grep "\\*"
Stephen C.
źródło
Najlepszym sposobem, aby dowiedzieć się, co by się stało, byłoby wypróbowanieecho *
Tak ... ale >> ja << nie mogę tego zrobić. Dlatego trudno mi przewidzieć, co się stanie :-)
Stephen C
1

Zanim grepzobaczy wiersz argumentu, ten argument jest analizowany przez powłokę. W przypadku powłoki *symbol wieloznaczny oznacza „wszystkie pliki bez kropek w bieżącym katalogu”. Ponieważ powłoka obsługuje argument jako pierwszy, twoja linia zmienia się w:

cat abcd | grep abcd otherfile zfile

(zakładając, że te trzy pliki znajdują się w bieżącym katalogu). To właśnie grepwidać z jej argumentów, ale nie jest to, czego chcesz.

Zamiast tego możesz umieścić wzorzec grepw cudzysłowie, aby nie był przetwarzany przez powłokę:

cat abcd | grep "*"

To lepiej, ale wciąż nie to, czego chcesz: grepużywa wyrażeń regularnych, a nie symboli wieloznacznych w stylu powłoki. Gwiazdka grepoznacza, że ​​„0..n powtórzeń poprzedniego znaku” - znak, którego nie określiłeś. Blisko, ale niezupełnie.

Jeśli chcesz mieć „dowolny” wzorzec, szukasz „0..n powtórzeń dowolnego znaku”. Ten ostatni jest reprezentowany przez kropkę ( '.') w wyrażeniach regularnych:

cat abcd | grep ".*"

Tego właśnie szukałeś.

Edycja: Drugi przypadek można łatwiej wyjaśnić. Podczas grep ""gdy szukasz pustego łańcucha, który jest obecny jako podciąg w dowolnym łańcuchu.

DevSolar
źródło
Tyle że catjest bezużyteczny i wyrażenie regularne jest bezużyteczne. partmaps.org/era/unix/award.html
tripleee
@tripleee: Widziałem tę „nagrodę” rozrzuconą z radością na stronach takich jak SO. Nie sądzę, żeby to było właściwe. Nie mówimy tutaj o kodzie produkcyjnym; catw tym przykładzie jest to ogólny stand-in „kiedy jestem grepping jakąś arbitralną standardowe wejście”. Odpowiedź jest łatwiejsza do zrozumienia, gdy nie zamienia abstrakcyjnego przykładu w coś zupełnie innego tylko po to, aby pokazać swoje umiejętności w zakresie unikania „niepotrzebnych” zastosowań cat- ale pozostaje przy oryginalnym kodzie i pokazuje kilka zwrotów, które są faktycznie związane z rdzeniem pytania.
DevSolar
Uważam to za błędne; odpowiedź, która nie wyjaśnia stycznych i zastrzeżeń, jest po prostu mniej cenna niż odpowiedź, która również stara się zapewnić, że podstawowe podejście jest prawidłowe. To nie jest tak złe, jak odpowiedzi „próbuj chmod 0777 *”, które czasem widzisz, ale w podejściu „po prostu napraw objawy” występuje pewna podobieństwo.
tripleee
@triplee: Nie omawiam nawiasów trzy vs. cztery wcięcia ani nawiasów eqyptian vs. ANSI podczas odpowiadania, chyba że jest to aktualne. Pomiędzy byciem bardzo pomocnym a protekcjonalnym istnieje cienka granica.
DevSolar
Świetne wyjaśnienie! Ale wciąż pozostaje pytanie: dlaczego i jak $ cat abcd | grep ""działa? Mam na myśli to, że jest to tylko pusty ciąg, od czego różni się ( ""), "*"a jednocześnie "*"nic nie pasuje?
0

Bash zawsze analizuje * jako symbole zastępcze symboli zastępczych dla pliku w katalogu. W twoim poleceniu bash przyjmuje to jako

cat abcd | grep abcd file1 file2 ...

więc pokazuje tylko puste dane wyjściowe, ponieważ nie jest to, czego szukasz


źródło
Nie zawsze. Jeśli *jest cytowany, nie będzie.
Stephen C