#!/usr/bin/python # Python 2 or 3 compatible. """ This command drives ls(1) but only directories are listed, files are ignored. Option processing is as in GNU ls(1). Current BUGS or limitations (I don't have the motivation to fix these): - ls(1) options taking arguments must be specified in their long form - -a behavior is incorrect, it does what -A or --almost-all should do. The second one could be easily fixed. The first could only be fixed if all of ls options were explicitly made known to this program. Example usages: list directories in the current directory: lsd list directories in home directory and /proc lsd ~ /proc list all directories in home directory and / with long listing and nice units lsd -lah ~ / list all directories in -dirname: lsd -a -- -dirname """ # Iain Murray, March 2007. Tweaks June 2012. import os, re, sys def hack_getopts_and_files(): """ Gets options and files from command line. Does not use getopt module, because that needs you to know what options you want. I'm generically passing them on to other programs and letting them throw errors if they don't like them. The problem is that you can not use short-style options that take arguments. This code will think the option is a filename. The POSIXLY_CORRECT environment variable is respected as by the getopt module and getopt(1). Usage: opts, files = hack_getopts_and_files() """ if "POSIXLY_CORRECT" in os.environ: gnu_behaviour=False else: gnu_behaviour=True opts=[] files=[] had_non_option=False had_breaker=False for str in sys.argv[1:]: if gnu_behaviour and (not had_breaker) and str=='--': had_breaker=True continue if str[0]!='-': had_non_option=True files.append(str) else: trad_not_option=((not gnu_behaviour) and had_non_option) gnu_not_option=(gnu_behaviour and had_breaker) if trad_not_option or gnu_not_option: files.append(str) else: opts.append(str) return opts, files opts, dirs = hack_getopts_and_files() if len(dirs)==0: dirs=['.'] combined_opts=' '.join(opts) # TODO should (strictly) distinguish -a and -A, but I don't care allpat=re.compile(r'^-[a-zA-Z0-9]*[aA][a-zA-Z0-9]*$') hidden_short_opt=len([x for x in opts if re.match(allpat,x)]) > 0 show_hidden=hidden_short_opt or ('--all' in opts) or ('--almost-all' in opts) startdir=os.getcwd() first=True for dir in dirs: os.chdir(startdir) try: os.chdir(dir) except: print(sys.argv[0] + ": Can not change into", dir) continue if len(dirs)>1: if not first: print() else: first=False print(dir + ':') for root, subdirs, files in os.walk('.'): if not show_hidden: subdirs=[x for x in subdirs if x[0]!='.'] os.system(r'ls -d --color=auto ' + combined_opts + ' -- ' + ' '.join(map(re.escape,subdirs))) break