Dette spørgsmål har allerede svar her :

Kommentarer

  • Hvad mener du af " hele delen af hver streng "? Du ønsker ikke ', at hele linjen skal udskrives?
  • Kan du bekræfte, at du vil have, at matchende filer indeholder både " foo " og " 321 " men ikke bare " foo " eller bare " 321 "?
  • Jeg kan godt lide, hvordan det ' s 321 i stedet for bar: – D

Svar

GNU grep

Skal være lidt hurtigere, fordi det andet grep fungerer muligvis på en liste over filer.

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

POSIX grep med find

find er mere nyttigt, hvis du vil søge i rekursive kataloger (i så fald mister -mindepth og -maxdepth indstillinger.

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

Kommentarer

  • -r fungerede fint på den første grep for at gøre den GNU-løsning rekursiv for mig, i stedet for at bruge POSIX-linjen med alle disse exec s

Svar

Du kan gøre dette med et kort script:

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

Du kan også gøre dette på en linje:

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

grep returnerer 0 (true), hvis den fandt strengen og && adskiller kommandoerne betyder, at den anden kører kun, hvis den første var sand. Muligheden -q sørger for, at grep ikke udsender noget.

Ekkoet kører kun, hvis begge strenge var findes i samme fil.


Jeg tænkte på en anden måde at gøre det på. Denne måde vil sandsynligvis være mere effektiv, hvis de pågældende filer er større end din installerede RAM, da den kun skal grep gennem hver fil en gang.

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

og versionen med en linje:

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

Kommentarer

  • For din mere effektive løsning: Hvad hvis filen har " foo foo "?
  • At ' s hvad uniq | sort | uniq er til. " foo foo " ender med at være en linje, men " foo 321 " ender med at være to linjer, fordi grep -o udsender alle fundne strenge på separate linjer, selvom de startede på den samme linje.
  • Hvis filerne bliver så store, at det ville være OK at forkaste mindst seks gange pr. Fil, er det sandsynligvis fornuftigt at bruge awk i stedet, så filerne ikke skal søges til slutningen.
  • @Ladadadada fik det. 🙂
  • @HaukeLaging grep -q og grep -l søger ikke til slutningen af filen: de afslutter så snart som en match er fundet. Det får mig til at undre mig over, hvorfor den første løsning ikke er ' t for FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done

Svar

Mærkeligt. For mig fungerer begge varianter (grep (GNU grep) 2.13):

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

Rediger 1 – vis kun filer med begge matches

for file in * svaret fungerer, men kan blive et præstationsmardrøm (for store mængder filer ): mindst to processer pr. fil. Dette er hurtigere (i GNU-verdenen):

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

streng1 skal være den, der resulterer i færre matches.

Kommentarer

  • Askeren leder kun efter, at resultatet returnerer true, hvis en fil indeholder begge strenge i stedet for hvis den bare matcher mindst en.
  • Det kan jeg godt lide --files-with-matches mulighed. Bare læs det op på mandsiden, og det får grep til at stoppe, når den finder den første kamp, hvilket betyder, at den ' er meget effektiv til store filer, hvis kampen sker tidligt. Det siger også, at den korte indstilling -l er specificeret af POSIX, så den kan bruges uden for GNU-verdenen.
  • @Ladadadada Effektiviteten er ingen fordel i forhold til din -q, dog. Nævner GNU tænkte jeg ikke ' t på –filer-med-tændstik, men omkring -0 / –null.Hvad der lige kommer til at tænke på mig: stienavneudvidelse indeholder alfabetisk sortering (virkelig dårlig: Det ser ud til, at ' ikke engang kan slås fra) så for enorme mængder filer, selv din for file in * holder virkelig op med at være sjov.
  • Effektivitetsoptimeringer ville faktisk være helt forskellige for et par store filer sammenlignet med mange små og * er bare ikke ' slet ikke fungerer efter et par tusinde filer.
  • @Ladadadada Det ville ikke ' t fungerer som en del af en kommandolinje til en ekstern kommando: grep foo * Men for file in * er en shell-intern struktur, så jeg antager at kommandolinjegrænsen ikke finder anvendelse her.

Svar

Dybest set for at finde alle filer inklusive en bestemt streng i en mappe, kan du bruge:

grep -lir "pattern" /path/to/the/dir 
  • -l: til at foretage denne scanning stopper ved første match
  • -i: for at ignorere store sager i mønsteret og inputfilerne
  • -r: søg i alle filer under kataloget, rekursivt

For at søge efter to mønstre, prøv dette:

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

Kommentarer

  • Standard kedelige kommentarer om $(), der ikke håndterer mellemrum, gælder. I praksis for en liners ved skallen fungerer denne kommando fint.

Svar

Skal være

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

Brug -e til flere mønstre

EDIT

Hvis du har brug for begge at matche:

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

Hvis ordren ikke betyder noget:

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

Kommentarer

  • Dette giver ikke svar på spørgsmålet. For at kritisere eller anmode om en afklaring fra en forfatter skal du efterlade en kommentar under deres indlæg.
  • @mdpc Jeg synes, det giver et svar. Hvad får dig til at tænke anderledes?
  • @HaukeLaging Fordi det vender tilbage, hvis begge mønstre matcher. OPen leder efter et tilfælde, hvor det kun returnerer sandt, hvis begge findes i filen.
  • Min forståelse af dette finder kun filer, hvor begge strenge indeholder på samme linje (I don ' tænk ikke. matcher nye linjer som standard)

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *