sort ls output by users

8,053

Solution 1

Determining which column the owner name is in from a single ls -l output without knowing which is which is not possible. You could try to match the entries in each column with the passwd file, but there is no guarantee that you would not be matching the group column or the filename column both which could only contain names you find in /etc/passwd.

If you want to go with ls, you could run the program twice, once as ls -l and once as ls -g. The latter drops the owner so by matching lines based on the other information you would be able to determine the owner name without specification. This is however not an exercise I would be happy to do in a bash shell script.

Solution 2

With zsh, you can define sort orders and use it in globbing qualifiers like:

zmodload zsh/stat
uid() zstat -A REPLY +uid -- $REPLY

... *(no+uid)

(n for numerical order, o for order, +uid to order with the uid function). The idea is to have a function that takes a filename in $REPLY and returns something in $REPLY that zsh sorts on.

So, for instance with GNU ls:

ls -ldU -- *(no+uid)

With GNU only tools, the equivalent would be something like:

find . ! -name . -prune -printf '%U\t%p\0' |
  sort -zn |
  tr '\0\n' '\n\0' |
  cut -f2- |
  tr '\0\n' '\n\0' |
  xargs -r0 ls -ldU

Solution 3

Don't parse ls: use stat

stat -c "%U %n" -- * | sort

Solution 4

Since the OP doesn't stipulate particular portability requirements (other than for use in Bash), and since parsing ls seems to remain the popular approach, and since the stat-based solution doesn't seem to handle newlines in filenames any better (who puts newlines in filenames, anyway?), I'm going to throw in my own suggestion for the most elegant solution:

I believe the OP actually had almost the best answer. It just needs to be escaped to prevent unexpected behavior from aliasing (remember, this is a Bash-specific solution):

\ls -l | sort -k 3

18 characters, only requires ls and sort, and no loops. Elegant, easy to understand, and reliable.

Also, as Olivier pointed out in his answer, it may be desirable to limit sort to only the third column, rather than the whole line starting with that column:

\ls -l | sort -k 3,3

I will retract this answer if someone can find me an implementation of ls -l that doesn't contain the owner in the third column or a way to break this solution that doesn't break solutions given in other answers.

Solution 5

1) Determine which column is the name:

myls='ls -al'
echo '+' > /tmp/MYOWNFILE.$$  #so file will be of size 2, "+" and newline.
zeuser=$( $myls /tmp/MYOWNFILE.$$ | awk -v myname=$(whoami) '{ for (field=1;field<=NF;field++) { if ($field == myname) { print field ; break } } }' )
zesize=$( $myls /tmp/MYOWNFILE.$$ | awk '{ for (field=1;field<=NF;field++) { if ($field == 2) { print field ; break } } }' )
zename=$( $myls /tmp/MYOWNFILE.$$ | awk -v filename=/tmp/MYOWNFILE.$$ '{ for (field=1;field<=NF;field++) { if ($field == filename) { print field ; break } } }' )
rm /tmp/MYOWNFILE.$$

It put in variable zeuser the column showing the username
I also determine zesize=column holding the size, and zename=column holding the filename

I'll put the ls command in a variable, so the lines determining the column are using the actual command used later on (in case you change it and it changes the column(s) listed)

2) use sort to sort on that column:

$myls | sort -k${zeuser},${zeuser}  #sort ONLY on column of usernames (see last example for bad alternative)
$myls | sort -k${zeuser},${zeuser} -k${zename},${zename} #sort on user, and then on filename
$myls | sort -k${zeuser},${zeuser} -k${zesize},${zesize}nr #sort on user, 
                            #  and then on size 
                            #modifiers: 'n'=order Numerically (and not alphabetically), 
                            #           'r'=Reverse order
$myls | sort -k${zeuser}    #sort STARTING FROM user column, which is probably not what you want!
                     #indeed the next column is probably the group, then the size...
                     #It will be sorting in a not so usefull way (especially as the
                     #  size will be sorted alphabetically instead of numerically)
Share:
8,053

Related videos on Youtube

erch
Author by

erch

my about me is blink at the moment

Updated on September 18, 2022

