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