Last active
August 29, 2015 14:00
-
-
Save AprilArcus/11124713 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# While GNU coreutil's ls is generally more featureful (including colorization | |
# based on file extensions, SI size formats, ISO date and time formats, | |
# semantic version sort, etc.), OS X's fork of FreeBSD ls allows viewing HFS+ | |
# extended attributes and access control lists through the -@ and -e flags, | |
# respectively. | |
# | |
# This script provides a shim to allow BSD ls to be invoked with GNU-style | |
# flags and .dircolor files, and a function that shadows ls, invoking coreutils | |
# ls by default but automatically switching to the shim when the -@ and/or -e | |
# flags are detected. | |
# | |
# Paste into your .bashrc after `eval $(dircolors ~/.dircolors)` and before | |
# any ls aliases. | |
if [[ "$OSTYPE" == darwin* ]]; then | |
# Look for an alternate ls in the $PATH | |
__bsd_ls=/bin/ls | |
__gnu_ls=$(which gls || which ls) | |
if [[ "$__gnu_ls" == "$__bsd_ls" ]]; then unset __gnu_ls; fi | |
if [[ "$__gnu_ls" ]]; then | |
if [[ ! $LS_COLORS ]]; then | |
eval $($(which gdircolors || which dircolors)) | |
fi | |
# Generate fallback colors for BSD ls | |
export LSCOLORS=$(python - <<'EOD' | |
import os, sys | |
types=['di','ln','so','pi','ex','bd','cd','su','sg','tw','ow'] | |
LS_COLORS=[e.split('=') for e in os.environ['LS_COLORS'].split(':') if len(e) > 0] | |
LS_COLORS={e[0]:e[1] for e in LS_COLORS if e[0]=='no' or e[0] in types} | |
LS_COLORS={k:[int(e) for e in v.split(';') if e] for k,v in LS_COLORS.items()} | |
LS_COLORS=[LS_COLORS.get('no',[])+LS_COLORS.get(k,[]) for k in types] | |
LSCOLORS=[] | |
for entry in LS_COLORS: | |
fgcodes=[code for code in entry if (code/10 == 3 or code/10 == 9)] | |
fgcolor=chr(fgcodes[-1]%10+ord('a')) if fgcodes else 'x' | |
brcodes=[code for code in entry if code in [0,1,2,21,22]] | |
bright=((brcodes and brcodes[-1]==1) or (fgcodes and fgcodes[-1]/10==9)) | |
fgcolor=fgcolor.upper() if bright else fgcolor | |
bgcodes=[code for code in entry if (code/10 == 4 or code/10 == 10)] | |
bgcolor=chr(bgcodes[-1]%10+ord('a')) if bgcodes else 'x' | |
LSCOLORS.append(fgcolor) | |
LSCOLORS.append(bgcolor) | |
sys.stdout.write(''.join(LSCOLORS)) | |
EOD | |
) | |
fi # [[ $LS_COLORS ]] | |
function __bsd_ls_shim { | |
# An abstraction layer to allow calling BSD ls with a subset | |
# of the GNU ls style parameters, and gracefully handle errors. | |
python - "$__bsd_ls" "$BASH_SOURCE" $FUNCNAME $@ <<'EOD' | |
# coding=UTF-8 | |
import os, sys, subprocess | |
__bsd_ls=sys.argv[1] | |
BASH_SOURCE=sys.argv[2] | |
FUNCNAME=sys.argv[3] | |
lookup = {'--all':'a','a':'a','--almost-all':'A','A':'A', | |
'--format=single-column':'1','1':'1','--format=vertical':'C', | |
'C':'C','--format=horizontal':'x','--format=across':'x','x':'x', | |
'--format=commas':'m','m':'m','--format=verbose':'l', | |
'--format=long':'l','l':'l','--sort=size':'S','S':'S', | |
'--sort=time':'t','t':'t','--reverse':'r','r':'r','--inode':'i', | |
'i':'i','--size':'s','s':'s','o':'o','g':'g', | |
'--numeric-uid-gid':'n','n':'n','--human-readable':'h','h':'h', | |
'--full-time':'T','--time=use':'u','--time=access':'u', | |
'--time=atime':'u','u':'u','--time=ctime':'c','--time=status':'c', | |
'c':'c','--indicator-style=classify':'F','--classify':'F','F':'F', | |
'--indicator-style=slash':'p','p':'p','--dereference':'L','L':'L', | |
'--dereference-command-line':'H','H':'H','--recursive':'R','R':'R', | |
'@':'@','e':'e','--hide-control-chars':'q','q':'q','--escape':'b', | |
'b':'b','--directory':'d','d':'d','f':'f'} | |
in_flags=[] | |
misc_args=[] | |
for arg in sys.argv[4:]: | |
if arg.startswith('--'): | |
in_flags.append(arg) | |
elif arg.startswith('-'): | |
in_flags.extend(list(arg)[1:]) | |
else: | |
misc_args.append(arg) | |
color_flag=None | |
out_flags=[] | |
err_flags=[] | |
for flag in in_flags: | |
if flag.startswith('--color'): | |
color_flag=flag | |
elif flag=='f': | |
color_flag=flag | |
out_flags = [flag for flag in out_flags | |
if flag not in ['l','s']]+['f'] | |
else: | |
try: | |
out_flags.append(lookup[flag]) | |
except: | |
err_flags.append(flag) | |
out_flags=['-'+''.join(out_flags)] if out_flags else [] | |
if err_flags: | |
err_flags=' '.join(['-'+flag if len(flag)==1 else flag for flag in err_flags]) | |
print('The following flags were not passed to '+__bsd_ls+' by '+FUNCNAME) | |
print('in '+BASH_SOURCE+': '+err_flags) | |
# The BSD ls flag -G is equivalent to GNU ls flag --color=auto, but we can | |
# more precisely match the GNU --color flag with environment variables. | |
if (not color_flag or | |
color_flag == 'f' or | |
color_flag == '--color=never' or | |
color_flag == '--color=no' or | |
color_flag == '--color=none'): | |
os.environ.pop('CLICOLOR',None) | |
os.environ.pop('CLICOLOR_FORCE',None) | |
elif (color_flag == '--color=auto' or | |
color_flag == '--color=tty' or | |
color_flag == '--color=if-tty'): | |
os.environ['CLICOLOR']='1' | |
os.environ.pop('CLICOLOR_FORCE',None) | |
elif (color_flag == '--color' or | |
color_flag == '--color=always' or | |
color_flag == '--color=yes' or | |
color_flag == '--color=force'): | |
os.environ['CLICOLOR']='1' | |
os.environ['CLICOLOR_FORCE']='1' | |
else: | |
print('error in '+BASH_SOURCE+' function '+FUNCNAME+':') | |
# This error message is copied verbatim from GNU ls | |
print('invalid argument ‘'+color_flag[8:]+'’ for ‘--color’') | |
print('Valid arguments are:') | |
print(' - ‘always’, ‘yes’, ‘force’') | |
print(' - ‘never’, ‘no’, ‘none’') | |
print(' - ‘auto’, ‘tty’, ‘if-tty’') | |
exit(1) | |
# subprocess.Popen() is safe against command injection when shell=False | |
exit(subprocess.Popen(args=[__bsd_ls]+out_flags+misc_args, | |
shell=False, | |
env=os.environ).wait()) | |
EOD | |
} | |
function ls { | |
# regex to match the -@ and -e parameters | |
if [[ ! "$__gnu_ls" || "$@" =~ (^|[[:space:]])-[[:alnum:]]*[@e] ]]; then | |
__bsd_ls_shim $@ | |
else | |
"$__gnu_ls" $@ | |
fi | |
} | |
fi # [[ $__gnu_ls ]] | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment