Jak grep dla kart bez użycia literalnych kart i dlaczego nie działa?

146

Kiedy szukam tabulatorów w pliku za pomocą (e) grep, używam tabu literalnego ( ^v + <tab>). Nie mogę użyć \tjako zamiennika tabulatorów w wyrażeniach regularnych. W przypadku np. Sed wyrażenie to działa bardzo dobrze.

Czy jest więc jakakolwiek możliwość zastosowania nielitetycznego zamiennika <tab>i jakie są tła niedziałającego / nie interpretowanego \t?

Lasall
źródło
stackoverflow.com/questions/1825552/grep-a-tab-in-unix
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Odpowiedzi:

206

grep używa wyrażeń regularnych zdefiniowanych przez POSIX . Z jakichkolwiek powodów POSIX nie zdefiniował \tjako tab.

Masz kilka alternatyw:

  • powiedz grep, aby używał wyrażeń regularnych zdefiniowanych przez perl (perl ma \tjako tab):

    grep -P "\t" foo.txt

    strona podręcznika ostrzega, że ​​jest to funkcja „eksperymentalna”. przynajmniej \twydaje się działać dobrze. ale bardziej zaawansowane funkcje wyrażenia regularnego Perla mogą nie.

  • użyj printf, aby wydrukować znak tabulacji:

    grep "$(printf '\t')" foo.txt
  • użyj dosłownego znaku tabulacji:

    grep "^V<tab>" foo.txt

    to znaczy: wpisz grep ", a następnie naciśnij ctrl+v, następnie naciśnij tab, a następnie wpisz " foo.txt. naciśnięcie ctrl+vterminala powoduje, że następny klucz jest pobierany dosłownie. oznacza to, że terminal wstawi znak tabulacji zamiast wyzwalania jakiejś funkcji powiązanej z klawiszem tab.

  • użyj funkcji cytowania ansi bash:

    grep $'\t' foo.txt

    nie działa to we wszystkich powłokach.

  • użyj awk:

    awk '/\t/'
  • użyj sed:

    sed -n '/\t/p'

Zobacz artykuł w Wikipedii na temat wyrażeń regularnych, aby uzyskać przegląd zdefiniowanych klas znaków w POSIX i innych systemach.

lesmana
źródło
na podstawie odpowiedzi enzotibu dodaję: grep $'\t' foo.txt(ale zwykle pisałbym fgrepzamiast grep)
Walter Tross
Potrzebowałem tego w połączeniu z użyciem wartości zmiennej środowiskowej. Kiedyś grep "$(printf '\t')${myvar}" foo.txt. Działa dobrze. Po kilku próbach nie udało mi się uruchomić ostatniego formularza.
sancho.s
1
Czy jest jakiś powód, dla którego zwykły grepnie mógł po cichu interpretować \tjako tabulator? Czy POSIX wymaga, żeby to \toznaczało coś innego? Może powinien pasować tylko do literału, \ po którym następuje t?
Aaron McDaid
Być może warto zauważyć, że grep BSD (w tym OSX) nie ma opcji -P.
TextGeek
Ze strony podręcznika This is highly experimental and grep -P may warn of unimplemented features.Prawdopodobnie nie jest dobrym pomysłem do użycia -Pw starszych systemach. printfWybór jest lepszy
Avindra Goolcharan
13

Nie jest to dokładnie odpowiedź, którą chciałbyś usłyszeć, ale możliwe użycie sekwencji ucieczki zapewnia bash

command | grep $'\t'

(nie umieszczaj go w podwójnych cudzysłowach!).

enzotib
źródło
1
nie ma potrzeby używania -E (szukane to nie wyrażenie regularne). Nie ma również potrzeby przesyłania potokiem za pomocą polecenia. To powiedziawszy, dziękuję za zwrócenie uwagi na tę dość przeoczoną funkcję bash (ciągi cudzysłowu poprzedzone $)
Walter Tross
2
Rzeczywiście sugeruję, aby @enzotib edytował odpowiedź tak, aby była prosta grep $'\t'.
Teemu Leisti
Należy podkreślić, że jest to funkcja bash i (cicho!) Zrobi coś złego, jeśli zostanie wykonana przez inną powłokę (taką jak dash, która jest domyślna dla skryptów powłoki na Ubuntu i innych)
xjcl
2

awk '/\t/' to moje ulubione obejście:

printf 'a\t\nb' | awk '/\t/'

Wyjście: a\t.

Ciro Santilli
źródło
1

Zawsze można użyć szesnastkowego kodu ascii dla tab:

$ echo "one"$'\t'"two" > input.txt                                 

$ grep -P "\x9" input.txt                                          
one two

$ grep $'\x9' input.txt                                            
one two
Sergiy Kolodyazhnyy
źródło