#!/usr/bin/env python # Copyright 2008 by Aidin Abedi # Some parts are modifications of http://www.pixelbeat.org/talks/python/ls.py # This script is essentially equivalent to "ls -lagFR" # It recursively prints details of all (even hidden) files in a directory # include necessary libraries import os import sys import stat # index constants for os.stat() import platform # OS name import locale import time # global time constants, used in printInfo() now = int(time.time()) recent = now - (6*30*24*60*60) # 6 months ago # global color variables, used in main() and printInfo() colorful = False # initially, no color support colors = { # dictionary to convert color-name to terminal-code "none": "", "default": "\x1b[00m", "blue": "\x1b[01;34m", "cyan": "\x1b[01;36m", "green": "\x1b[01;32m", "red": "\x1b[01;31m" } #----------------------------------------------------------------------------- # simplified from Python cookbook, #475186 def hasColors(): if not hasattr(sys.stdout, "isatty"): return False elif not sys.stdout.isatty(): return False # auto color only on TTYs elif platform.system().lower() == "windows": return False # windows not supported else: return True # guess #----------------------------------------------------------------------------- # find and print reason for error def printError(filename, source): if not os.access(filename, os.F_OK): # check if exists print "%s: No such file or directory" % filename elif not os.access(filename, os.R_OK): # check read access print "%s: Premission denied" % filename else: # bad happened print "%s: Unknown %s() error" % (filename, source) #----------------------------------------------------------------------------- # print well formated file info def printInfo(filename, filetitle = ""): if not filetitle: # default value for filetitle filetitle = filename try: # lstat() is like stat(), but do not follow symbolic links filestat = os.lstat(filename) # get all file info except: printError(filename, "lstat") # print error return # exit function try: import pwd # not available on all platforms fileuser = pwd.getpwuid(filestat.st_uid)[0] # convert to user name except (ImportError, KeyError): fileuser = "usr#%d" %filestat.st_uid # just user id try: import grp # not available on all platforms filegroup = grp.getgrgid(filestat.st_gid)[0] # convert to group name except (ImportError, KeyError): filegroup = "grp#%d" % filestat.st_gid # just group id filemode = filestat.st_mode fileperms = '-' # string representing premissions fileisdir = False # fileisdir is returned at end of function filecolor = "none" # classify file if stat.S_ISDIR(filemode): # directory fileperms = 'd' filecolor = "blue" filetitle += '/' # add indication fileisdir = True # inform function caller that file is a directory elif stat.S_ISLNK(filemode): # symbolic link fileperms = 'l' filecolor = "cyan" # get relative and absolute link filenames targetrel = os.readlink(filename) targetabs = os.path.join(os.path.dirname(filename), targetrel) filetitle += " -> " + targetrel # add 'point to' target if not os.path.exists(targetabs): # target doesn't exists filecolor = "red" # bad link elif os.path.isdir(targetabs): # target is a directory filetitle += '/' # add indication elif stat.S_ISREG(filemode): # regular file if filemode & (stat.S_IXGRP|stat.S_IXUSR|stat.S_IXOTH): # executable filecolor = "green" filetitle += '*' # add indication # loop every combination "S_I" + ["R", "W", "X"] + ["USR", "GRP", "OTH"] for who in "USR", "GRP", "OTH": for what in "R", "W", "X": # lookup attributes at runtime using getattr if filemode & getattr(stat, "S_I" + what + who): fileperms += what.lower() # add 'r', 'w', or 'x' else: fileperms += '-' # doesn't have access # get modification time stamp of file filetime = filestat.st_mtime global recent, now if (filetime < recent) or (filetime > now): # time stamp is 6 months old filetime = time.strftime("%b %d %Y", time.localtime(filetime)) else: filetime = time.strftime("%b %d %H:%M", time.localtime(filetime)) # format file info to fixed-size columns filenlink = "%2d" % filestat.st_nlink filesize = "%8d" % filestat.st_size fileuser = "%-8s" % fileuser filegroup = "%-8s" % filegroup # add color if available global colorful, colors if colorful and colors[filecolor]: filetitle = colors[filecolor] + filetitle + colors["default"] # print the result print fileperms, filenlink, fileuser, filegroup, # don't add newline print filesize, filetime, filetitle return fileisdir # is this file a directory #----------------------------------------------------------------------------- # print all files and dirs in a directory and it's sub-directories def printDir(directory): if os.path.isfile(directory): # directory is actually a file printInfo(directory) return # exit function try: # get array of files (and dirs) in directory files = os.listdir(directory) # Python doesn't have opendir, readdir except: printError(directory, "listdir") # print error return # exit function # do locale sensitive sort of files to list locale.setlocale(locale.LC_ALL, '') files.sort(locale.strcoll) # sub-directories to traverse recursively after printing files subdirs = [] # print directory name print "%s:" % directory # note listdir() does not add "." and ".." so we must do this manually printInfo(os.path.join(directory, "."), ".") # print info of this directory printInfo(os.path.join(directory, ".."), "..") # and it's parent # print files and collect any sub-directories for filetitle in files: filename = os.path.join(directory, filetitle) # get full path name if printInfo(filename, filetitle): subdirs.append(filename) # file is a sub-directory # print files in each sub-directory for dirpath in subdirs: print # newline printDir(dirpath) #----------------------------------------------------------------------------- # process command line input def main(argv = None): if argv is None: # default value for argv argv = sys.argv # trigger color support if available global colorful colorful = hasColors() if len(argv) == 1: # no arguments printDir(".") # print current dir else: printDir(argv[1]) # process remaining arguments too for arg in argv[2:]: print # newline printDir(arg) #----------------------------------------------------------------------------- if __name__ == "__main__": # the script is called directly by the interpreter sys.exit(main()) # call main and return exit code k