tags:

views:

1982

answers:

5

Using the tcsh shell on Free BSD, is there a way to recursively list all files and directories including the owner, group and relative path to the file?

ls -alR comes close, but it does not show the relative path in front of every file, it shows the path at the top of a grouping i.e.

owner% ls -alR
total 0
drwxr-xr-x   3 owner  group  102 Feb  1 10:50 .
drwx------+ 27 owner  group  918 Feb  1 10:49 ..
drwxr-xr-x   5 owner  group  170 Feb  1 10:50 subfolder

./subfolder:
total 16
drwxr-xr-x  5 owner  group   170 Feb  1 10:50 .
drwxr-xr-x  3 owner  group   102 Feb  1 10:50 ..
-rw-r--r--  1 owner  group     0 Feb  1 10:50 file1
-rw-r--r--  1 owner  group     0 Feb  1 10:50 file2

What I would like is output like:

owner group ./relative/path/to/file

The accepted answer to this question shows the relative path to a file, but does not show the owner and group.

+5  A: 

How about this:

find . -exec ls -dl \{\} \; | awk '{print $3, $4, $9}'
Alabaster Codify
It looks like this fails if there are any spaces in the path because awk will create another field.There any way to print from $9 to the end of the line?
Ben
Right you are! You *could* read the ls output into a function, shift your way though the arguments and use $@ to read "the rest of the line", but honestly, it's getting messy enough that I'd just write a little Python utility and do it The Right Way instead..
Alabaster Codify
Or try one of the Perl solutions suggested by slim or Chris.
Alabaster Codify
+6  A: 

find comes close:

find . -printf "%u %g %p\n"

There is also "%P", which removes the prefix from the filename, if you want the paths to be relative to the specified directory.

Note that this is GNU find, I don't know if the BSD find also supports -printf.

Torsten Marek
BSD find indeed doesn't support -printf, but it's easy enough to install GNU find to ~/bin/gnufind ;)
John Douthat
A: 

Use a shell script. Or a Perl script. Example Perl script (because it's easier for me to do):

#!/usr/bin/perl
use strict;
use warnings;
foreach(`find . -name \*`) {
  chomp;
  my $ls = `ls -l $_`;
  # an incomprehensible string of characters because it's Perl
  my($owner, $group) = /\S+\s+\S+\s+(\S+)\s+(\S)+/;
  printf("%-10s %-10s %s\n", $owner, $group, $_);
}

Perhaps a bit more verbose than the other answers, but should do the trick, and should save you having to remember what to type. (Code untested.)

Chris Lutz
+1  A: 

If you fancy using Perl don't use it as a wrapper around shell commands. Doing it in native Perl is faster, more portable, and more resilient. Plus it avoids ad-hoc regexes.

use File::Find;
use File::stat;

find (\&myList, ".");

sub myList {
   my $st = lstat($_) or die "No $file: $!";

   print  getgrnam($st->gid), " ", 
          getpwuid($st->uid), " ", 
          $File::Find::name, "\n";
}
slim
+2  A: 

Use tree. Few linux distributions install it by default (in these dark days of only GUIs :-), but it's always available in the standard repositories. It should be available for *BSD also, see http://mama.indstate.edu/users/ice/tree/

Use:

tree -p -u -g -f -i

or

tree -p -u -g -f

or check the man page for many other useful arguments.

Davide