This is a pretty basic question but I am having a hard time with it. I want to be able to get all of the folder information from a directy into a tab delim. text file. When I do something like this ls -ln > /tmp/tabfile.txt, the colums that would normally display to the console are not delimited in the file. Is there a way to delimit the information from ls so that I get one column with owner, then a tab then foldername etc....
If this is not the best way maybe there is another way to get the info I need. Here is the issue.
I have a folder with about 4000 sub folders. I need to get the owner UID and the folder name into two columns in a Database. So, if I could create a tab file with uid in one column and folder name in another it would be golden.
Thanks
mervTormel
04-05-2004, 04:37 PM
quick and dirty:
$ ls -ln | tr -s " " | tr " " ","
tr -s to squish spaces, then tr space to a comma. you could ^V^I to get a tab in there.
hmm, this is going to scupper filenames with spaces. hmm... perhaps a perl script that stats just the file's UID and name?
breen
04-05-2004, 06:34 PM
quick and dirty:
$ ls -ln | tr -s " " | tr " " ","
tr -s to squish spaces, then tr space to a comma. you could ^V^I to get a tab in there.
hmm, this is going to scupper filenames with spaces. hmm... perhaps a perl script that stats just the file's UID and name?
Also quick and dirty:
find -type d -print0 |xargs -0 ls -ldn |awk '{print $3, "," $9}'
Like Merv's, this is comma delimited.
Breen
acme.mail.order
04-05-2004, 06:39 PM
ls -ln | sed -e 's/\(^[^ ]*\) *\([[:digit:]]*\) \([[:digit:]]..\) *\([[:digit:]]*\) *\([[:digit:]]*\) *\([[:digit:]]* [[:alpha:]]*[[:space:]]*[0123456789:][^ ]*\) /\1,\2,\3,\4,\5,\6,/' | sed -e 's/ / /g'
remove the last "| sed -e 's/ / /g'" if you don't want double spaces (including those in filenames) squashed.
Write back if you need an explanation. regular expressions are "write-only"!
acme.mail.order
04-05-2004, 06:42 PM
Breen - you type faster than I can write sed code, but your solution doesn't work on my box - find: illegal option t|y|p|e. which version are you using?
huskerchad
04-05-2004, 07:46 PM
That find command needs the path, i.e. "find /path/to/search -type..." but since it uses awk, it is going to return only the part of the filename up to the first space (if there is one).
breen
04-06-2004, 10:13 AM
Breen - you type faster than I can write sed code, but your solution doesn't work on my box - find: illegal option t|y|p|e. which version are you using?
Blast and damnit. I was typing on a box that had gnu find. Doesn't work on the default BSD.
(Hardest thing about OSX for me is keeping those differences in mind. I should probably listen to my favorite sermon about working with the defaults of whichever distribution/version you're using.)
Sorry!
b.
hayne
04-06-2004, 12:01 PM
Here's a Perl script that does a tab-separated listing of a folder/directory.
You can customize it to output what you want by editing the last line
in the print_info function.
E.g.
print "$name\t$uid\n";
would print out just the filename and UID.
#!/usr/bin/perl -w
use strict;
# This script lists the files in the specified directory
# If no command-line argument, use the current directory
my $dirname = scalar(@ARGV) >= 1 ? $ARGV[0]: ".";
# function declarations
sub list_directory($);
MAIN:
{
list_directory($dirname);
}
exit;
#----- FUNCTIONS -----
sub printable($)
{
my ($str) = @_;
# replace anything other than normal characters with a question mark
$str =~ s/[^\w\d.\- ]/?/g;
return $str;
}
sub time_as_date($)
{
my ($time) = @_;
my $date = localtime($time);
return $date;
}
sub print_info($)
{
my ($filename) = @_;
use File::stat;
my $info = stat($filename)
or warn "Can't stat file $filename: $!\n" and return;
# see 'man stat' for the meaning of the following fields
my $name = printable($filename);
my $ino = $info->ino; # inode
my $mode = $info->mode; # permissions etc
my $nlink = $info->nlink; # number of links to this file/directory
my $uid = $info->uid; # user ID of owner
my $gid = $info->gid; # group ID
my $size = $info->size; # size in bytes
my $atime = $info->atime; # time of last access (seconds since epoch)
my $mtime = $info->mtime; # time of last data modification
my $ctime = $info->ctime; # time of last file status change
# discard file type info from 'mode' and put in usual numeric format
my $perms = sprintf("%04o", $mode & 07777);
# convert times (in seconds since the epoch) to date strings
my $adate = time_as_date($atime);
my $mdate = time_as_date($mtime);
my $cdate = time_as_date($ctime);
# print out the desired fields in tab-separated format
print "$name\t$uid\t$gid\t$perms\t$mdate\n";
}
sub list_directory($)
{
my ($dirname) = @_;
# open the directory and call 'print_info()' for each file/sub-directory
opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
while (defined(my $filename = readdir(DIR)))
{
next if $filename =~ /^\.\.?$/; # skip . and ..
print_info($filename);
}
closedir(DIR);
}