grep "^$1" trochę działa, ale jak uciec "$1" więc grep nie „nie interpretuje specjalnie żadnych zawartych w nim znaków?

A może jest lepszy sposób?

Edycja: Nie chcę szukać "^$1", ale dynamicznie wstawianego stałego ciągu, który powinien być dopasowane, jeśli znajduje się na początku wiersza. To właśnie miałem na myśli przez $1.

Komentarze

  • Czy próbowałeś użyć pojedynczych cudzysłowów zamiast podwójnych, np grep '^$1'? A może nie ' czy masz na myśli, że chcesz zapobiec rozszerzaniu $1 przez powłokę?
  • @mnille Nie ' nie chcę szukać ' ^ $ 1 ', ale dynamicznie wstawianego ustalony ciąg, który powinien być dopasowywany tylko wtedy, gdy ' znajduje się na początku wiersza. To ' miałem na myśli przez dolara.
  • Możesz to zrobić za pomocą grep, ale ' Najpierw będę musiał zmienić znaczenie dowolnego znaku specjalnego w ciągu, np. printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti, które ' są lepsze niż niektóre inne odpowiedzi. Chcesz to zrobić?
  • @roaima – wiem, ale ' jest już tutaj kilka odpowiedzi, a to (z pominięciem znaków specjalnych wewnątrz vars) jest coś, co ja (i kilku innych użytkowników tutaj) wbijaliśmy w stronę od dłuższego czasu … Zawsze możesz dodać to do swojej odpowiedzi, jeśli chcesz, a ja ' usunę skomentuj tutaj (nie ' nie zapomnij dodać brakującego nawiasu początkowego).

Odpowiedz

Nie mogę wymyślić sposobu, aby to zrobić za pomocą grep; ^ jest częścią wyrażenie regularne, więc użycie go wymaga interpretacji wyrażeń regularnych. Jest to trywialne przy dopasowywaniu podciągów w awk, perl lub czymkolwiek:

awk -v search="$1" "substr($0, 1, length(search)) == search { print }" 

Aby obsłużyć wyszukiwane ciągi zawierające \, możesz użyć tej samej sztuczki co w odpowiedź 123 :

search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }" 

Komentarze

  • To wygrało ' nie działa dla ciągów takich jako \/
  • @ 123 rzeczywiście, ' dodałem wariant, aby to obsłużyć.
  • Nadal nie powiedzie się w przypadku skomplikowanych ciągów, takich jak \\\/\/\/\\\\/, które są widoczne w programie jako \\///\\/. O ile mi wiadomo, nie ma sposobu na poprawne uniknięcie ukośników odwrotnych w awk, chyba że wiesz wcześniej, ile z nich zostanie użytych.
  • @ 123 dzięki, ' dostosowaliśmy twoją sztuczkę przechodzenia przez środowisko, aby uniknąć przetwarzania danych.
  • Nadal podoba mi się to rozwiązanie najbardziej. Wydajne (awk + bez marnowania czasu na rozglądanie się), szybkie uruchamianie (awk + brak dodatkowych procesów potrzebnych do ustawienia stanu) wykorzystuje standardowe narzędzia i jest dość zwięzłe. W pozostałych odpowiedziach brakuje przynajmniej części z nich. (Wydajność jest tutaj mocną stroną, ponieważ grep jest znany z niezrównanej szybkości).

Odpowiedź

Jeśli tylko trzeba sprawdzić, czy znaleziono dopasowanie, przyciąć wszystkie wiersze wejściowe do długości żądanego prefiksu ($1), a następnie użyć polecenia grep o ustalonym wzorze:

if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi 

Łatwo jest również uzyskać liczbę pasujących wierszy:

cut -c 1-"${#1}" | grep -cF "$1" 

Lub numery wierszy wszystkie pasujące wiersze (numery wierszy zaczynają się od 1):

cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1 

Możesz wprowadzić numery wierszy do head i tail, aby uzyskać pełny tekst pasujących wierszy, ale w tym momencie łatwiej jest po prostu sięgnąć po nowoczesny język skryptowy, taki jak Python lub Ruby.

(Powyższe przykłady zakładają, że Posix grep i cut. Zakładają, że plik do przeszukania pochodzi ze standardowego wejścia, ale można go łatwo dostosować do przyjęcia nazwy pliku.)

Edycja: Należy również upewnić się, że wzorzec ( ) nie jest ciągiem o zerowej długości. W przeciwnym razie cut nie powiedzie się, mówiąc values may not include zero. Ponadto, jeśli używasz Bash, użyj set -o pipefail, aby wychwycić błędy wyjścia przez cut.

Odpowiedź

Sposób używania perla, który będzie respektować odwrotne ukośniki

v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file 

To ustawia zmienną środowiskową v dla polecenie, następnie wyświetla, jeśli indeks zmiennej wynosi 0, tj. początek wiersza.

Tak samo możesz zrobić w awk

v="$1" awk "index($0, ENVIRON["v"])==1" file 

