grep "^$1"
funktioniert, aber wie entkomme ich "$1"
damit grep keine Zeichen darin speziell interpretiert?
Oder gibt es einen besseren Weg?
Bearbeiten: Ich möchte nicht nach "^$1"
suchen, sondern nach einer dynamisch eingefügten festen Zeichenfolge, die nur sollte abgeglichen werden, wenn es am Anfang einer Zeile steht. Das habe ich mit $1
gemeint.
Kommentare
- Haben Sie versucht, einfache Anführungszeichen anstelle von doppelten Anführungszeichen zu verwenden, z
grep '^$1'
? Oder haben Sie nicht ‚ gemeint, dass Sie verhindern möchten, dass$1
von der Shell erweitert wird? - @mnille Ich ‚ möchte nicht nach ‚ ^ $ 1 ‚ suchen, sondern nach einem dynamisch eingefügten feste Zeichenfolge, die nur übereinstimmen sollte, wenn sie ‚ am Zeilenanfang steht. Das ‚ habe ich mit $ 1 gemeint.
- Sie können es auch mit
grep
tun, aber Sie ‚ muss zuerst ein Sonderzeichen in Ihrer Zeichenfolge maskieren, zprintf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
- @don_crissti, dass ‚ besser ist als einige der anderen Antworten. Möchtest du es zu einem machen?
- @roaima – Ich weiß, aber ‚ gibt es hier bereits eine Reihe von Antworten, und dies (ohne die Sonderzeichen in vars) Etwas, das ich (und einige andere Benutzer hier) schon seit einiger Zeit nach Hause hämmern … Sie können es jederzeit zu Ihrer Antwort hinzufügen, wenn Sie dies wünschen, und ich ‚ werde das entfernen Kommentar hier (‚ vergessen Sie nicht, die fehlende führende Klammer hinzuzufügen).
Antwort
Ich kann mir keine Möglichkeit vorstellen, dies mit grep
zu tun. ^
selbst ist Teil von a Um reguläre Ausdrücke zu verwenden, müssen reguläre Ausdrücke interpretiert werden. Es ist trivial, Teilstring-Übereinstimmungen in awk
, perl
oder was auch immer zu verwenden:
awk -v search="$1" "substr($0, 1, length(search)) == search { print }"
Um Suchzeichenfolgen mit \
zu verarbeiten, können Sie denselben Trick wie in 123 „s Antwort :
search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }"
Kommentare
- Dies funktioniert nicht ‚ für Zeichenfolgen wie z Als
\/
- @ 123 habe ich ‚ eine Variante hinzugefügt, um dies zu handhaben.
- schlägt immer noch für komplizierte Zeichenfolgen wie
\\\/\/\/\\\\/
fehl, die im Programm als\\///\\/
angesehen werden. Soweit mir bekannt ist, gibt es keine Möglichkeit, Backslashes in awk ordnungsgemäß zu umgehen, es sei denn, Sie wissen, wie viele zuvor verwendet werden. - @ 123 danke, ich ‚ Ich habe Ihren Trick, durch die Umgebung zu gehen, angepasst, um eine Escape-Verarbeitung zu vermeiden.
- Diese Lösung gefällt mir immer noch am besten. Effizient (awk + keine Zeitverschwendung beim Umsehen), schneller Start (awk + keine zusätzlichen Prozesse zum Einrichten des Status erforderlich) verwendet Standardtools und ist recht präzise. Allen anderen Antworten fehlen zumindest einige davon. (Effizienz ist hier eine Stärke, da grep für unübertroffene Geschwindigkeit bekannt ist.)
Antwort
Wenn Sie nur Sie müssen überprüfen, ob eine Übereinstimmung gefunden wurde oder nicht, alle Eingabezeilen auf die Länge des gewünschten Präfixes ($1
) schneiden und dann grep mit festem Muster verwenden:
if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi
Es ist auch einfach, die Anzahl der übereinstimmenden Zeilen zu ermitteln:
cut -c 1-"${#1}" | grep -cF "$1"
Oder die Zeilennummern von Alle übereinstimmenden Zeilen (Zeilennummern beginnen bei 1):
cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1
Sie können die Zeilennummern head
und eingeben tail
, um den vollständigen Text der übereinstimmenden Zeilen abzurufen. An diesem Punkt ist es jedoch einfacher, nur nach einer modernen Skriptsprache wie Python oder Ruby zu greifen.
(Die obigen Beispiele setzen Posix grep und cut voraus. Sie gehen davon aus, dass die zu durchsuchende Datei von der Standardeingabe stammt, können jedoch leicht angepasst werden, um stattdessen einen Dateinamen zu verwenden.)
Bearbeiten: Sie sollten auch sicherstellen, dass das Muster ( $1
) ist keine Zeichenfolge mit der Länge Null. Andernfalls sagt cut
nicht values may not include zero
. Wenn Sie Bash verwenden, verwenden Sie außerdem set -o pipefail
, um Fehlerausgänge mit cut
abzufangen.
Antwort
Eine Methode zur Verwendung von Perl, die Backslashes berücksichtigt.
v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file
Hiermit wird die Umgebungsvariable v für festgelegt Befehl, druckt dann, wenn der Index der Variablen 0 ist, dh der Zeilenanfang.
Sie können dies auch in awk
v="$1" awk "index($0, ENVIRON["v"])==1" file
Antwort
Hier ist eine All-Bash-Option, nicht dass ich Bash für die Textverarbeitung empfehle, aber sie funktioniert.
#!/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
Das Skript berechnet die Länge len
des eingegebenen Parameters $ 1 verwendet dann die Parametererweiterung in jeder Zeile, um festzustellen, ob die ersten len
-Zeichen mit $ 1 übereinstimmen. Wenn ja, ist dies der Fall druckt die Zeile.
Antwort
Wenn Ihre $1
reines ASCII ist und Ihre grep
verfügt über die Option -P
(um PCRE zu aktivieren). Sie können dies tun:
#!/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"
Die Idee hier ist, dass grep -P
reguläre Ausdrücke mit , um Literalzeichen anzugeben, wobei XX
der hexadezimale ASCII-Wert dieses Zeichens ist. Das Zeichen er wird buchstäblich abgeglichen, auch wenn es sich ansonsten um ein spezielles Regex-Zeichen handelt.
od
wird verwendet, um den erwarteten Zeilenanfang in eine Liste von Hex-Werten umzuwandeln werden dann aneinander gereiht, wobei jeweils \x
von printf vorangestellt wird. ^
wird dieser Zeichenfolge vorangestellt, um den erforderlichen regulären Ausdruck zu erstellen.
Wenn Ihre $1
Unicode ist, dann wird dies etwas schwieriger, da es keine 1: 1-Entsprechung von Zeichen zu Hex-Bytes gibt, wie von od
ausgegeben.
Antwort
Wenn Ihr grep die Option -P hat, bedeutet dies PCRE können Sie dies tun:
grep -P "^\Q$1\E"
Siehe diese Frage , Weitere Informationen finden Sie unter PCRE-Dokument .
Antwort
Als Filter:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern
Führen Sie eine oder mehrere Dateien aus:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file..
Im Abschnitt „Zitieren von Metazeichen“ der Perlre-Dokumentation wird Folgendes erläutert:
Zitieren Metazeichen
Backslashed-Metazeichen in P. erl sind alphanumerisch, z. B.
\b
,\w
,\n
. Im Gegensatz zu einigen anderen Sprachen mit regulären Ausdrücken gibt es keine umgekehrten Symbole, die nicht alphanumerisch sind. Also alles, was aussieht wie\\
,\(
,\)
,\[
,\]
,\{
oder\}
wird immer als interpretiert ein wörtliches Zeichen, kein Metazeichen. Dies wurde einmal in einer allgemeinen Sprache verwendet, um die speziellen Bedeutungen von Metazeichen für reguläre Ausdrücke in einer Zeichenfolge zu deaktivieren oder zu zitieren, die Sie für ein Muster verwenden möchten. Zitieren Sie einfach alle Nicht-Wort-Zeichen:$pattern =~ s/(\W)/\\$1/g;
(Wenn
use locale
festgelegt ist, hängt dies davon ab das aktuelle Gebietsschema.) Heutzutage ist es üblicher, die Funktionquotemeta
oder die Escape-Sequenz\Q
zu verwenden, um die speziellen Bedeutungen aller Metazeichen zu deaktivieren wie folgt:/$unquoted\Q$quoted\E$unquoted/
Beachten Sie, dass Sie zwischen
\Q
und literale Backslashes (die nicht in interpolierten Variablen enthalten sind) setzen\E
Eine Backslash-Interpolation mit doppeltem Anführungszeichen kann zu verwirrenden Ergebnissen führen. Wenn Sie in\Q...\E
wörtliche Backslashes verwenden müssen, konsultieren Sie „Wichtige Details zum Parsen zitierter Konstrukte“ in Perlop .
quotemeta
und\Q
sind vollständig in quotemeta .
Antwort
Wenn Sie ein Zeichen eingeben Wenn Sie dies nicht verwenden, können Sie damit den Zeilenanfang markieren. Beispiel: $"\a"
(ASCII 007). Es ist hässlich, aber es funktioniert:
{ 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
Wenn Sie die übereinstimmenden Zeilen nicht benötigen, können Sie die nachfolgende sed
löschen und grep -qF
. Mit awk
(oder perl
) ist es jedoch viel einfacher …
Antwort
Wenn Sie in einer Datei ohne Schleife suchen möchten, können Sie Folgendes verwenden:
Schneiden Sie die Datei mit der Länge der Suche Zeichenfolge
Suchen Sie nach festen Zeichenfolgen und geben Sie Zeilennummern zurück.
grep -Fn "$1" <(cut -c1-${#1} < file)
Verwenden Sie die Zeilennummern für etwas wie sed -n "3p;11p" file
sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file
Wenn Sie diese Zeilen löschen möchten, verwenden Sie
sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file