Skip to content

Instantly share code, notes, and snippets.

@alaniwi
Created May 1, 2024 07:41
Show Gist options
  • Save alaniwi/d71bf9b982903f493a70a31b65fe59ef to your computer and use it in GitHub Desktop.
Save alaniwi/d71bf9b982903f493a70a31b65fe59ef to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""
Display various file statistics for each directory.
"""
import sys
import os
import stat
from time import strftime, localtime
class FileStats:
def __init__(self):
self.min_mtime = None
self.max_mtime = None
self.min_ctime = None
self.max_ctime = None
self.min_atime = None
self.max_atime = None
self.tot_blocks = 0
self.tot_inodes = 0
def add(self, stat_data):
mtime = stat_data.st_mtime
ctime = stat_data.st_ctime
atime = stat_data.st_atime
self.min_mtime = self._min(self.min_mtime, mtime)
self.max_mtime = self._max(self.max_mtime, mtime)
self.min_ctime = self._min(self.min_ctime, ctime)
self.max_ctime = self._max(self.max_ctime, ctime)
self.min_atime = self._min(self.min_atime, atime)
self.max_atime = self._max(self.max_atime, atime)
self.tot_blocks += stat_data.st_blocks
self.tot_inodes += 1
def update(self, other):
self.min_mtime = self._min(self.min_mtime, other.min_mtime)
self.max_mtime = self._max(self.max_mtime, other.max_mtime)
self.min_ctime = self._min(self.min_ctime, other.min_ctime)
self.max_ctime = self._max(self.max_ctime, other.max_ctime)
self.min_atime = self._min(self.min_atime, other.min_atime)
self.max_atime = self._max(self.max_atime, other.max_atime)
self.tot_blocks += other.tot_blocks
self.tot_inodes += other.tot_inodes
def _max(self, a, b):
return self._func(a, b, max)
def _min(self, a, b):
return self._func(a, b, min)
def _func(self, a, b, f):
if a is None:
return b
elif b is None:
return a
else:
return f(a, b)
def __str__(self):
fields = [
('min_mtime', self._time_format(self.min_mtime)),
('max_mtime', self._time_format(self.max_mtime)),
('min_ctime', self._time_format(self.min_ctime)),
('max_ctime', self._time_format(self.max_ctime)),
('min_atime', self._time_format(self.min_atime)),
('max_atime', self._time_format(self.max_atime)),
('blocks', self.tot_blocks),
('inodes', self.tot_inodes),
]
return ' '.join(f'{k}={v}' for k, v in fields)
def _time_format(self, timeval):
if timeval is None:
return 'None'
else:
return strftime('%Y-%m-%d.%H:%M:%S', localtime(timeval))
def scan(path, depth=0):
stats = FileStats()
try:
els = os.listdir(path)
except OSError as exc:
sys.stderr.write(f"{exc}\n")
return stats
for el in els:
elp = os.path.join(path, el)
try:
stat_data = os.lstat(elp)
except OSError as exc:
sys.stderr.write(f"{exc}\n")
continue
if stat.S_ISDIR(stat_data.st_mode):
stats_sub = scan(elp, depth=(depth + 1))
stats.update(stats_sub)
else:
stats.add(stat_data)
stat_data = os.lstat(path)
stats.add(stat_data)
print(f'{stats} depth={depth} {path}')
return stats
def main():
try:
path, = sys.argv[1:]
except ValueError:
sys.stderr.write("starting path needed as command line argument\n")
sys.exit(1)
scan(path)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment