Kommentarer
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ørstegrep
for at gøre den GNU-løsning rekursiv for mig, i stedet for at bruge POSIX-linjen med alle disseexec
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, fordigrep -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
oggrep -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 ' tfor 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 *
Menfor 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)
321
i stedet forbar
: – D