Deze vraag heeft hier al antwoorden :

Reacties

  • Wat bedoel je door " het volledige deel van elke string "? U ' niet wilt dat de hele regel wordt afgedrukt?
  • Kunt u bevestigen dat u wilt dat de overeenkomende bestanden beide " foo " en " 321 " maar niet alleen " foo " of gewoon " 321 "?
  • Ik vind het leuk dat het ' s 321 in plaats van bar: – D

Answer

GNU grep

Zou iets sneller moeten zijn omdat de tweede grep werkt mogelijk op een lijst met bestanden.

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

POSIX grep met find

find is handiger als u recursieve mappen wilt doorzoeken (in dat geval verliest u de -mindepth en -maxdepth opties.

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

Reacties

  • -r werkte prima op de eerste grep om die GNU-oplossing recursief voor mij te maken, in plaats van de POSIX-regel te gebruiken met al die exec s

Answer

U kunt dit doen met een kort script:

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

U kunt dit ook op één regel doen:

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

grep retourneert 0 (true) als het de string heeft gevonden en de && die de opdrachten scheiden, betekent dat de tweede wordt alleen uitgevoerd als de eerste waar was. De -q optie zorgt ervoor dat grep niets uitvoert.

De echo wordt alleen uitgevoerd als beide strings waren gevonden in hetzelfde bestand.


Ik dacht aan een andere manier om het te doen. Deze manier zal waarschijnlijk efficiënter zijn als de bestanden in kwestie groter zijn dan uw geïnstalleerde RAM, aangezien het slechts één keer grep door elk bestand hoeft te gaan.

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

en de versie met één regel:

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

Reacties

  • Voor uw efficiëntere oplossing: wat als het bestand " foo foo " bevat?
  • Dat ' s waar uniq | sort | uniq voor is. " foo foo " wordt uiteindelijk één regel, maar " foo 321 " wordt uiteindelijk twee regels omdat grep -o alle gevonden strings op aparte regels uitvoert, zelfs als ze op dezelfde regel zijn begonnen.
  • Als de bestanden zo groot worden dat het ok zou zijn om minstens zes keer per bestand te splitsen, dan is het waarschijnlijk logisch om in plaats daarvan awk te gebruiken, zodat de bestanden niet tot het einde hoeven te worden doorzocht.
  • @Ladadadada got het. 🙂
  • @HaukeLaging grep -q en grep -l zoeken niet tot het einde van het bestand: ze worden zo snel mogelijk afgesloten als er een overeenkomst is gevonden. Ik vraag me af waarom de eerste oplossing n ' t for FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done

antwoord is

Vreemd. Voor mij werken beide varianten (grep (GNU grep) 2.13):

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

Bewerk 1 – toon bestanden met alleen beide overeenkomsten

Het for file in * antwoord werkt, maar kan een nachtmerrie worden voor de prestaties (voor grote hoeveelheden bestanden ): minimaal twee processen per bestand. Dit is sneller (in de GNU-wereld):

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

string1 zou degene moeten zijn die resulteert in minder overeenkomsten.

Reacties

  • De vragensteller zoekt naar het resultaat om alleen true te retourneren als een bestand beide strings bevat in plaats van als het slechts overeenkomt met ten minste één.
  • Dat vind ik leuk --files-with-matches optie. Lees het gewoon op in de man-pagina en het zorgt ervoor dat grep stopt nadat het de eerste overeenkomst heeft gevonden, wat betekent dat het ' zeer efficiënt is voor grote bestanden als de overeenkomst vroeg plaatsvindt. Er staat ook dat de korte optie -l wordt gespecificeerd door POSIX, dus het kan buiten de GNU-wereld worden gebruikt.
  • @Ladadadada De efficiëntie is geen voordeel ten opzichte van uw -q. Terwijl ik GNU noemde, dacht ik niet ' aan –files-with-matches maar over -0 / –null.Wat bij me opkomt: padnaamuitbreiding bevat alfabetische sortering (echt slecht: het lijkt erop dat ' zelfs niet kan worden uitgeschakeld), dus voor grote hoeveelheden bestanden zelfs uw for file in * is echt niet leuk meer.
  • Inderdaad, de efficiëntie-optimalisaties zouden heel anders zijn voor een paar grote bestanden in vergelijking met veel kleine en * is gewoon niet ' gaan werken na een paar duizend bestanden.
  • @Ladadadada Het zou niet ' t werken als onderdeel van een opdrachtregel voor een extern commando: grep foo * Maar for file in * is een shell-interne structuur, dus ik neem aan dat de opdrachtregellimiet hier niet van toepassing is.

Antwoord

Kortom, om alle bestanden te vinden, inclusief een bepaalde tekenreeks in een directory, kunt u gebruiken:

grep -lir "pattern" /path/to/the/dir 
  • -l: om deze scan uit te voeren stopt bij de eerste overeenkomst
  • -i: om het onderscheid tussen hoofdletters en kleine letters in zowel het patroon als de invoerbestanden te negeren
  • -r: doorzoek recursief alle bestanden in de directory

Probeer dit om naar twee patronen te zoeken:

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

Reacties

  • Standaard saaie opmerkingen over $() die spaties niet goed behandelen zijn van toepassing. In de praktijk zal dit commando voor one liners bij de shell prima werken.

Answer

Moet

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

Gebruik -e voor meerdere patronen

EDIT

Als u beide nodig heeft om overeen te komen:

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

Als de volgorde er niet toe doet:

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

Reacties

  • Dit geeft geen antwoord op de vraag. Om een auteur te bekritiseren of om opheldering te vragen, kun je een reactie achterlaten onder hun post.
  • @mdpc Ik denk dat het een antwoord geeft. Waarom denk je anders?
  • @HaukeLaging Omdat het terugkeert als een van de patronen overeenkomt. Het OP zoekt naar een geval waarin het alleen true retourneert als beide in het bestand worden gevonden.
  • Ik begrijp dat dit alleen bestanden vindt waarvan beide strings op dezelfde regel staan (I don ' t think. komt standaard overeen met nieuwe regels)

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *