bha 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/python3
  2. # Bash History Analyser
  3. # by Farooq Karimi Zadeh
  4. # fkz@riseup.net
  5. # Under GNU GPLv3+
  6. # This software is free software and COMES WITHOUT ANY WARRENTY FROM MAIN AUTHOR
  7. # https://notabug.org/farooqkz/BHA
  8. import sys
  9. import os
  10. def fexist(path): # file exist
  11. return os.path.isfile(path)
  12. def cexist(command): # command exist
  13. for path in os.environ["PATH"].split(":"):
  14. if fexist(f"{path}/{command}"):
  15. return True
  16. return False
  17. def usage():
  18. print('Usage: bha [History_file_path]')
  19. def dictsort(adict): # this function sorts a map by its values (uses bubblesort)
  20. keys = list(adict.keys())
  21. values = list(adict.values())
  22. swaped = 1
  23. while swaped:
  24. swaped = 0
  25. for i in range(len(values)):
  26. if i == len(values) - 1: continue
  27. if values[i] < values[i+1]:
  28. values[i], values[i+1] = values[i+1], values[i]
  29. keys[i], keys[i+1] = keys[i+1], keys[i] # swap
  30. swaped = 1
  31. return [keys, values]
  32. def excmd(s): # EXtracts CoMMands from a given string
  33. # first we delete anything between two "
  34. ns = '' # new string
  35. inq = False
  36. for i in s:
  37. if i == '\"':
  38. inq = not inq # toggle
  39. continue
  40. if not inq:
  41. ns += i
  42. # then we delete anything between two '
  43. fs = '' # final string
  44. inq = False
  45. for i in ns:
  46. if i == '\'':
  47. inq = not inq
  48. continue
  49. if not inq:
  50. fs += i
  51. cmds = []
  52. for i in fs.split(' '):
  53. if i.startswith('./'): # we don't count them
  54. continue
  55. if i.startswith('#'): # we don't count comments
  56. continue
  57. if i == 'sudo' or i == 'su': # they aren't command.are they?
  58. continue
  59. if cexist(i):
  60. cmds.extend([i])
  61. return cmds
  62. history_file_path = os.path.expanduser('~') + '/.bash_history'
  63. if len(sys.argv) == 2:
  64. history_file_path = sys.argv[1]
  65. fs = open(history_file_path) # opens a File Stream for text reading
  66. history = fs.read() # reads all what is in file
  67. fs.close() # closes the file stream (no longer we need it)
  68. history = history.split('\n') # => a list of strings seprated by a new line
  69. cmds = {} # an empty map
  70. for i in history:
  71. for cmd in excmd(i):
  72. if cmd not in cmds:
  73. cmds[cmd] = 1
  74. else:
  75. cmds[cmd] += 1
  76. cmds = dictsort(cmds) # {'ls': 125, 'gcc': 10, 'cat': 100} => [['ls', 'cat', 'gcc'], [125, 100, 10]]
  77. total = sum(cmds[1]) # [0, 1, 2] => 3
  78. othercc = 0 # Other Commands Count (anything lower than 0.25%)
  79. otherc = [] # list of other commands
  80. for i in range(len(cmds[0])):
  81. cmd = cmds[0][i]
  82. count = cmds[1][i]
  83. percent = count / total * 100
  84. if percent < 0.25:
  85. othercc += count
  86. otherc.extend([cmd])
  87. else:
  88. print(cmd + ': ', round(percent,2), '%', ' (', count, '/', total, ')', sep='')
  89. print('other commands: ')
  90. for i in otherc:
  91. print(i, end=', ')
  92. print()
  93. print('% of other: ', round(othercc/total*100, 2), '%', ' (', othercc, '/', total, ')', sep='')