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 for en dynamisk satt inn 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 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. Bryr deg om å 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 ønsker det, og jeg ‘ fjerner kommenter her (ikke ‘ t glem å legge til de manglende ledende selene).

Svar

Jeg kan ikke tenke meg en måte å gjøre dette på grep; ^ i seg selv er en del av en regelmessig uttrykk, så bruk av det krever at regelmessige 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 slik 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 på en ukjent måte, med mindre du vet hvor mange som vil bli brukt på forhånd. > 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 å 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 er funnet en kamp eller ikke, kutte alle inngangslinjene til lengden på ønsket prefiks ($1) og bruk deretter 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 samsvarende 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 med å si values may not include zero. Hvis du bruker Bash, bruker du 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 alternativ for alle ting, ikke det 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 -tegnene samsvarer med $ 1. Hvis det er tilfelle, er det 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 bokstavstegn, 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 strenget sammen, hver foran en \x av printf. ^ blir deretter lagt denne strengen for å bygge den nødvendige regex.


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 , du kan 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 «Sitering av metategn» i perlerdokumentasjonen forklarer:

Sitering 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 bruker, 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 for 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 *