Comments

  • erch
    erch over 1 year

    On Linux, is there a way to sort ls output by users? What I try to achieve is something like this:

    user_a   file1
    user_a   file2
    user_b   another_file
    user_c   this_file
    user_c   that_file
    user_d   file3

    I am aware that a listing like this would also contain file size, permissions etc. – my main concern is the sorting by users. Would be quite handy, wouln't it

    So far I found ls -l | sort -k 3 to sort by column three which [if using ls -l] contains the file owner [thus sort -k 4 to sort by group].

    BUT what if the file owner isn't in row three? Is there another way to achieve this, independent from the number of the column?


    Update: I forgot to mention that I work in BASH and try to stick to it for quite a while from here on so things don't become more complicated.

    • Admin
      Admin about 11 years
      BUT what if the file owner isn't in row three? where else it can be?
    • Admin
      Admin about 11 years
      @nylon100: a lot of unixes (and even on the same one, different version of the OS or the ls command) will act differently with many commands. It's good to be extra careful about portability, as a simple script here would be dangerous there (ex: if you rely on column 3 to find which files to delete, and it happens it contains something else than the owner's name, you may end up deleting every files you wanted to keep...)
    • Admin
      Admin about 11 years
      @depquid : of course ^^ But they also could just have an alias, or a function, changing the output (ex: adding the inode in front) ^^ (but you can use "command ls" instead of "ls" in bash to bypass both)
  • erch
    erch about 11 years
    I forgot to mention that I work in BASH [and updated my question]. I try to stick to it for quite a while from here on so things don't become more complicated. [I love the choices I have with Linux and don't want to be ungrateful, but for a newb all this possibilities can become to much.]
  • erch
    erch about 11 years
    'Matching with the passwd file sounds great &ndash; but how to achieve this?
  • Anthon
    Anthon about 11 years
    @cellar.dweller if that would work I would do it in my programming language of choice, but with some output you can never be sure which column are the owner names and not filenames or groupnames. That makes the effort futile IMHO. Better start with the uid info as I indicated in my comment on your question.
  • erch
    erch about 11 years
    There might come a time when I would be able to code in C but for the moment I am lucky to get along witch basic commands and options, but thanks :)
  • Anthon
    Anthon about 11 years
    Most of the C library functions are also available in in some form in Python, Ruby or Perl. Those are somewhat more forgiving than C, to do these kind of things.
  • Stéphane Chazelas
    Stéphane Chazelas about 11 years
    Note that there are several implementations of stat. That one is the GNU one.
  • Olivier Dulac
    Olivier Dulac about 11 years
    the awk are done for clarity, not tersity... I'm sure a guru out there will propose a much neater/shorter way
  • depquid
    depquid about 11 years
    I get this error at step #2: sort: open failed: 4,3: No such file or directory The value of $zeuser is 3 4 The zeuser assignment doesn't handle when the owner and group names are the same?
  • Stéphane Chazelas
    Stéphane Chazelas about 11 years
    On many systems, the group of ~ has the same name as the user name, so, $field would then be 3 4 there.
  • Olivier Dulac
    Olivier Dulac about 11 years
    @depquid: I don't understand: my 1) part take care of finding the columns using the myls command. Assign myls=the_command_you'll_actually_use and it will be determining the columns for that actual command (be it alias or anything) and then the sorts will be using those found values.
  • Olivier Dulac
    Olivier Dulac about 11 years
    @depquid: I edited to break as soon as a match occurs (but if you need the group, it will get a bit more difficult, where you'll need to take the last (=1st if only 1 number returned, or 2nd if 2 number returned in case user=group))
  • erch
    erch about 11 years
    Forgiving is nice for the Pro's who might have overseen something [oopsie!] but did a good job for 99% of what they did OR ended up giving their best trying to give 99%. But then I welcome 'not forgiving' because if IT is based on math there should be 'right' or 'wrong' and as little as possible in between. I accept strict rules as long as they are there to work as properly as one is able to do. Everything else is confusing - especially for Newbs. It might just be me...
  • Drake Clarris
    Drake Clarris about 11 years
    Well it was a quick and dirty solution - so often what I do in linux when tackling a solution like this. I didn't think about the group - A break could be added to stop once the first matching field is found (which should be the user), and escaped the ls to avoid alias problems. Still not perfect, but meh, Works on My Machine©
  • Lri
    Lri about 11 years
    OS X's stat uses -f instead of -c and it only supports %u (UID) and not %U (username).
  • depquid
    depquid about 11 years
    ls -l | sort -k 3 also "Works on My Machine©", but the OP was looking for a solution that was more robust/portable than that.
  • depquid
    depquid about 11 years
    @LauriRanta stat -f "%Su %N" -- * | sort should work on OS X and *BSD.
  • depquid
    depquid about 11 years
    @Glenn Why is stat better in this case? In my tests, it still doesn't handle newlines in filenames well.
  • depquid
    depquid about 11 years
    Sorry, I missed the significance of the edit where you added $myls.
  • Olivier Dulac
    Olivier Dulac about 11 years
    @depquid: no problem ^^ it happens (and I tend to edit a lot, as I throw things out before actually trying them...).
  • Angel Todorov
    Angel Todorov about 11 years
    newlines in filenames is really a pathological edge case: no line-oriented tools will be able to handle that. stat is not really safer here, but it does provide the (apparently) desired output. Also, since it's inherently difficult to parse the filename from ls -l output, I'm showing a better technique. Stephane's answer demonstrates a safe way using the zero-byte as a delimiter.