Jak uzyskać polecenie find, aby wydrukować rozmiar pliku z nazwą pliku?

107

Jeśli wydaję polecenie wyszukiwania w następujący sposób:

$ find . -name *.ear

Drukuje:

./dir1/dir2/earFile1.ear
./dir1/dir2/earFile2.ear
./dir1/dir3/earFile1.ear

To, co chcę `` wydrukować '' w wierszu poleceń, to nazwa i rozmiar:

./dir1/dir2/earFile1.ear  5000 KB
./dir1/dir2/earFile2.ear  5400 KB
./dir1/dir3/earFile1.ear  5400 KB
Brian Hart
źródło

Odpowiedzi:

110
find . -name '*.ear' -exec ls -lh {} \;

tylko h extra z odpowiedzi jer.drab.org. oszczędza czas psychicznej konwersji na MB;)

nieśmiały
źródło
8
Ta wersja wykona proces "ls" dla każdego pliku. Jeśli masz wiele plików (powiedzmy ponad tysiąc), lepiej to zoptymalizuj przez: find . -name '*.ear' -exec ls -lh {} + \;(rozszerzenie GNU) lub find . -name '*.ear' -print0 | xargs -0 ls -lh. Możesz także chcieć dodać, -type fjeśli interesują Cię tylko pliki (lub dodać -ddo ls, jeśli chcesz, aby same katalogi były dołączone bez ich zawartości).
ash108
2
Twoja odpowiedź nie wyklucza katalogów, więc w końcu uruchomisz ls również na katalogach, co oczywiście nie jest właściwe.
Faheem Mitha
2
To naprawdę nieefektywny sposób robienia rzeczy - i niestety komentarze ash108 również nie są idealne. Znacznie lepiej jest użyć opcji -printf, aby znaleźć.
oskarpearson
Odpowiedź dmazzoni jest dużo bardziej wydajna, ponieważ pozwala uniknąć rozwidlenia + exec na każdym pliku (100x szybciej na moim komputerze). Musiałem zmienić% k na% s. @FaheemMitha: możesz dodać opcje, takie jak -type fliczenie tylko zwykłych plików.
Pan Fooz,
@FaheemMitha łatwe rozwiązanie jest find . -name "*.ear" -type fdla plików. -type ddziała dla katalogów.
anon58192932
112

Musisz użyć -exec lub -printf. Printf działa tak:

find . -name *.ear -printf "%p %k KB\n"

-exec ma większe możliwości i pozwala na wykonywanie dowolnych poleceń - więc możesz użyć wersji „ls” lub „wc” do wydrukowania nazwy pliku wraz z innymi informacjami. 'man find' pokaże dostępne argumenty do printf, które mogą zrobić dużo więcej niż tylko rozmiar pliku.

[edytuj] -printf nie jest w oficjalnym standardzie POSIX, więc sprawdź, czy jest obsługiwany w twojej wersji. Jednak większość nowoczesnych systemów będzie korzystać z narzędzia GNU find lub podobnie rozszerzonej wersji, więc jest duża szansa, że ​​zostanie zaimplementowany.

Leigh Caldwell
źródło
Wygląda na to, że twój przykład jest bardziej precyzyjny, ale nie mogę go uzyskać do pracy nad Solarisem 10.
Brian
Obawiam się, że Solaris Find w ogóle nie obsługuje -printf: jrwren.wrenfam.com/blog/2006/10/07/solaris-find-sucks cs.bgu.ac.il/~arik/usail/man/solaris/ find.1.html Możesz zainstalować GNU find, jeśli przeszkadza ci to, w przeciwnym razie musisz użyć exec lub | zgodnie z sugestiami innych.
Leigh Caldwell
1
+1 To wydaje się bardziej przejrzyste. Aby sformatować dane wyjściowe, wolałbym dodać columnpolecenie. find . -name *.ear -printf "%p %k KB\n" | column -t
Amol
1
Ta odpowiedź jest o wiele bardziej poprawna niż odpowiedź zaakceptowana
groźna
2
Ta -printfopcja również nie działa w systemie OS X. Zobacz stackoverflow.com/questions/752818/… .
abeboparebop
33

prostym rozwiązaniem jest użycie opcji -ls w find:

find . -name \*.ear -ls

To daje ci każdy wpis w normalnym formacie „ls -l”. Lub, aby uzyskać konkretny wynik, którego szukasz, to:

find . -name \*.ear -printf "%p\t%k KB\n"

Co da ci nazwę pliku, a następnie rozmiar w KB.

Michael Cramer
źródło
Nie wiedziałem nawet o lsopcji, powinna ona znajdować się znacznie wyżej na liście odpowiedzi niż jest.
Prometheus
24

Używając funkcji wyszukiwania gnu, myślę, że tego właśnie chcesz. Znajduje wszystkie prawdziwe pliki, a nie katalogi (-type f), i dla każdego z nich wypisuje nazwę pliku (% p), tabulator (\ t), rozmiar w kilobajtach (% k), przyrostek „KB”, a następnie nowa linia (\ n).

find . -type f -printf '%p\t%k KB\n'

Jeśli polecenie printf nie formatuje rzeczy tak, jak chcesz, możesz użyć exec, a następnie polecenie, które chcesz wykonać na każdym pliku. Użyj {} jako nazwy pliku i zakończ polecenie średnikiem (;). W większości powłok wszystkie trzy znaki powinny być poprzedzone ukośnikiem odwrotnym.

Oto proste rozwiązanie, które wyszukuje i drukuje je przy użyciu „ls -lh”, które pokaże rozmiar w postaci czytelnej dla człowieka (k to kilobajty, M to megabajty):

find . -type f -exec ls -lh \{\} \;

Jako jeszcze jedna alternatywa, „wc -c” wypisze liczbę znaków (bajtów) w pliku:

find . -type f -exec wc -c \{\} \;
dmazzoni
źródło
+1 Z wyjątkiem pominięcia -name '*.ear'w przykładach, to powinna być odpowiedź nr 1. Dokładnie odpowiada na pytanie, wyjaśnia znaczenie składni i podaje wiele alternatyw.
OsakaWebbie
ta odpowiedź powinna zostać zaakceptowana, ponieważ nie uruchamia nowej komendy dla każdej linii, więc jest znacznie szybsza niż obecnie akceptowana odpowiedź z shyam
jirislav.
Rzeczywiście, powinna to być właściwa odpowiedź. Ponadto, find . -type f -printf '%k KB\t %p\n'np. Wydrukowanie rozmiaru pliku jako pierwsze, najprawdopodobniej będzie lepszym wynikiem pod względem formatowania ze względu na wyrównanie.
myradio
8
find . -name '*.ear' -exec du -h {} \;

To daje tylko rozmiar pliku, zamiast wszystkich niepotrzebnych rzeczy.

użytkownik2121791
źródło
wcdziała w tym przypadku po prostu lepiej, jeśli potrzebujesz rozmiaru w bajtach.
Alex
4

Awk może naprawić dane wyjściowe, aby podać dokładnie to, o co prosił pytający. W moim systemie Solaris 10 jako drugie pole znajdź rozmiar wydruków -ls w KB, więc:

% find . -name '*.ear' -ls | awk '{print $2, $11}'
5400 ./dir1/dir2/earFile2.ear
5400 ./dir1/dir2/earFile3.ear
5400 ./dir1/dir2/earFile1.ear

W przeciwnym razie użyj -exec ls -lh i wybierz pole rozmiaru z wyniku. Ponownie w systemie Solaris 10:

% find . -name '*.ear' -exec ls -lh {} \; | awk '{print $5, $9}'
5.3M ./dir1/dir2/earFile2.ear
5.3M ./dir1/dir2/earFile3.ear
5.3M ./dir1/dir2/earFile1.ear
tpgould
źródło
4

Dlaczego nie użyć du -a ? Na przykład

find . -name "*.ear" -exec du -a {} \;

Działa na komputerze Mac

sietschie
źródło
3

Zmagałem się z tym na Mac OS X, gdzie polecenie find nie obsługuje -printf.

Rozwiązaniem, które znalazłem, które wprawdzie opiera się na `` grupie '' dla wszystkich plików jako `` personelu '', było ...

ls -l -R | sed 's/\(.*\)staff *\([0-9]*\)..............\(.*\)/\2 \3/'

To dzieli długie wyjście ls na trzy tokeny

  1. rzeczy przed tekstem „personel”
  2. rozmiar pliku
  3. nazwa pliku

Następnie wyprowadza tokeny 2 i 3, tj. Wyjście to liczba bajtów, a następnie nazwa pliku

8071 sections.php
54681 services.php
37961 style.css
13260 thumb.php
70951 workshops.php
Mike M.
źródło
1
Warto wiedzieć .. Wersja GNU findjest dostępna przez homebrew za pomocąbrew install findutils
mwfearnley
2

To powinno dostarczyć Ci tego, czego szukasz, wraz z formatowaniem (tj. Najpierw nazwa pliku, a później rozmiar):

find . -type f -iname "*.ear" -exec du -ah {} \; | awk '{print $2"\t", $1}'

przykładowe dane wyjściowe (gdzie -iname "*.php"uzyskiwałem jakiś wynik):

./plugins/bat/class.bat.inc.php  20K
./plugins/quotas/class.quotas.inc.php    8.0K
./plugins/dmraid/class.dmraid.inc.php    8.0K
./plugins/updatenotifier/class.updatenotifier.inc.php    4.0K
./index.php      4.0K
./config.php     12K
./includes/mb/class.hwsensors.inc.php    8.0K
adriano72
źródło
2

Wypróbuj następujące polecenia:

GNU stat:

find . -type f -name *.ear -exec stat -c "%n %s" {} ';'

BSD stat:

find . -type f -name *.ear -exec stat -f "%N %z" {} ';'

jednak statnie jest standardowe, więc dulub wcmogłoby być lepszym podejściem:

find . -type f -name *.ear -exec sh -c 'echo "{} $(wc -c < {})"' ';'
kenorb
źródło
1

Możesz spróbować tego:

find. -name *.ear -exec du {} \;

To da ci rozmiar w bajtach. Ale polecenie du akceptuje również parametry -k dla KB i -m dla MB. To da ci wynik podobny do

5000  ./dir1/dir2/earFile1.ear
5400  ./dir1/dir2/earFile2.ear
5400  ./dir1/dir3/earFile1.ear
Yaba
źródło
1
find . -name "*.ear" | xargs ls -sh
killdash10
źródło
0
find . -name "*.ear" -exec ls -l {} \;
Jeremy Weathers
źródło
0

Jeśli chcesz uzyskać całkowity rozmiar, oto propozycja skryptu

#!/bin/bash
totalSize=0

allSizes=`find . -type f -name *.ear -exec stat -c "%s" {} \;`

for fileSize in $allSizes; do
    totalSize=`echo "$(($totalSize+$fileSize))"`
done
echo "Total size is $totalSize bytes"
Damien C
źródło