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 nie chodziło Ci o to, aby $1 nie był rozszerzany przez powłokę?
  • @mnille Nie ' nie chcę szukać ' ^ $ 1 ', ale dynamicznie wstawionego ustalony ciąg, który powinien być dopasowany tylko wtedy, gdy ' znajduje się na początku wiersza. To ' miałem na myśli, mówiąc o $ 1.
  • Możesz to zrobić z grep, ale ' Najpierw musisz uciec przed jakimkolwiek znakiem specjalnym w twoim ciągu, np. printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti, że ' jest 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 zmiennych) jest coś, co ja (i kilku innych użytkowników tutaj) wbijaliśmy w stronę od jakiegoś 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).

Odpowiedź

Nie mogę wymyślić sposobu, aby to zrobić za pomocą grep; ^ jest częścią wyrażenie regularne, więc jego użycie 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 w programie są postrzegane 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 stałym 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, czyli początek wiersza.

Tak samo możesz zrobić w awk

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

Odpowiedź

Oto 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 linię.

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 w przeciwnym razie 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 ze sobą, każdy z prefiksem \x przez printf. ^ jest następnie dodawany na początku tego ciągu w celu zbudowania wymaganego wyrażenia regularnego.


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.. 

Sekcja „Cytowanie metaznaków” w dokumentacji Perlre wyjaśnia:

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 literalne ukośniki odwrotne (te, które nie znajdują się w zmiennych interpolowanych) między \Q a \E, interpolacja z podwójnym ukośnikiem w cudzysłowie 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 „Krwawe szczegóły analizowania konstrukcji z cudzysłowami” w 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ć . Ale jest to znacznie ł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 linii 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 *