Disk-Usage

bash:使du顯示類似於ncdu的輸出

  • February 9, 2022

ncdu在 Linux 上,以下是NCurses 磁碟使用工具的一些範例輸出:

命令:

ncdu /boot
ncdu 1.14.1 ~ Use the arrow keys to navigate, press ? for help 
--- /boot -----------------------------------------------------
 100.2 MiB [##########]  initrd.img-5.13.0-28-generic         
 100.2 MiB [######### ]  initrd.img-5.13.0-27-generic
  11.2 MiB [#         ]  vmlinuz-5.11.0-46-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-28-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-27-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-25-generic
   8.0 MiB [          ] /grub
   5.7 MiB [          ]  System.map-5.13.0-28-generic
   5.7 MiB [          ]  System.map-5.13.0-27-generic
   5.7 MiB [          ]  System.map-5.13.0-25-generic
   5.6 MiB [          ]  System.map-5.11.0-46-generic
 252.0 KiB [          ]  config-5.13.0-28-generic
 252.0 KiB [          ]  config-5.13.0-27-generic
 252.0 KiB [          ]  config-5.13.0-25-generic
 252.0 KiB [          ]  config-5.11.0-46-generic
 184.0 KiB [          ]  memtest86+_multiboot.bin
 184.0 KiB [          ]  memtest86+.elf
 180.0 KiB [          ]  memtest86+.bin
!  16.0 KiB [          ] /lost+found
!   4.0 KiB [          ] /efi
@   0.0   B [          ]  initrd.img.old
@   0.0   B [          ]  initrd.img
@   0.0   B [          ]  vmlinuz.old
@   0.0   B [          ]  vmlinuz

但是,它是一個人機互動程序,並且輸出不可編寫腳本。我想將它儲存到一個變數中,那麼,我怎樣才能獲得類似的輸出du呢?

這是我的問題的後續問題:如何ncdu快速顯示磁碟使用情況並退出?

最終用途將如下所示:

output_before="$(du /boot)"
# do a bunch of stuff here which reduces the size of /boot
output_after="$(du /boot)"
echo "Before:"
echo "$output_before"
echo ""
echo "After:"
echo "$output_after"

這是一個開始,但它沒有以正確的從大到小的降序顯示輸出:

du --all --max-depth=1 -h /boot

我最想看到的:

--- /boot -----------------------------------------------------
 100.2 MiB [##########]  initrd.img-5.13.0-28-generic         
 100.2 MiB [######### ]  initrd.img-5.13.0-27-generic
  11.2 MiB [#         ]  vmlinuz-5.11.0-46-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-28-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-27-generic
   9.7 MiB [          ]  vmlinuz-5.13.0-25-generic
   8.0 MiB [          ] /grub
   5.7 MiB [          ]  System.map-5.13.0-28-generic
   5.7 MiB [          ]  System.map-5.13.0-27-generic
   5.7 MiB [          ]  System.map-5.13.0-25-generic
   5.6 MiB [          ]  System.map-5.11.0-46-generic
 252.0 KiB [          ]  config-5.13.0-28-generic
 252.0 KiB [          ]  config-5.13.0-27-generic
 252.0 KiB [          ]  config-5.13.0-25-generic
 252.0 KiB [          ]  config-5.11.0-46-generic
 184.0 KiB [          ]  memtest86+_multiboot.bin
 184.0 KiB [          ]  memtest86+.elf
 180.0 KiB [          ]  memtest86+.bin
  16.0 KiB [          ] /lost+found
   4.0 KiB [          ] /efi
   0.0   B [          ]  initrd.img.old
   0.0   B [          ]  initrd.img
   0.0   B [          ]  vmlinuz.old
   0.0   B [          ]  vmlinuz

但是,可接受的最低答案如下所示:

 100.2 MiB  /boot/initrd.img-5.13.0-28-generic         
 100.2 MiB  /boot/initrd.img-5.13.0-27-generic
  11.2 MiB  /boot/vmlinuz-5.11.0-46-generic
   9.7 MiB  /boot/vmlinuz-5.13.0-28-generic
   9.7 MiB  /boot/vmlinuz-5.13.0-27-generic
   9.7 MiB  /boot/vmlinuz-5.13.0-25-generic
   8.0 MiB  /boot/grub
   5.7 MiB  /boot/System.map-5.13.0-28-generic
   5.7 MiB  /boot/System.map-5.13.0-27-generic
   5.7 MiB  /boot/System.map-5.13.0-25-generic
   5.6 MiB  /boot/System.map-5.11.0-46-generic
 252.0 KiB  /boot/config-5.13.0-28-generic
 252.0 KiB  /boot/config-5.13.0-27-generic
 252.0 KiB  /boot/config-5.13.0-25-generic
 252.0 KiB  /boot/config-5.11.0-46-generic
 184.0 KiB  /boot/memtest86+_multiboot.bin
 184.0 KiB  /boot/memtest86+.elf
 180.0 KiB  /boot/memtest86+.bin
  16.0 KiB  /boot/lost+found
   4.0 KiB  /boot/efi
   0.0   B  /boot/initrd.img.old
   0.0   B  /boot/initrd.img
   0.0   B  /boot/vmlinuz.old
   0.0   B  /boot/vmlinuz

python從以下內容讀取的小腳本ncdu -o-

read_ncdu.py:

#!/usr/bin/env python3

import sys, json

def sizeof_fmt(num, suffix='B'):
   for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
       if abs(num) < 1024.0:
           return "%3.1f%s%s" % (num, unit, suffix)
       num /= 1024.0
   return "%.1f%s%s" % (num, 'Yi', suffix)

def get_recursive(item):
   size = 0
   if isinstance(item, dict):
       name = item["name"]
       size = item["asize"]
   else:
       name = item[0]["name"]
       for sub in item:
           size += get_recursive(sub)[1]
   return (name, size)

data = json.loads(sys.stdin.read())

items=[]
for i in data[3][1:]:
   items.append(get_recursive(i))

sum_sizes = sum([item[1] for item in items])
biggest = max([item[1] for item in items])
print("------ {} --- {} -------".format(data[3][0]["name"], sizeof_fmt(sum_sizes)))

for item in sorted(items, key=lambda x:x[1], reverse=True):
   size=item[1]
   hsize=sizeof_fmt(item[1])
   name=item[0]
   percent=(size/sum_sizes*100)
   percent_str="({:.1f}%)".format(percent)
   
   print("{} {:8} [{}{}] {}".format(
       " " * (10 - len(str(hsize)))+ str(hsize),
       " " * (8 - len(percent_str)) + percent_str,  
       ('#' * round(size/biggest*10)),
       ('-' * round(10-size/biggest*10)),
       item[0])
   )

您可能想要改進腳本:

  • 如果您願意,可以使用dsize(disk size) 代替asize(apparant size),或者在腳本中引入參數讓使用者決定。
  • os.walk()使用而不是使用ncdu -o-輸入使腳本獨立。

有關json 輸出格式的說明,另請參見此處。ncdu

跑:

使read_ncdu.py執行檔 –> chmod +x read_ncdu.py,然後你可以執行:

ncdu -o- /boot | ./read_ncdu.py

輸出:

------ /boot --- 224.3MiB -------
  56.8MiB  (25.3%)  [##########]  initrd.img-5.13.0-28-generic
  56.7MiB  (25.3%)  [##########]  initrd.img-5.13.0-27-generic
  55.4MiB  (24.7%)  [##########]  initrd.img-5.11.0-46-generic
  11.2MiB  (5.0%)   [##--------]  vmlinuz-5.11.0-46-generic
   9.7MiB  (4.3%)   [##--------]  vmlinuz-5.13.0-28-generic
   9.7MiB  (4.3%)   [##--------]  vmlinuz-5.13.0-27-generic
   6.5MiB  (2.9%)   [#---------]  grub
   5.7MiB  (2.5%)   [#---------]  System.map-5.13.0-28-generic
   5.7MiB  (2.5%)   [#---------]  System.map-5.13.0-27-generic
   5.6MiB  (2.5%)   [#---------]  System.map-5.11.0-46-generic
 251.7KiB  (0.1%)   [----------]  config-5.13.0-28-generic
 251.6KiB  (0.1%)   [----------]  config-5.13.0-27-generic
 248.1KiB  (0.1%)   [----------]  config-5.11.0-46-generic
 180.6KiB  (0.1%)   [----------]  memtest86+_multiboot.bin
 180.1KiB  (0.1%)   [----------]  memtest86+.elf
 178.4KiB  (0.1%)   [----------]  memtest86+.bin
  16.0KiB  (0.0%)   [----------]  lost+found
    28.0B  (0.0%)   [----------]  initrd.img
    28.0B  (0.0%)   [----------]  initrd.img.old
    25.0B  (0.0%)   [----------]  vmlinuz
    25.0B  (0.0%)   [----------]  vmlinuz.old

根據以下問題,這提供了可接受的最低答案

du --all --max-depth=1 -h /boot | sort -rh

範例用法,根據問題中的範例(但製成“單行”命令,因此我可以將其複制粘貼到終端中,而無需為其製作執行檔腳本):

output="$(du --all --max-depth=1 -h /boot | sort -rh)"; \
echo "Before:"; \
echo "$output"

輸出到標準輸出的範例:

Before:
273M    /boot
101M    /boot/initrd.img-5.13.0-28-generic
101M    /boot/initrd.img-5.13.0-27-generic
12M /boot/vmlinuz-5.11.0-46-generic
9.8M    /boot/vmlinuz-5.13.0-28-generic
9.7M    /boot/vmlinuz-5.13.0-27-generic
9.7M    /boot/vmlinuz-5.13.0-25-generic
8.0M    /boot/grub
5.7M    /boot/System.map-5.13.0-28-generic
5.7M    /boot/System.map-5.13.0-27-generic
5.7M    /boot/System.map-5.13.0-25-generic
5.6M    /boot/System.map-5.11.0-46-generic
252K    /boot/config-5.13.0-28-generic
252K    /boot/config-5.13.0-27-generic
252K    /boot/config-5.13.0-25-generic
252K    /boot/config-5.11.0-46-generic
184K    /boot/memtest86+_multiboot.bin
184K    /boot/memtest86+.elf
180K    /boot/memtest86+.bin
16K /boot/lost+found
4.0K    /boot/efi
0   /boot/vmlinuz.old
0   /boot/vmlinuz
0   /boot/initrd.img.old
0   /boot/initrd.img

參考:

  1. 感謝@terdon,他指出 sort -h可以按人類可讀的大小進行排序,例如9.7 MiBvs 100 KiB

也可以看看:

  1. @Fabien Auréjac 指出的問答:伺服器故障:如何按大小對 du -h 輸出進行排序-sort -h可以對人類可讀的輸出進行排序du -h

引用自:https://unix.stackexchange.com/questions/689668