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 wollten Sie nicht, dass ‚ verhindert wird, 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 abgeglichen werden 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, z printf %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 es gibt ‚ hier bereits eine Reihe von Antworten, und dies (den Sonderzeichen in vars entkommen) ist etwas, das ich (und ein paar andere Benutzer hier) schon seit einiger Zeit nach Hause gehämmert haben … Sie können es jederzeit zu Ihrer Antwort hinzufügen, wenn Sie dies wünschen, und ich ‚ werde das entfernen Kommentar hier (nicht ‚ 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 wird ‚ 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 \\///\\/ angezeigt 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 an head und weitergeben 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

tun

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 „Metazeichen zitieren“ 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 Funktion quotemeta 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 zwei 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 / p>

quotemeta und \Q werden vollständig in quotemeta .

Antwort

Wenn es ein Zeichen gibt, das Sie nicht verwenden 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 das 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 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.