Denna fråga har redan svar här :

Kommentarer

  • Vad menar du av " hela delen av varje sträng "? Du vill inte ' att hela raden ska skrivas ut?
  • Kan du bekräfta att du vill att matchande filer innehåller både " foo " och " 321 " men inte bara " foo " eller bara " 321 "?
  • Jag gillar hur det ' s 321 istället för bar: – D

Svar

GNU grep

Bör vara lite snabbare eftersom den andra grep kan fungera på en lista med filer.

grep -lZ "foo" * | xargs -0 grep -l "321" 

POSIX grep med sök

find är mer användbart om du vill söka i rekursiva kataloger (i så fall förlora -mindepth och -maxdepth alternativ.

find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} + 

Kommentarer

  • -r fungerade bra på den första grep för att göra den GNU-lösningen rekursiv för mig, istället för att använda POSIX-raden med alla dessa exec s

Svar

Du kan göra detta med ett kort skript:

for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done 

Du kan också göra detta på en rad:

for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done 

grep returnerar 0 (true) om den hittade strängen och && som skiljer kommandona betyder att den andra kör bara om den första var sant. Alternativet -q ser till att grep inte matar ut något.

Ekot körs bara om båda strängarna var finns i samma fil.


Jag tänkte på ett annat sätt att göra det. Det här sättet kommer förmodligen att vara mer effektivt om filerna i fråga är större än ditt installerade RAM-minne eftersom det bara behöver grep genom varje fil en gång.

 for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done 

och versionen med en rad:

 for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done 

Kommentarer

  • För din effektivare lösning: vad händer om filen har " foo foo "?
  • Att ' s vad uniq | sort | uniq är för. " foo foo " blir en rad men " foo 321 " blir två rader eftersom grep -o matar ut alla hittade strängar på separata rader, även om de började på samma rad.
  • Om filerna blir så stora att det skulle vara OK att gaffla åtminstone sex gånger per fil, är det förmodligen vettigt att använda awk istället så att filerna inte behöver sökas till slutet.
  • @Ladadadada fick den. 🙂
  • @HaukeLaging grep -q och grep -l söker inte till slutet av filen: de avslutas så snart som en matchning hittas. Det får mig att undra varför den första lösningen inte är ' t for FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done

Svar

Konstigt. För mig fungerar båda varianterna (grep (GNU grep) 2.13):

grep "foo\|321" grep -E "foo|321" 

Redigera 1 – visa bara filer med båda matchningarna

for file in * svaret fungerar men kan bli en prestationsmardröm (för stora mängder filer ): minst två processer per fil. Detta är snabbare (i GNU-världen):

find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2 

sträng1 bör vara den som resulterar i färre matchningar.

Kommentarer

  • Frågaren letar efter att resultatet bara returnerar true om en fil innehåller båda strängarna snarare än om den bara matchar minst en.
  • Jag gillar det --files-with-matches alternativ. Läs bara upp det på mansidan och det får grep att sluta efter att den hittat den första matchningen, vilket betyder att den ' är mycket effektiv för stora filer om matchningen sker tidigt. Det säger också att det korta alternativet -l är specificerat av POSIX, så det kan användas utanför GNU-världen.
  • @Ladadadada Effektiviteten är ingen fördel jämfört med din -q, dock. Att nämna GNU tänkte inte ' tänka på –filer-med-tändstickor men ungefär -0 / –null.Vad som bara tänker på mig: sökvägsexpansion innehåller alfabetisk sortering (riktigt dåligt: Det verkar som att ' inte ens kan stängas av) så för stora mängder filer till och med din for file in * slutar verkligen vara kul.
  • Effektivitetsoptimeringarna skulle faktiskt vara helt annorlunda för några stora filer jämfört med många små och * är bara inte ' kommer inte att fungera alls efter några tusen filer.
  • @Ladadadada Det skulle inte ' t fungerar som en del av en kommandorad för ett externt kommando: grep foo * Men for file in * är en skal-intern struktur så jag antar att kommandoradsgränsen inte är tillämplig här.

Svar

I grund och botten för att hitta alla filer inklusive en viss sträng i en katalog kan du använda:

grep -lir "pattern" /path/to/the/dir 
  • -l: för att göra denna skanning kommer att sluta vid den första matchningen
  • -i: för att ignorera fallskillnader i både mönster och inmatningsfiler
  • -r: sök igenom alla filer under katalogen, rekursivt

För att söka efter två mönster, prova detta:

grep -lr "321" $(grep -lr "foo" /path/to/the/dir) 

Kommentarer

  • Standardtråkiga kommentarer om $() som inte hanterar utrymmen väl gäller. I praktiken för en linje i skalet fungerar det här kommandot bra.

Svar

Bör vara

grep -e "foo" -e "321" * 

Använd -e för flera mönster

EDIT

Om du behöver båda för att matcha:

grep -e ".*foo.*321.*" * 

Om ordern inte spelar någon roll:

grep -e ".*foo.*321.*" ".*321.*foo.*" * 

Kommentarer

  • Detta ger inte svar på frågan. För att kritisera eller begära förtydligande från en författare, lämna en kommentar under deras inlägg.
  • @mdpc Jag tror att det ger ett svar. Vad får dig att tänka annorlunda?
  • @HaukeLaging Eftersom det återkommer om något av mönstren matchar. OP: n letar efter ett fall där det bara returneras sant om båda finns i filen.
  • Min förståelse här hittar bara filer där båda strängarna innehåller på samma rad ( don ' tänk inte. matchar nya rader som standard)

Lämna ett svar

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