-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfile-recent
executable file
·394 lines (320 loc) · 13.9 KB
/
file-recent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/bin/python3
'''
Note that:
alias recent_files="find . -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort"
...does almost everything all this code does :)
Written by Bart Alewijnse
'''
import sys
import os
import time
import re
import datetime
from optparse import OptionParser
def kmg(bytes,kilo=1000, append='',thresh=15,rstrip0=1):
""" Readable size formatter
e.g. '%sB'%kmg(2342342324) = '2.3 GB'
kmg(3429873278462) == '3.1T'
kmg(342987327) == '327M'
kmg(34298) == '33K'
Decimal/SI kilos by default. Specify kilo=1024 if you want binary kilos.
Maybe use sfloat-like behaviour for the number?
"""
ret=None
mega=kilo*kilo
giga=mega*kilo
tera=giga*kilo
peta=tera*kilo
if abs(bytes)>(0.80*peta):
showval = bytes/float(peta)
if showval<thresh:
ret= "%.1f"%(showval,)
else:
ret= "%.0f"%(showval,)
append+='P'
elif abs(bytes)>(0.80*tera):
showval = bytes/float(tera)
if showval<thresh:
ret= "%.1f"%(showval,)
else:
ret= "%.0f"%(showval,)
append+='T'
elif abs(bytes)>(0.95*giga):
showval = bytes/float(giga)
if showval<thresh: # e.g. 1.3GB but 15GB
ret= "%.1f"%(showval,)
else:
ret= "%.0f"%(showval,)
append+='G'
elif abs(bytes)>(0.9*mega):
showval = bytes/float(mega)
if showval<thresh:
ret= "%.1f"%(showval,)
else:
ret= "%.0f"%(showval,)
append+='M'
elif abs(bytes)>(0.85*kilo):
showval = bytes/float(kilo)
if showval<thresh:
ret= "%.1f"%(showval,)
else:
ret= "%.0f"%(showval,)
append+='K'
else:
ret= "%d"%(bytes,)
if rstrip0:
if '.' in ret:
ret=ret.rstrip('0').rstrip('.')
ret+=append
return ret
def nicetimelength(sec, long=False, joinon=' ', parts=2):
""" Takes a relative amount of time (seconds as float/int, or a timedelta)
Returns a string describing that is human terms
e.g. nicetimelength(767) == '12min 47sec',
nicetimelength(2615958475) == '82yr 11mo',
"""
if type(sec) is datetime.timedelta:
sec = sec.days*86400 + sec.seconds
vals = [
#('century','centuries','cent', 60.*60.*24.*365.*100. ),
('year', 'years', 'yr', 60.*60.*24.*365. ),
('month', 'months', 'mo', 60.*60.*24.*30.6 ),
('week', 'weeks', 'wk', 60.*60.*24.*7 ),
('day', 'days', 'dy', 60.*60.*24. ),
('hour', 'hours', 'hr', 60.*60. ),
('minute', 'minutes', 'min', 60. ),
#('second', 'seconds', 'sec', 1. ),
]
ret=[]
left = sec
roundme=False
if left>10:
roundme=True
for one,many,shorts,insec in vals:
if left>insec:
howmany = int(left/insec)
left -= howmany*insec
if long:
if howmany==1:
ret.append( '1 %s'%(one) )
else:
ret.append( '%d %s'%(howmany,many) )
else: # short form
ret.append('%2d%-3s'%(howmany,shorts))
if left>0.:
if long:
ret.append( '%d seconds'%(left) )
else:
ret.append( '%dsec'%(left) )
return joinon.join(ret[:parts])
def walk_and_print(paths, recursive, what,amount=None, future=True, dirs=False, timespec_sec=None, use_color=True, sort=False):
results = [] # (time, line)
what_type = 'time' # or size
now = time.time()
try:
for path in paths:
for r, d, f in os.walk( path ):
if dirs: # show dirs in results?
f.extend(d) # (cheating a bit)
if not recursive:
del( d[:] ) # clear that array (see os.walk docs)
for fn in f:
ffn = os.path.join(r, fn)
mode, inode, device, numhardlinks, uid,gid, size, atime, mtime, ctime = os.lstat(ffn)
#print( datetime.datetime.fromtimestamp( mtime ) )
if what=='mtime':
what_val = now - mtime
elif what=='atime':
what_val = now - atime
elif what=='ctime':
what_val = now - ctime
elif what=='cmtime':
what_val = now - max(ctime,mtime)
elif what=='cmatime':
what_val = now - max(ctime,mtime,atime)
elif what=='size':
what_val = size
what_type = 'size'
else:
raise ValueError("Don't understand sorting by %r"%what)
if what_val < 0 and not future:
continue
if what_type=='time':
if what_val < timespec_sec:
vst = nicetimelength(what_val)
line=[]
#if use_color:
# line.append(col)
line.append('%16s'%vst)
#if use_color:
# line.append( sc.RESET )
line.append(': %s\n'%(ffn,))
if not sort:
sys.stdout.write(''.join(line))
sys.stdout.flush()
else:
results.append( (what_val, ''.join(line)) )
elif what_type=='size':
line=['%15sB: %s\n'%(kmg(what_val),ffn)]
if not sort:
sys.stdout.write(''.join(line))
sys.stdout.flush()
else:
results.append( (size, ''.join(line)) )
else:
raise ValueError("Don't know type %r"%what_type)
if sort:
results.sort(key = lambda x:x[0], reverse=True)
if amount:
results = results[-int(amount):]
for sortkey, line in results:
sys.stdout.write(line)
sys.stdout.flush()
except KeyboardInterrupt:
#if use_color:
# print sc.RESET
print( "\nStopping")
#if use_color:
# print sc.RESET
def main():
##################################################
parser = OptionParser() # Has some options, but we're ignoring this
parser.add_option("-r", "--recurse", dest="recursive", default=True, action="store_true",
help="Recurse into subdirectories")
parser.add_option("-R", "--no-recurse", dest="recursive", default=True, action="store_false",
help="Recurse into subdirectories")
parser.add_option("-d", "--dirs", dest="dirs", default=False, action="store_true",
help="include directories in results")
parser.add_option("-M", "--cmtime", dest="cmtime", default=False, action="store_true",
help="use max(ctime,mtime) (default)")
parser.add_option("-A", "--cmatime", dest="cmatime", default=False, action="store_true",
help="use max(ctime,mtime,atime)")
parser.add_option("-m", "--mtime", dest="mtime", default=False, action="store_true",
help="use mtime")
parser.add_option("-a", "--atime", dest="atime", default=False, action="store_true",
help="use atime")
parser.add_option("-c", "--ctime", dest="ctime", default=False, action="store_true",
help="use ctime")
parser.add_option("-f", "--filesize", dest="filesize", default=False, action="store_true",
help="use file size")
parser.add_option("-p", "--colors", dest="colors", default=True, action="store_true",
help="use pretty colors in output")
parser.add_option("-P", "--no-colors", dest="colors", default=True, action="store_false",
help="use no colors in output")
parser.add_option("-s", "--nosort", dest="sort", default=True, action="store_false",
help="Don't sort output (by default it sorts by time - see options related to ctime, mtime, and atime). Implies not limiting by amount")
parser.add_option("-n", "--amount", dest="amount", default='30', action="store", type="string",
help="show only the most recent x files (implies --sort) (default: 100)")
parser.add_option("-t", "--timespec", dest="timespec", default=False, action="store", type="string",
help="Look only at files younger than some age, a value like 200day or 60min (default: 100day)")
parser.add_option("-F", "--no-future", dest="future", default=True, action="store_false",
help="don't display files with future dates")
parser.add_option("-w", "--watch", dest="watch", default=False, action="store_true", help="repeat every 10sec")
#if __name__ == '__main__':
(options, args) = parser.parse_args()
#
what = 'cmtime' # default
what_s = 'max(ctime,mtime)'
if options.filesize:
what = 'size'
what_s = 'size'
elif options.cmtime:
what = 'cmtime'
what_s = 'max(ctime,mtime)'
elif options.cmatime:
what = 'cmatime'
what_s = 'max(ctime,mtime,atime)'
elif options.mtime:
what = 'mtime'
what_s = what
elif options.atime:
what = 'atime'
what_s = what
elif options.ctime:
what = 'ctime'
what_s = what
recursive = False
if options.recursive:
recursive = True
sort = options.sort
if not options.sort: # that is, you used --nosort
options.amount = None
if options.amount: # if you used amount, default (back) to sorting
options.amount = int(options.amount)
sort = True
use_color = False
#if options.colors:
# use_color = sc.supported()
dirs = False
if options.dirs:
dirs = True
if len(args) == 0:
rcwd = os.path.realpath('.')
sys.stderr.write('Defaulting to current directory (%r)\n'%rcwd)
paths = [rcwd]
else:
sys.stderr.write('Looking in %s\n'%(', '.join(repr(e) for e in args)))
paths = args
paths = list( os.path.abspath(item) for item in paths)
in_seconds = False
if options.timespec:
howmuch = options.timespec.strip()
# TODO: use time parser I have somewhere, and/or merge this in.
if howmuch.endswith('d') or howmuch.endswith('day') or howmuch.endswith('days'):
howmuch = howmuch.rstrip('days') # yeah, that's cheating a bit :)
days = float(howmuch)
in_seconds = 86400. * days
named_units = 'days'
sys.stderr.write( " checking %s is in the last %d days\n"%(what_s,days) )
sys.stderr.flush()
elif howmuch.endswith('m') or howmuch.endswith('min') or howmuch.endswith('mins') or howmuch.endswith('minute') or howmuch.endswith('minutes'):
howmuch = howmuch.rstrip('minutes') # yeah, that's cheating a bit :)
mins = float(howmuch)
in_seconds = 60. * mins
sys.stderr.write( " checking %s is in the last %d minutes\n"%(what_s,mins) )
sys.stderr.flush()
elif howmuch.endswith('s') or howmuch.endswith('sec') or howmuch.endswith('secs') or howmuch.endswith('second') or howmuch.endswith('seconds'):
howmuch = howmuch.rstrip('seconds') # yeah, that's cheating a bit :)
secs = float(howmuch)
in_seconds = secs
sys.stderr.write( " checking %s is in the last %d secs"%(what_s,secs) )
sys.stderr.flush()
else:
sys.stderr.write( "\nDidn't recognize time units in %r\n"%howmuch )
sys.stderr.flush()
sys.exit(-1)
if not in_seconds:
sys.stderr.write(' including files where %s is in the last 100 days\n'%what_s)
in_seconds = 86400. * 100
if options.sort:
sys.stderr.write(' will sort results by age\n')
if options.amount:
sys.stderr.write(' and show the %d most recent files\n'%options.amount)
#sys.stderr.write('.\n')
sys.stderr.flush()
ERASEDISP = '\x1b[2J'
GOTO00 = '\x1b[;H'
CLEARSCREEN = ERASEDISP + GOTO00
if options.watch:
while True:
print( CLEARSCREEN )
walk_and_print(paths,recursive,what,
amount = options.amount,
future = options.future,
dirs = dirs,
timespec_sec = in_seconds,
use_color = use_color,
sort = options.sort,
)
time.sleep(10)
else:
walk_and_print(paths,recursive,what,
amount=options.amount,
future=options.future,
dirs=dirs,
timespec_sec = in_seconds,
use_color = use_color,
sort = options.sort,
)
if __name__=='__main__':
main()