Mawiają – potrzeba matką wynalazku. Tak też jest i teraz.
Zaczynając jednak od początku… Kilka miesięcy temu Borys polecił mi narzędzie, którego nazwa to nnn. W dużym uproszczeniu jest to bardzo prosty menadżer plików. Od polecenia przez niego, używam tego narzędzia namiętnie. Szczególnie, gdy potrzebuję usunąć więcej plików, po różnych katalogach, lub przekopiować coś na szybko. Poruszanie się z pomocą strzałek działa znakomicie. Jestem bardzo zadowolony z niego.
Posiada jednak pewne ograniczenia, mimo przełącznika d, który pozwala na wylistowanie plików z rozmiarami – nie potrafi przeliczyć zajętości katalogów. A nie ukrywam, że często tego potrzebuję. Szczególnie na serwerze, lub na serwerach klientów (gdzie niestety tego narzędzia nie mamy zainstalowanego, ale o tym dalej).

Szukałem alternatywy, która wyliczałaby zajętość plików i folderów. Znalazłem ncdu.
ncdu potrafi z kolei fajnie w postaci „wykresu” przedstawić aktualną zajętość katalogu, w którym się znajdujemy, oraz udostępnia podstawowe funkcje menadżera plików, jak np. usuwanie pojedynczych plików/folderów, które mamy zaznaczone.

Generuje natomiast pewne ograniczenie, którego nie byłem w stanie przeskoczyć – program nie jest zainstalowany na serwerach, z których korzystam, więc jest, ale bez dostępu. Poza tym brakowało w nim też fundamentalnej dla mnie funkcji – przeliczania liczby plików z obecnego katalogu oraz podkatalogów.
No i tutaj dochodzimy do finału wpisu. Ze względu na ograniczenia, stawiane przez sysops oraz własną wygodę, zrobiłem swój skrypcik, który robi to, co chcę, od początku do końca :)
- Sortuje pliki i katalogi uwzględniając ich rozmiar
- Pokazuje to w czytelnej postaci wykresu
- Zlicza liczbę plików i katalogów
- Nie wymaga instalacji ;)
#!/usr/bin/env bash
#
# dusize.sh - wizualizacja zajętości katalogu przy użyciu du + awk.
# Sortuje wpisy malejąco wg rozmiaru i rysuje słupki proporcjonalne
# do największego elementu. Katalogi na niebiesko, pliki na bialo.
# Uruchomienie: ./dusize.sh działa w bieżącym katalogu.
# Kontakt: Filip Cierpich (keepmind.eu)
export LC_ALL=C
spin='-\|/'
si=0
tick() {
[ -t 2 ] || return
si=$(( (si + 1) % 4 ))
printf '\r\033[1;36m%s\033[0m Skanowanie: %-40.40s' "${spin:$si:1}" "$1" >&2
}
clear_line() { [ -t 2 ] && printf '\r\033[K' >&2; }
data=$(find . -mindepth 1 -maxdepth 1 -print0 2>/dev/null | while IFS= read -r -d '' path; do
name=${path#./}
tick "$name"
size=$(du -sh -- "$path" 2>/dev/null | cut -f1)
[ -n "$size" ] || continue
if [ -d "$path" ]; then
type=d
# liczymy WSZYSTKIE pliki i podkatalogi w glab (bez ograniczenia poziomow)
fc=$(find "$path" -mindepth 1 \( -type f -o -type d \) 2>/dev/null | wc -l); fc=$((fc))
else
type=f
fc=-1
fi
printf '%s\t%s\t%s\t%s\n' "$size" "$type" "$fc" "$name"
done)
tick "podsumowanie"
# pelna rekurencja: osobno pliki i katalogi w calym drzewie
total_files=$(find . -mindepth 1 -type f 2>/dev/null | wc -l); total_files=$((total_files))
total_dirs=$(find . -mindepth 1 -type d 2>/dev/null | wc -l); total_dirs=$((total_dirs))
total=$((total_files + total_dirs))
dirsize=$(du -sh . 2>/dev/null | cut -f1)
clear_line
render() {
printf '%s\n' "$data" | awk -F'\t' \
-v total="$total" -v tfiles="$total_files" -v tdirs="$total_dirs" \
-v dirsize="$dirsize" '
BEGIN {
BLUE="\033[1;34m"; WHITE="\033[0;37m"; RESET="\033[0m"
}
NF >= 4 {
size=$1; type=$2; fc=$3; name=$4
unit=substr(size, length(size))
val=substr(size, 1, length(size)-1)
if (unit=="T") mb=val*1024*1024*1024
else if (unit=="G") mb=val*1024*1024
else if (unit=="M") mb=val*1024
else if (unit=="K") mb=val+0
else mb=(val+0)/1024
count++
sizes[count]=mb; names[count]=name; labels[count]=size
types[count]=type; fcounts[count]=fc
if (type=="d") dirs++; else files++
}
END {
for (i=1;i<=count;i++)
for (j=i+1;j<=count;j++)
if (sizes[j]>sizes[i]) {
t=sizes[i]; sizes[i]=sizes[j]; sizes[j]=t
t=names[i]; names[i]=names[j]; names[j]=t
t=labels[i]; labels[i]=labels[j]; labels[j]=t
t=types[i]; types[i]=types[j]; types[j]=t
t=fcounts[i]; fcounts[i]=fcounts[j]; fcounts[j]=t
}
printf "%-8s %-6s %-34s %s\n", "Rozmiar","Wpisy","Wykres","Nazwa"
print "-------- ------ ---------------------------------- --------"
maxmb=(count>0 && sizes[1]>0) ? sizes[1] : 1
for (i=1;i<=count;i++) {
bars=int((sizes[i]/maxmb)*32); if(bars<1)bars=1
bar=""
for(k=0;k<bars;k++) bar=bar"\xe2\x96\x88"
for(k=bars;k<32;k++) bar=bar"\xe2\x96\x91"
color=(types[i]=="d") ? BLUE : WHITE
fcl=(fcounts[i]=="-1") ? "-" : fcounts[i]
printf "%s%-8s %-6s [%s] %s%s\n", color, labels[i], fcl, bar, names[i], RESET
}
print "-------- ------ ---------------------------------- --------"
printf "Katalogi: %-4d Pliki: %-4d\n", dirs+0, files+0
printf "Zawartość (rekurencyjnie) -> Pliki: %d Katalogi: %d Razem (inody): %d\n", tfiles+0, tdirs+0,
total+0
printf "Zajęta przestrzeń: %s\n", dirsize
}'
}
if [ -t 1 ] && [ "${REVEAL:-1}" != 0 ]; then
render | while IFS= read -r line; do
printf '%s\n' "$line"
sleep 0.015 2>/dev/null
done
else
render
fi


Uruchomić go możemy na kilka sposobów. Począwszy od bezpośredniego wpisania całego skryptu, jako polecenie, jako zapisanie pliku do katalogu ~/bin, z uprawnieniami +x, czy też globalnie wrzucając do /usr/bin. Jest też możliwość wrzucenia na swój hosting i wykonanie polecenia do jego uruchomienia, np.:
curl -sSL https://domena.pl/plik | bash

Dodaj komentarz