Question

I'm trying to sort the output from ls. The order that I'm going for is this:

  • any directories with names that begin with _
  • any directories with names that begin with +
  • all soft links (which may include some dot files)
  • all remaining .files
  • all remaining .directories
  • everything else

Everything is sorted alphabetically within these 'sublists'. At the moment I'm using the find command a number of times to find files meeting the criteria above. Following that I pipe the output from find to sort and then pass the entire sorted list to ls:

#!/bin/bash

find1=`find . -maxdepth 1 -name "_*" -type d -printf "%f\n" | sort`
find2=`find . -maxdepth 1 -name "+*" -type d -printf "%f\n" | sort`
find3=`find . -maxdepth 1 -type l -printf "%f\n" | sort`
find4=`find . -maxdepth 1 -name ".*" -type f -printf "%f\n" | sort`
find5=`find . -maxdepth 1 \( ! -name "."  \) -name ".*" -type d -printf "%f\n" | sort`
find6=`find . -maxdepth 1 \( ! -name "_*" \) \( ! -name "+*" \) \( ! -name ".*" \) \( ! -type l \) -printf "%f\n"`
find="$find1 $find2 $find3 $find4 $find5 $find6"
ls -dfhlF --color=auto $find

This doesn't handle any names that contain spaces, and overall seems a bit excessive. I'm sure there is a better way to do this. Any ideas?

Was it helpful?

Solution

Will this work for you? It prints the files in the order you specified, but it won't print them in color. In order to do that, you'd need to strip the ANSI codes from the names before pattern-matching them. As it is, it will handle filenames with embedded spaces, but not horribly pathological names, like those with embedded newlines or control characters.

I think the awk script is fairly self-explanatory, but let me know if you'd like clarification. The BEGIN line is processed before the ls output starts, and the END line is processed after all the output is consumed. The other lines start with an optional condition, followed by a sequence of commands enclosed in curly brackets. The commands are executed on (only) those lines that match the condition.

ls -ahlF --color=none | awk '
  BEGIN { name_col = 45 }
  { name = substr($0, name_col) }
  name == "" { next }
  /^d/ && substr(name, 1, 1) == "_" { under_dirs = under_dirs $0 "\n"; next }
  /^d/ && substr(name, 1, 1) == "+" { plus_dirs = plus_dirs $0 "\n"; next }
  /^l/ { links = links $0 "\n"; next }
  /^[^d]/ && substr(name, 1, 1) == "." { dot_files = dot_files $0 "\n"; next }
  /^d/ && substr(name, 1, 1) == "." { dot_dirs = dot_dirs $0 "\n"; next }
  { others = others $0 "\n" }
  END { print under_dirs plus_dirs links dot_files dot_dirs others }
'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top