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
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ę funkcjiquotemeta
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
\/
\\\/\/\/\\\\/
, 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.