Jak wyświetlić liczbę wierszy każdego pliku w katalogu w formacie czytelnym dla człowieka.

41

Mam listę katalogów i podkatalogów zawierających duże pliki csv. Pliki te zawierają około 500 milionów linii, z których każda jest rekordem. chciałbym wiedzieć

  1. Ile linii jest w każdym pliku.
  2. Ile linii jest w katalogu.
  3. Ile w sumie linii

Co najważniejsze, potrzebuję tego w „czytelnym dla człowieka formacie”, np. 12 346 678 zamiast 12345678

Byłoby miło nauczyć się tego robić na 3 sposoby. Proste waniliowe narzędzia bash, awk itp. Oraz perl (lub python).

Heksatoniczny
źródło

Odpowiedzi:

56

Ile linii jest w każdym pliku.

Zastosowanie wc, pierwotnie dla liczby słów, wierzę, ale może to zrobić linie, słowa, znaki, bajtów, a długość najdłuższej linii. Ta -lopcja mówi, aby liczyć linie.

wc -l <filename>

Spowoduje to wyświetlenie liczby wierszy w:

$ wc -l /dir/file.txt
32724 /dir/file.txt

Możesz także przesyłać dane do wc:

$ cat /dir/file.txt | wc -l
32724
$ curl google.com --silent | wc -l
63

Ile linii jest w katalogu.

Próbować:

find . -name '*.pl' | xargs wc -l

inny jednowarstwowy:

( find ./ -name '*.pl' -print0 | xargs -0 cat ) | wc -l

BTW, wcpolecenie liczy nowe kody linii, a nie linie. Kiedy ostatni wiersz w pliku nie kończy się nowym kodem wiersza, nie będzie to liczone.

Możesz użyć grep -c ^, pełny przykład:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

Ile w sumie linii

Nie jestem pewien, czy zrozumiałem, że prosisz poprawnie. np. spowoduje to wyświetlenie wyników w następującym formacie, pokazującym liczbę wierszy dla każdego pliku:

# wc -l `find /path/to/directory/ -type f`
 103 /dir/a.php
 378 /dir/b/c.xml
 132 /dir/d/e.xml
 613 total

Alternatywnie, aby wyświetlić tylko całkowitą liczbę nowych znaków wiersza bez liczenia plik po pliku, może okazać się przydatne następujące polecenie:

# find /path/to/directory/ -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
 613

Co najważniejsze, potrzebuję tego w „czytelnym dla człowieka formacie”, np. 12 346 678 zamiast 12345678

Bash ma wbudowaną funkcję printf :

printf "%0.2f\n" $T

Jak zawsze, istnieje wiele różnych metod, które można wykorzystać do osiągnięcia tych samych rezultatów wymienionych tutaj.

malyy
źródło
Przy okazji, jak mogę użyć printf w twoich przykładach? Próbowałem przesłać do niego z wc -l, ale to nie działało.
Heksatoniczny
spróbuj> znajdź. -nazwa „* .pl” | xargs wc -l | awk '{printf ("% 0.2f", 1 $)} {print 2 $} zmień wyjście z' printf 'na twoje potrzeby
malyy
Nie dodaje to przecinków do liczby, dzięki czemu jest bardziej czytelna dla człowieka. Po prostu dodaje zera na końcu.
Heksatoniczny
echo 1000000000000 | xargs printf "% 'd \ n" 1 000 000 000 000
heksatoniczny
1
@ Hexatonic printfnie odczytuje swoich argumentów stdin, lecz raczej z wiersza poleceń (porównaj potok do echovs potok do cat; catczyta z stdin, echonie robi). Zamiast tego użyj printf "$(find ... | xargs ...)"do podania wyniku jako argumentu printf.
BallpointBen,
13

W wielu przypadkach może być wystarczające połączenie wcpolecenia i symbolu wieloznacznego *.
Jeśli wszystkie pliki znajdują się w jednym katalogu, możesz zadzwonić:

wc -l src/*

Możesz także wymienić kilka plików i katalogów:

wc -l file.txt readme src/* include/*

To polecenie wyświetli listę plików i ich liczbę wierszy.
Ostatni wiersz będzie sumą wierszy ze wszystkich plików.


Aby rekurencyjnie policzyć wszystkie pliki w katalogu:

Najpierw włącz globstar, dodając shopt -s globstardo swojego .bash_profile. Obsługa globstar wymaga wersji Bash ≥ 4.x, którą można zainstalować w brew install bashrazie potrzeby. Możesz sprawdzić swoją wersję za pomocą bash --version.

Następnie uruchomić:

wc -l **/*

Zauważ, że to wyjście będzie niepoprawne, jeśli globstar nie jest włączony.

Thomio
źródło
I do rekurencyjnego zliczania plików w bieżącym katalogu:wc -l **/*
Taylor Edmiston
@TaylorEdmiston Dla mnie (na komputerze Mac), który odlicza tylko pliki dokładnie o jeden katalog w dół. Pomija pliki w bieżącym katalogu i dla każdego wystąpienia, który miałby więcej niż jeden katalog głęboko, ostrzega, że ​​jest to katalog: „ wc: parent_dir/child_dir: read: Is a directory
M. Justin
@Thomio Wymaga włączenia globstar. Wydaje mi się, że w systemie macOS jest on wyłączany po wyjęciu z pudełka. Właśnie przesłałem edycję do twojej odpowiedzi, która dodaje polecenie i jak włączyć globstar.
Taylor Edmiston,
2

To polecenie wyświetli listę kodów wierszy w każdym katalogu:

find . -name '*.*' -type f | xargs wc -l
Suresh.A
źródło
2

nieco późno do gry, ale dostałem sporo błędów argumentów z powyższym ze względu na rozmiar reż. To działało dla mnie:

for i in $(find . -type f); do wc -l $i; done >> /home/counts.txt

Ron Paulfan
źródło
0

catpołączy pliki w jeden i wyprowadzi wszystko na standardowe wyjście, możesz to zrobić wc -ldla całkowitej liczby linii plików w katalogu:

cat /path/to/directory/* | wc -l
picmate 涅
źródło
0

Dodam tylko @malyy odpowiedź na następujące pytania (zbyt duże, by skomentować):

Ile w sumie linii

Wiele odpowiedzi używa wcopcji pliku wiersza poleceń z xargs. Problem polega na tym, że xargs jest ograniczony do dość małego rozmiaru zależnego od platformy.

Ponadto istnieje różnica między BSD (macOS) a GNU (linux / homebrew) wc.

GNU jeden jest idealny, ponieważ może odczytywać listę plików z pliku zamiast argumentów ( --files0).

Jeśli korzystasz z komputera Mac i masz Homebrew, wykonaj następujące czynności:

find . -name "*.pl" -print0 | gwc -l --files0=-

Zauważ gwc zamiast wc .

Adam Gent
źródło