To niekoniecznie wymagają modyfikacji grep
, choć prawdopodobnie można uzyskać dokładniejsze pasek postępu z taką modyfikacją.
Jeśli przeglądasz "tysiące plików" za pomocą jednego wywołania polecenia grep, najprawdopodobniej używasz opcji -r
do rekursywnie struktury katalogów.W takim przypadku nie jest nawet jasne, czy grep
wie, ile plików będzie badać, ponieważ uważam, że zaczyna analizować pliki, zanim przejrzy całą strukturę katalogów. Najpierw odkrywanie struktury katalogów prawdopodobnie zwiększyłoby całkowity czas skanowania (i, w rzeczy samej, zawsze istnieje koszt tworzenia raportów z postępu, dlatego kilka tradycyjnych narzędzi Unix to robi).
W każdym razie prosty, ale nieznaczny niedokładny pasek postępu można uzyskać, tworząc kompletną listę plików do zeskanowania, a następnie przesyłając je do grep
w partiach o pewnym rozmiarze, może 100, lub może w oparciu o całkowity rozmiar partii. Małe partie pozwoliłyby na dokładniejsze raporty z postępów, ale zwiększyłyby również koszty ogólne, ponieważ wymagałyby dodatkowego uruchomienia procesu grep, a czas rozpoczęcia procesu może być czymś więcej niż otwieraniem małego pliku. Raport postępu byłby aktualizowany dla każdej partii plików, więc chciałbyś wybrać rozmiar wsadu, który dawałby regularne aktualizacje bez zwiększania narzutów za dużo. Oparcie rozmiaru wsadu na całkowitym rozmiarze plików (przy użyciu na przykład stat
w celu uzyskania rozmiaru pliku) sprawiłoby, że raport postępu byłby dokładniejszy, ale dodał dodatkowy koszt do uruchomienia procesu.
Jedną z zalet tej strategii jest to, że można równolegle uruchomić dwa lub więcej komunikatów, co może nieco przyspieszyć proces.
W szerokim ujęciu, prosty skrypt (który właśnie dzieli pliki liczbowo, a nie wielkość, a co nie próbować parallelize).
# Requires bash 4 and Gnu grep
shopt -s globstar
files=(**)
total=${#files[@]}
for ((i=0; i<total; i+=100)); do
echo $i/$total >>/dev/stderr
grep -d skip -e "$pattern" "${files[@]:i:100}" >>results.txt
done
Dla uproszczenia używam globstar (**
), aby bezpiecznie umieścić wszystkie pliki w tablicy. Jeśli twoja wersja bash jest zbyt stara, możesz to zrobić, wykonując pętlę nad wynikiem find
, ale to nie jest zbyt wydajne, jeśli masz dużo plików. Niestety nie ma sposobu, aby napisać wyrażenie globstar, które dopasowuje tylko pliki. (**/
dopasowuje tylko katalogi.) Na szczęście GNU grep udostępnia opcję -d skip
, która po cichu pomija katalogi. Oznacza to, że liczba plików będzie nieznacznie niedokładna, ponieważ katalogi będą zliczane, ale prawdopodobnie nie ma to znaczenia.
Prawdopodobnie chcesz wyczyścić raport postępu za pomocą niektórych kodów konsoli. Powyższe jest tylko po to, abyś zaczął.
Najprostszym sposobem na podzielenie tego na różne procesy byłoby po prostu podzielenie listy na X różnych segmentów i uruchomienie X różnych dla pętli, z których każda ma inny punkt początkowy. Jednak prawdopodobnie nie wszyscy skończą w tym samym czasie, więc nie jest to optymalne. Lepszym rozwiązaniem jest równoległe GNU. Można zrobić coś takiego:
find . -type f -print0 |
parallel --progress -L 100 -m -j 4 grep -e "$pattern" > results.txt
(tutaj -L 100
określa, że do 100 pliki powinny być podane do każdej instancji grep i -j 4
określa cztery procesy równoległe właśnie wyciągnął te numery z powietrza; ci”. ll prawdopodobnie chcą je dostosować.)
Czy rozważałeś użycie skryptu, aby to zrobić? To prostsze niż edycja kodu źródłowego grep –