grep "^$1" slags verk, men hvordan slipper jeg "$1" så grep tolker ikke noen tegn i den spesielt?

Eller er det en bedre måte?

Rediger: Jeg vil ikke søke etter "^$1" men etter en dynamisk innsatt fast streng som bare skal bli matchet hvis det er i begynnelsen av en linje. Det er det jeg mente med $1.

Kommentarer

  • Forsøkte du å bruke enkle anførselstegn i stedet for doble anførselstegn, f.eks grep '^$1'? Eller mente du ‘ at du vil forhindre at $1 utvides av skallet?
  • @mnille Jeg vil ikke ‘ ikke søke etter ‘ ^ $ 1 ‘ men etter en dynamisk innsatt fast streng som bare skal matches hvis den ‘ er i begynnelsen av en linje. At ‘ er det jeg mente med $ 1.
  • Du kan gjøre det med grep også, men du ‘ Jeg må unnslippe ethvert spesialtegn i strengen din, f.eks printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti at ‘ er bedre enn noen av de andre svarene. Har du lyst til å gjøre det til?
  • @roaima – jeg vet, men det er ‘ allerede en haug med svar her, og dette (unnslippe de spesielle tegnene inne i vars) er noe jeg (og et par andre brukere her) har hamret hjemme i ganske lang tid … Du kan alltid legge det til svaret ditt hvis du vil, og jeg ‘ fjerner kommenter her (ikke ‘ Ikke glem å legge til den manglende ledestangen).

Svar

Jeg kan ikke tenke meg en måte å gjøre dette ved å bruke grep; ^ er en del av en regelmessig uttrykk, så bruk av det krever at regulære uttrykk tolkes. Det er trivielt ved å bruke underordnet samsvar i awk, perl eller hva som helst:

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

For å håndtere søkestrenger som inneholder \, kan du bruke samme triks som i 123 «svar :

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

Kommentarer

  • Dette vant ‘ t fungerer for strenger som som \/
  • @ 123 faktisk, har jeg ‘ lagt til en variant for å håndtere det.
  • Vil fortsatt mislykkes for kompliserte strenger som \\\/\/\/\\\\/ som blir sett på som \\///\\/ i programmet. Så vidt jeg er klar over, er det ingen måte å unnslippe tilbakeslag i tverr, med mindre du vet hvor mange som vil bli brukt på forhånd.
  • @ 123 takk, jeg ‘ Vi har tilpasset trikset ditt med å gå gjennom miljøet for å unngå rømningsbehandling.
  • Jeg liker fortsatt denne løsningen best. Effektiv (awk + ingen bortkastet tid på å se seg rundt), rask oppstart (awk + ingen ekstra prosesser som trengs for å sette opp tilstand) bruker standardverktøy, og er ganske kortfattet. Alle de andre svarene mangler i det minste noen av disse. (Effektivitet er et sterkt punkt her, da grep er kjent for uovertruffen hastighet.)

Svar

Hvis du bare må du sjekke om det ikke er funnet samsvar, klippe alle inngangslinjene til lengden på ønsket prefiks ($1) og deretter bruke grep med fast mønster:

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

Det er også enkelt å få tellingen av samsvarende linjer:

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

Eller linjenumrene til alle samsvarende linjer (linjenumre starter ved 1):

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

Du kan mate linjenumrene til head og tail for å få fullteksten til de matchende linjene, men på det tidspunktet er det lettere å bare nå et moderne skriptspråk som Python eller Ruby.

(Eksemplene ovenfor antar Posix grep og klipp. De antar at filen som skal søkes kommer fra standardinngang, men kan lett tilpasses til å ta et filnavn i stedet.)

Rediger: Du bør også sørge for at mønsteret ( $1) er ikke en streng med null lengde. Ellers mislykkes cut values may not include zero. Hvis du bruker Bash, bruk set -o pipefail for å fange feilutganger med cut.

Svar

En måte å bruke perl som vil respektere tilbakeslag

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

Dette angir miljøvariabelen v for kommandoen, og skriver deretter ut hvis indeksen til variabelen er 0, dvs. begynnelsen på linjen.

Du kan også gjøre det samme i awk

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

Svar

Her er et all-bash-alternativ, ikke det at jeg anbefaler bash for tekstbehandling, men det fungerer.

#!/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 beregner lengden len for den innlagte parameteren $ 1, bruker deretter parameterutvidelse på hver linje for å se om de første len tegn samsvarer med $ 1. I så fall skriver ut linjen.

Svar

Hvis $1 er ren ASCII og din grep har -P -alternativet (for å aktivere PCRE), du kan gjøre dette:

 #!/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 her er at grep -P tillater regelmessige uttrykk med \xXX for å spesifisere bokstavlige tegn, der XX er den hex-ASCII-verdien til det tegnet. er matches bokstavelig, selv om det ellers er et spesielt regex-tegn.

od brukes til å konvertere forventet linjestart til en liste med hexverdier, som blir deretter strengt sammen, hver foran en \x av printf. ^ blir deretter lagt denne strengen for å bygge den nødvendige regexen.


Hvis $1 er unicode, da blir dette ganske vanskeligere, fordi det ikke er en 1: 1-korrespondanse mellom tegn og heksebytes som utdata fra od.

Svar

Hvis grep har alternativet -P, som betyr PCRE , kan du gjøre dette:

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

Se dette spørsmålet , og se PCRE doc for detaljer hvis du vil.

Svar

Som filter:

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

Kjør på en eller flere filer:

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

Avsnittet «Siterer metategn» i perlerdokumentasjonen forklarer:

Sitat metategn

Snartegnet metategn i P erl er alfanumeriske, slik som \b, \w, \n. I motsetning til andre språk med vanlig uttrykk, er det ingen tilbakeslagstegnede symboler som ikke er alfanumeriske. Så alt som ser ut som \\, \(, \), \[, \], \{, eller \} tolkes alltid som en bokstavelig karakter, ikke en metakarakter. Dette ble en gang brukt i et vanlig uttrykk for å deaktivere eller sitere de spesielle betydningene av metategn med regulært uttrykk i en streng du vil bruke til et mønster. Bare sitat alle tegn som ikke er “ord”:

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

(Hvis use locale er angitt, avhenger dette av gjeldende sted.) I dag er det mer vanlig å bruke quotemeta -funksjonen eller \Q metakvoterende rømningssekvens for å deaktivere alle metategnens spesielle betydninger slik:

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

Vær oppmerksom på at hvis du setter bokstavelige tilbakeslag (de som ikke er i interpolerte variabler) mellom \Q og \E, tilbakeslagsinterpolering med dobbelt anførselstegn kan føre til forvirrende resultater. Hvis du trenger å bruke bokstavelige tilbakeslag innen \Q...\E, kan du gå til “Gory details of parsing sitated constructs” in perlop .

quotemeta og \Q er fullstendig beskrevet i quotemeta .

Svar

Hvis det er et tegn du ikke gir «t bruk, du kan bruke det til å markere begynnelsen på linjen. For eksempel, $"\a" (ASCII 007). Det er stygt, men det vil fungere:

{ 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 

Hvis du ikke trenger den eller de samsvarende linjene, kan du slippe den etterfølgende sed og bruke grep -qF. Men det er mye lettere med awk (eller perl) …

Svar

Når du vil se i en fil uten løkke, kan du bruke:
Klipp filen med lengden på søket streng

Se etter faste strenger og returlinjenumre

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

Bruk linjenumrene til noe 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 vil slette disse linjene, bruk

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *