Kommentarer
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örstagrep
för att göra den GNU-lösningen rekursiv för mig, istället för att använda POSIX-raden med alla dessaexec
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 eftersomgrep -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
ochgrep -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 ' tfor 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 *
Menfor 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)
321
istället förbar
: – D