Odpowiedz

Tutaj jest opcja all-bash, nie żebym polecał bash do przetwarzania tekstu, ale działa.

#!/usr/bin/env bash # searches for $1 at the beginning of the line of its input len=${#1} while IFS= read -r line do [[ "${line:0:len}" = "$1" ]] && printf "%s\n" "$line" done 

Skrypt oblicza długość len wprowadzonego parametru $ 1, a następnie używa rozwinięcia parametrów w każdym wierszu, aby sprawdzić, czy pierwsze len znaki pasują do $ 1. Jeśli tak, to wypisuje wiersz.

Odpowiedź

Jeśli $1 to czysty ASCII, a grep ma opcję -P (aby włączyć PCRE), możesz to zrobić:

 #!/bin/bash line_start="$1" line_start_raw=$(printf "%s" "$line_start" | od -v -t x1 -An) line_start_hex=$(printf "\\x%s" $line_start_raw) grep -P "^$line_start_hex"  

Pomysł jest taki, że grep -P zezwala na wyrażenia regularne z \xXX, aby określić znaki literału, gdzie XX to szesnastkowa wartość ASCII tego znaku. Znak er jest dopasowywane dosłownie, nawet jeśli jest to specjalny znak wyrażenia regularnego.

od służy do konwersji oczekiwanego początku wiersza na listę wartości szesnastkowych, które są następnie łączone razem, każdy z prefiksem \x przez printf. ^ jest następnie dodawany na początku tego ciągu, aby utworzyć wymagane wyrażenie regularne.


Jeśli $1 to Unicode, wtedy staje się to trochę trudniejsze, ponieważ nie ma zgodności 1: 1 znaków z bajtami szesnastkowymi jako wyjście od.

Odpowiedź

Jeśli grep ma opcję -P, co oznacza PCRE , możesz to zrobić:

grep -P "^\Q$1\E" 

Odnieś się do tego pytania , i zobacz dokument PCRE , aby uzyskać szczegółowe informacje, jeśli chcesz.

Odpowiedź

Jako filtr:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern 

Uruchom na co najmniej jednym pliku:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file.. 

W sekcji „Cytowanie metaznaków” w dokumentacji Perlre wyjaśniono:

Cytowanie metaznaki

Metaznaki z odwrotnym ukośnikiem w P erl są alfanumeryczne, na przykład \b, \w, \n. W przeciwieństwie do niektórych innych języków wyrażeń regularnych nie ma symboli odwróconych ukośnikiem, które nie są alfanumeryczne. Więc wszystko, co wygląda jak \\, \(, \), , \], \{ lub \} jest zawsze interpretowane jako literalny znak, a nie metaznak. Było to kiedyś używane w popularnym idiomie do wyłączania lub cytowania specjalnego znaczenia metaznaków wyrażeń regularnych w ciągu, którego chcesz użyć jako wzorca. Po prostu zacytuj wszystkie znaki inne niż „słowo”:

 $pattern =~ s/(\W)/\\$1/g; 

(Jeśli ustawiono use locale, zależy to od bieżącej lokalizacji). Obecnie częściej używa się funkcji quotemeta lub \Q sekwencji ucieczki metaquotingu, aby wyłączyć specjalne znaczenie wszystkich metaznaków w ten sposób:

 /$unquoted\Q$quoted\E$unquoted/ 

Uważaj, jeśli umieścisz dosłowne ukośniki odwrotne (te, które nie znajdują się w zmiennych interpolowanych) między \Q a \E, interpolacja z podwójnym cudzysłowem odwrotnym ukośnikiem może prowadzić do mylących wyników. Jeśli chcesz użyć dosłownych ukośników odwrotnych w \Q...\E, zapoznaj się z „Gory details of parsing quoted constructs” in perlop .

quotemeta i \Q są w pełni opisane w quotemeta .

Odpowiedź

Jeśli jest jakiś znak, którego nie „Nie używaj, możesz tego użyć do zaznaczenia początku wiersza. Na przykład $"\a" (ASCII 007). Jest brzydki, ale zadziała:

{ echo "this is a line to match"; echo "but this is not"; } >file.txt stuffing=$"\a" # Guaranteed never to appear in your source text required="this" # What we want to match that beginning of a line match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//") if [[ -n "$match" ]] then echo "Yay. We have a match: $match" fi 

Jeśli nie potrzebujesz dopasowanych linii, możesz porzucić końcowe sed i użyć grep -qF. Ale jest to dużo łatwiejsze z awk (lub perl) …

Odpowiedź

Jeśli chcesz zajrzeć do pliku bez pętli, możesz użyć:
Skróć plik o długość wyszukiwania ciąg

Poszukaj stałych ciągów i zwracaj numery wierszy

 grep -Fn "$1" <(cut -c1-${#1} < file) 

Użyj numerów wierszy dla czegoś takiego jak sed -n "3p;11p" file

 sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file 

Jeśli chcesz usunąć te wiersze, użyj

 sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *