grep "^$1" typ av verk, men hur flyr jag "$1" så grep tolkar inga tecken i det speciellt?

Eller finns det ett bättre sätt?

Redigera: Jag vill inte söka efter "^$1" men efter en dynamiskt införd fast sträng som bara ska matchas om det står i början av en rad. Det är vad jag menade med $1.

Kommentarer

  • Försökte du använda enkla citat istället för dubbla citat, t.ex. grep '^$1'? Eller menade du inte ’ att du vill förhindra att $1 utvidgas av skalet?
  • @mnille Jag vill ’ inte söka efter ’ ^ $ 1 ’ men efter en dynamiskt införd fast sträng som endast bör matchas om den ’ är i början av en rad. Att ’ är vad jag menade med $ 1.
  • Du kan göra det med grep också men du ’ måste undvika alla specialtecken i din sträng först t.ex. printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti att ’ är bättre än några av de andra svaren. Vill du göra det till?
  • @roaima – jag vet men det finns ’ redan ett gäng svar här och detta (undgår de speciella karaktärerna inuti vars) är något jag (och ett par andra användare här) har slagit hem under ganska lång tid … Du kan alltid lägga till det i ditt svar om du vill och jag ’ tar bort kommentera här (don ’ glöm inte att lägga till den saknade ledningsstaget).

Svar

Jag kan inte tänka mig ett sätt att göra detta med grep; ^ är en del av en reguljärt uttryck så att använda det kräver att reguljära uttryck tolkas. Det är trivialt med hjälp av substringmatchning i awk, perl eller vad som helst:

awk -v search="$1" "substr($0, 1, length(search)) == search { print }" 

För att hantera söksträngar som innehåller \ kan du använda samma trick som i 123 ”svar :

search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }" 

Kommentarer

  • Detta vann ’ t fungerar för strängar som sådana som \/
  • @ 123 verkligen har jag ’ lagt till en variant för att hantera det.
  • Kommer fortfarande att misslyckas för komplicerade strängar som \\\/\/\/\\\\/ som ses som \\///\\/ i programmet. Så vitt jag känner till finns det inget sätt att undvika bakåtvända snedstreck i awk, såvida du inte vet hur många som kommer att användas i förväg.
  • @ 123 tack, jag ’ Vi har anpassat ditt trick för att gå igenom miljön för att undvika flyktbehandling.
  • Jag tycker fortfarande bäst om den här lösningen. Effektiv (awk + ingen slösad tid att titta runt), snabb start (awk + inga ytterligare processer behövs för att installera tillstånd) använder standardverktyg och är ganska kortfattat. Alla andra svar saknar åtminstone några av dessa. (Effektivitet är en stark punkt här eftersom grep är känt för oöverträffad hastighet.)

Svar

Om du bara måste kontrollera om en matchning hittas eller inte, klipp alla inmatningsrader till längden på önskat prefix ($1) och använd sedan grep med fast mönster:

if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi 

Det är också lätt att räkna med matchande rader:

cut -c 1-"${#1}" | grep -cF "$1" 

Eller radnumren på alla matchande rader (radnummer börjar vid 1):

cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1 

Du kan mata radnumren till head och tail för att få hela texten i matchande rader, men vid det tillfället är det lättare att bara nå ett modernt skriptspråk som Python eller Ruby.

(Exemplen ovan antar Posix grep och klipp. De antar att filen att söka kommer från standardinmatning, men kan enkelt anpassas för att ta ett filnamn istället.)

Redigera: Du bör också se till att mönstret ( $1) är inte en sträng med noll längd. Annars misslyckas cut med att säga values may not include zero. Om du använder Bash använder du set -o pipefail för att fånga felutgångar med cut.

Svar

Ett sätt att använda perl som kommer att respektera snedstreck

v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file 

Detta ställer in miljövariabeln v för kommandot och skriver sedan ut om variabelns index är 0, dvs. början på raden.

Du kan också göra identiskt i awk

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

Svar

Här är ett alternativ för alla, inte att jag rekommenderar bash för textbehandling, men det fungerar.

#!/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 

Skriptet beräknar längden len för den inmatade parametern $ 1 och använder sedan parameterutvidgning på varje rad för att se om de första len -tecken matchar $ 1. Om så är fallet skriver ut linjen.

Svar

Om din $1 är ren ASCII och din grep har -P -alternativet (för att aktivera PCRE), du kan göra detta:

 #!/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"  

Tanken här är att grep -P tillåter regelbundna uttryck med \xXX för att ange bokstavstecken, där XX är hex-ASCII-värdet för det tecknet. er matchas bokstavligen, även om det annars är ett speciellt regex-tecken.

od används för att konvertera förväntad radstart till en lista med hex-värden, som strängas sedan ihop, var och en prefixas med \x av printf. ^ förbereds sedan den här strängen för att bygga den nödvändiga regexen.


Om din $1 är unicode, då blir detta ganska svårare, eftersom det inte finns en 1: 1-korrespondens mellan tecken och hexbyte som utdata av od.

Svar

Om din grep har alternativet -P, vilket betyder PCRE , du kan göra detta:

grep -P "^\Q$1\E" 

Se denna fråga , och se PCRE doc för detaljer om du vill.

Svara

Som ett filter:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern 

Kör på en eller flera filer:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file.. 

Avsnittet ”Citera metatecken” i perlerdokumentationen förklarar:

Citat metatecken

Backslashed metatecken i P erl är alfanumeriska, såsom \b, \w, \n. Till skillnad från andra språk med vanligt uttryck finns det inga bakåtstreckade symboler som inte är alfanumeriska. Så allt som ser ut som \\, \(, \), \[, \], \{ eller \} tolkas alltid som en bokstavlig karaktär, inte en metatecken. Detta användes en gång i ett vanligt språk för att inaktivera eller citera de speciella betydelserna av metatecken för reguljära uttryck i en sträng som du vill använda för ett mönster. Citera helt enkelt alla icke-“ord” -tecken:

 $pattern =~ s/(\W)/\\$1/g; 

(Om use locale är inställt beror detta på den aktuella platsen.) Idag är det vanligare att använda quotemeta -funktionen eller \Q metakvoterande escape-sekvens för att inaktivera alla metateckenens speciella betydelser så här:

 /$unquoted\Q$quoted\E$unquoted/ 

Var uppmärksam på att om du lägger bokstavliga bakåtvända snedstreck (de som inte finns i interpolerade variabler) mellan \Q och \E, interpolering med bakåtvänd snedstreck kan leda till förvirrande resultat. Om du behöver använda bokstavliga snedstreck inom \Q...\E, se “Gory details of parsing citerade konstruktioner” in perlop .

quotemeta och \Q beskrivs fullständigt i quotemeta .

Svar

Om det finns ett tecken som du inte ”t använder, du kan använda det för att markera början på raden. Till exempel $"\a" (ASCII 007). Det är ful men det fungerar:

{ 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 

Om du inte behöver matchade rader kan du släppa efterföljande sed och använda grep -qF. Men det är mycket lättare med awk (eller perl) …

Svar

När du vill titta i en fil utan en loop kan du använda:
Klipp ut filen med längden på sökningen sträng

Leta efter fasta strängar och returnera radnummer

 grep -Fn "$1" <(cut -c1-${#1} < file) 

Använd linjenumren för något som sed -n "3p;11p" file

 sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file 

När du vill radera dessa rader använder du

 sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *