29

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.

8 Answers 8

25

How about this:

find . -exec ls -dl \{\} \; | awk '{print $3, $4, $9}'
5
  • 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
    Commented Feb 2, 2009 at 16:42
  • 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.. Commented Feb 2, 2009 at 17:11
  • Or try one of the Perl solutions suggested by slim or Chris. Commented Feb 2, 2009 at 17:32
  • Spaces in the path? I thought that this question was tagged "linux"
    – Bruno9779
    Commented Nov 18, 2013 at 12:49
  • @Bruno9779 Spaces in the path are very much allowed in Linux -- try it -- touch 'my file with spaces'. Some people discourage it because it's easy to write shell scripts that choke on them -- but you can't prevent apps and users from creating filenames with spaces.
    – slim
    Commented Feb 10, 2016 at 10:09
21

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.

1
  • You can add the -a flag to show hidden files as well.
    – Enterprise
    Commented Apr 9, 2021 at 23:29
21

Works in Linux Debian:

find $PWD -type f     
4
  • 1
    Works flawlessly on Mac OS X Mountain Lion as well. Thanks.
    – pyronaur
    Commented Oct 5, 2013 at 8:13
  • 1
    If your current directory path contains spaces, surround $PWD with double quotes: find "$PWD" -type f Commented Nov 3, 2015 at 10:09
  • Just in case, it also works on Git Bash from GitHub for Windows. Commented Nov 3, 2015 at 10:11
  • Not only does this work with macOS out of the box, but it's also nice, short and memorable. Though I realise this solution doesn't list owner and group. For this you'd need one of the other more verbose solutions. Commented Sep 18, 2017 at 9:47
10

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.

1
  • 1
    BSD find indeed doesn't support -printf, but it's easy enough to install GNU find to ~/bin/gnufind ;) Commented Apr 8, 2009 at 19:17
8

You've already got an answer that works, but for reference you should be able to do this on the BSDs (I've tested it on a mac) :

find . -ls
4

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";
}
1

Simple way I found was this:

ls -lthr /path_to_directory/*

" * " - represents levels.

Ajiths-MBP:test ajith$ ls -lthr *
test2:
total 0
-rw-r--r--  1 ajith  staff     0B Oct 17 18:22 test2.txt

test3:
total 0
-rw-r--r--  1 ajith  staff     0B Oct 17 18:22 test3.txt

test1:
total 0
-rw-r--r--  1 ajith  staff     0B Oct 17 18:21 test1.txt
drwxr-xr-x  3 ajith  staff    96B Oct 17 18:22 test1_sub_dir


Ajiths-MBP:test ajith$ ls -lthr */*
-rw-r--r--  1 ajith  staff     0B Oct 17 18:21 test1/test1.txt
-rw-r--r--  1 ajith  staff     0B Oct 17 18:22 test2/test2.txt
-rw-r--r--  1 ajith  staff     0B Oct 17 18:22 test3/test3.txt

test1/test1_sub_dir:
total 0
-rw-r--r--  1 ajith  staff     0B Oct 17 18:22 test1_sub_file.txt
-4

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.)

1
  • Looks like the OP wanted an answer "[u]sing the tcsh shell on Free BSD".
    – David J.
    Commented Feb 20, 2017 at 4:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.