Go Back   The macosxhints Forums > OS X Help Requests > UNIX - General



Reply
 
Thread Tools Rating: Thread Rating: 19 votes, 5.00 average. Display Modes
Old 08-11-2002, 12:16 AM   #1
pmccann
Major Leaguer
 
Join Date: Jan 2002
Location: Adelaide, South Australia
Posts: 470
Command line fun

OK, I'm obviously a bit bored at the moment, so I dusted off an old script that I had lying around and cleaned it up a bit. [If anyone has a copy of the old version, please trash it; this one's far sounder.] It's modelled on an old utility that used to run on some SunOS machine, but ceased working when my ex-workplace upgraded to Solaris some time back. Someone who had grown reliant on this executable wanted it back, so I thought it would be fun to write it in perl. Hmm, so what *is* it? The original was called "lc", and is a variant of "ls", except that it separates files from directories and displays the results "across" the page instead of in columns.

I'm a fan of the separation aspect, but the row-based display is a bit awkward to view, so I've written my replacement to do column-based output by default, with row-based output available via a flag. The other big thing I've added is case insensitive sorting (by default). I think this makes a lot of sense, particularly when used on a mac. Anyway, enough rambling: you should be able to just copy the script below (between the %%%%% lines), then open up a terminal window and enter

% cat > ~/bin/lc

[[Now type command-V to paste in the copied contents]]
[[Now hit return and then control-D]]

% chmod u+x !$
% rehash

And that should be it. Instant "lc" goodness. Enter "lc -h" for usage instructions. The defaults should work OK. I have a couple of aliases set up: nothing fancy, but in my .cshrc there's

alias lcd 'lc -d'
alias lcf 'lc -f'
alias lcl 'lc | less'

Cheers,
Paul

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#!/usr/bin/perl -w
use strict;
use Getopt::Std;
use vars qw($opt_f $opt_h $opt_d $opt_s $opt_r $opt_l);
my $screenwidth = 80; # adjust if necessary
my $dirs_topstring = "+----------------- Directories "; #adjust as desired!
my $files_topstring = "+--------------------- Files ";
getopts('dfshrl'); # These are the valid options: see help message
if (!($opt_f || $opt_d || $opt_h)){ $opt_f=1; $opt_d=1 };
# show both if neither option present (and it's not a help request)
warn <<HELP if $opt_h;

A bare "lc" will separate files and directories, and sort them in a
case insensitive manner down the screen (ie in columns). To sort case
sensitively, or to display results in rows, or to show just files or
just directories use the flags as outlined below.

Flags may be grouped together (so "lc -id" is the same as "lc -i -d")
--------------------------------------------------------------------------------
-d : Show directories
-f : Show files (note that a bare "lc" will show both)
-s : Sort case sensitively (eg "Lemon" before "apple")
-r : List the output in rows instead of columns
-h : Display this message
-l : Display link (@) and exec (*) status on files displayed

HELP
open LS,"ls -F|"; # pipe the output of ls -F to this handle
my @what = <LS>; # catch the output from the ls -F command
my @dirs = grep /\/$/,@what; # directories end with "/"
my @files = grep /[^\/]\n$/,@what; # the rest (incl. links)

if (@dirs && $opt_d){ # process dirs, if they exist and are requested
my @sdirs = map {substr $_,0,-2} @dirs; # kill / and newline at once
bannerprint($dirs_topstring);
displaylist(\@sdirs);
}

if (@files && $opt_f){ # show files, if they exist and are requested
chomp @files;
$opt_l or s/\*|\@$// foreach (@files); # remove exec/link status?
bannerprint($files_topstring);
displaylist(\@files);
}

### Subroutines used above ###
sub bannerprint{
my $starter = shift;
my $topstring = $starter.("-"x($screenwidth-length($starter)-1))."+\n";
print $topstring;
}

sub displaylist{
my $array_ref = shift;
my $disp_len = getlen($array_ref)+1;
my $num_disp_perline = int(80/${disp_len});
my @list = @{$array_ref};
@list = sort {lc($a) cmp lc($b)} @list unless $opt_s;
if ($opt_r){ # for some perverted reason they want rows... OK!!
my $j=0;
foreach (@list){
printf "%-${disp_len}s", $_; $j++;
print "\n" if $j % ${num_disp_perline} == 0;
}
print "\n";
}else{ # here's one revolting way to print out columns
my $length = @list;
my $numrows = int($length/$num_disp_perline);
$numrows++ if ($length/$num_disp_perline - $numrows);
# extra row if doesn't divide evenly (ie there's a remainder)
foreach my $i (1..$numrows){
my $j=0;
my @row = grep {$j++;($i-$j)%$numrows == 0} @list;
printf "%-${disp_len}s",$_ foreach @row;
print "\n";
}
}
}

sub getlen{
my $arr_ref = shift;
my $blen = 0; my $len = 0;
foreach (@{$arr_ref}){
$len = length($_);
$blen = $len if $len>$blen;
}
$blen++; # return one greater than the longest word
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pmccann is offline   Reply With Quote
Old 08-11-2002, 01:31 AM   #2
eagle_eyes
Triple-A Player
 
Join Date: Jan 2002
Posts: 116
This is all that I got when I tried running it...

Quote:
Can't find string terminator "HELP" anywhere before EOF at /bin/lc line 11.

eagle_eyes is offline   Reply With Quote
Old 08-11-2002, 01:44 AM   #3
mervTormel
League Commissioner
 
Join Date: Jan 2002
Posts: 5,536
holy schnikeys! hey paul. an excellent sample.

to get a copy/paste of this to run, you'll have to delete the space after the standalone HELP around line 27.
mervTormel is offline   Reply With Quote
Old 08-11-2002, 01:56 AM   #4
eagle_eyes
Triple-A Player
 
Join Date: Jan 2002
Posts: 116
Thanks merv!

Works like a charm! I like very much!
eagle_eyes is offline   Reply With Quote
Old 08-11-2002, 04:15 AM   #5
sao
Moderator
 
Join Date: Jan 2002
Location: Singapore
Posts: 4,237
pmccann,

The pirate from the southern seas throwing another "gem" to the multitude.

Paul, it works very well, thanks a lot!


Cheers...

PS: Could you guide me to 'update for iTunes3' the script you share with us at the end of this thread?:

http://forums.macosxhints.com/showth...n&pagenumber=1

Last edited by sao; 08-11-2002 at 05:24 AM.
sao is offline   Reply With Quote
Old 08-11-2002, 07:57 AM   #6
bluehz
MVP
 
Join Date: Jan 2002
Posts: 1,562
Thanks pmccann - works great!
bluehz is offline   Reply With Quote
Old 08-11-2002, 07:58 AM   #7
pmccann
Major Leaguer
 
Join Date: Jan 2002
Location: Adelaide, South Australia
Posts: 470
Hi again,

thanks for the pick-up Merv: seems to be a browser-dependent thing, as I *swear* I tested cut/paste with IE. Maybe I'm the only one still using this thing! Damn, damn, damn: just checked again and there's that extra space problem in IE, so I suck. Wacko stuff: it's not evident in the selection shadow in the browser window, but comes running out of hiding once you paste. Indeed, every line gets that "breathing space" at the end after pasting. (Maybe it's *only* IE that does this? Yes and no: just checked with Chimera, and it seems to highlight an extra space in the browser window, but then pastes without it. Sigh...)

The extra space thing does ring a bell though, --doubtless some other "heredoc" has triggered the difficulty-- so I'll have to watch that in the future.

sao, what's the problem with iTunes3? I don't have this beasty, and don't want to put my poor old modem through that particular hell, but if you want to send me (ie email) a (small) portion of the export file I'm willing to have a look. Oh yeah, someone has started a perl module to look directly at the itunes library files. Have a look at search.cpan.org if you're interested. Hey! It's the *brand new* search.cpan.org: very cool indeed. The itunes stuff is at:

http://search.cpan.org/author/BDFOY/...iTunes-0.5_01/

Cheers,
Paul
pmccann is offline   Reply With Quote
Old 08-11-2002, 08:44 AM   #8
eriklager
Triple-A Player
 
Join Date: Jan 2002
Location: Sweden
Posts: 122
pmccann,

Very nice script! I modified it a little to support the -a option (lists all files) and listing of other directories (like "lc /Users". Is it OK with you that I post it?

Erik
eriklager is offline   Reply With Quote
Old 08-11-2002, 08:59 AM   #9
pmccann
Major Leaguer
 
Join Date: Jan 2002
Location: Adelaide, South Australia
Posts: 470
Hi Erik,

Sure, do with it what you will. Sounds like things that I should have had in there from the start!

Cheers,
Paul
pmccann is offline   Reply With Quote
Old 08-11-2002, 11:02 AM   #10
eriklager
Triple-A Player
 
Join Date: Jan 2002
Location: Sweden
Posts: 122
Quote:
Originally posted by eriklager
pmccann,

Very nice script! I modified it a little to support the -a option (lists all files) and listing of other directories (like "lc /Users". Is it OK with you that I post it?

Erik

Here is the modified version:
Code:
[SIZE=small]#!/usr/bin/perl -w
use strict;
use Getopt::Std;
use vars qw($opt_a $opt_f $opt_h $opt_d $opt_s $opt_r $opt_l);
my $screenwidth = 80; # adjust if necessary
my $dirs_topstring = "+----------------- Directories "; #adjust as desired!
my $files_topstring = "+--------------------- Files ";
getopts('adfshrl'); # These are the valid options: see help message
if (!($opt_f || $opt_d || $opt_h)){ $opt_f=1; $opt_d=1 };
# show both if neither option present (and it's not a help request)
warn <<HELP and exit if $opt_h or $ARGV[1];
usage: lc [-adfsrhl] [directory]

A bare "lc" will separate files and directories, and sort them in a
case insensitive manner down the screen (ie in columns). To sort case
sensitively, or to display results in rows, or to show just files or
just directories use the flags as outlined below.

Flags may be grouped together (so "lc -ad" is the same as "lc -a -d")
--------------------------------------------------------------------------------
-a : Include directory entries whose names begin with a dot (.)
-d : Show directories
-f : Show files (note that a bare "lc" will show both)
-s : Sort case sensitively (eg "Lemon" before "apple")
-r : List the output in rows instead of columns
-h : Display this message
-l : Display link (@) and exec (*) status on files displayed

HELP

$ARGV[0] or $ARGV[0] = ".";
open LS,"ls -aF -- $ARGV[0]|"; # pipe the output of ls to this handle
my @what = <LS>; # catch the output from the ls -F command
$opt_a or @what = grep(!/^\./,@what); # filter out dot files?
my @dirs = grep /\/$/,@what; # directories end with "/"
my @files = grep /[^\/]\n$/,@what; # the rest (incl. links)

if (@dirs && $opt_d){ # process dirs, if they exist and are requested
my @sdirs = map {substr $_,0,-2} @dirs; # kill / and newline at once
bannerprint($dirs_topstring);
displaylist(\@sdirs);
}

if (@files && $opt_f){ # show files, if they exist and are requested
chomp @files;
$opt_l or s/\*|\@$// foreach (@files); # remove exec/link status?
bannerprint($files_topstring);
displaylist(\@files);
}

### Subroutines used above ###
sub bannerprint{
my $starter = shift;
my $topstring = $starter.("-"x($screenwidth-length($starter)-1))."+\n";
print $topstring;
}

sub displaylist{
my $array_ref = shift;
my $disp_len = getlen($array_ref)+1;
my $num_disp_perline = int(80/${disp_len});
my @list = @{$array_ref};
@list = sort {lc($a) cmp lc($b)} @list unless $opt_s;
if ($opt_r){ # for some perverted reason they want rows... OK!!
my $j=0;
foreach (@list){
printf "%-${disp_len}s", $_; $j++;
print "\n" if $j % ${num_disp_perline} == 0;
}
print "\n";
}else{ # here's one revolting way to print out columns
my $length = @list;
my $numrows = int($length/$num_disp_perline);
$numrows++ if ($length/$num_disp_perline - $numrows);
# extra row if doesn't divide evenly (ie there's a remainder)
foreach my $i (1..$numrows){
my $j=0;
my @row = grep {$j++;($i-$j)%$numrows == 0} @list;
printf "%-${disp_len}s",$_ foreach @row;
print "\n";
}
}
}

sub getlen{
my $arr_ref = shift;
my $blen = 0; my $len = 0;
foreach (@{$arr_ref}){
$len = length($_);
$blen = $len if $len>$blen;
}
$blen++; # return one greater than the longest word
}[/SIZE]
Edit: corrected a bug.

Erik

Last edited by eriklager; 08-11-2002 at 05:15 PM.
eriklager is offline   Reply With Quote
Old 08-11-2002, 11:12 AM   #11
vickishome
MVP
 
Join Date: Jul 2002
Location: Texas
Posts: 1,075
Newbie raises hand from the back of the room...

Unix beginner here...

% cat > ~/bin/lc returns /Users/vicki/bin/lc: No such file or directory.

I know how to create the dirs, but I don't know if I should because my perl scripts are in my /u/web/vickis/local-cgi/ subdir (path matches my online webhost).

I know how to create the file in my local-cgi dir and chmod it.

What I don't know is:

1) I have my httpd.conf set up to use the extension .pl for my scripts. Do I name the file lc.pl?

2) How do I execute the script from the terminal? And how do I add my local-cgi dir to <insert whatever kind of> path to make it executable no matter what dir I'm in while in the terminal?

Or in other words... can someone take me from what I know to what I need to know to run the lc script while in any subdir in the terminal? All I know is to plop scripts with the extension of .pl into my (/u/web/vickis/local-cgi/) dir and exectute them from my browser (http://localhost/cgi-local/lc.pl). I don't think that's the intended usage of lc.
__________________
Vicki
• 15" MacBook Pro 2.66GHz i7, Mavericks 10.9.1, 8GB RAM
• iPad 4G WiFi 64GB
• iPhone 5 64GB
• 15" MacBook Pro 2.4GHz, Tiger 10.4, 4GB RAM
• G5 Dual 2GHz, Panther 10.3, 1.5GB RAM
• G4 Dual 1GHz, Tiger 10.4, 1.5GB RAM

Using Macs since 1986!
vickishome is offline   Reply With Quote
Old 08-11-2002, 11:14 AM   #12
vickishome
MVP
 
Join Date: Jul 2002
Location: Texas
Posts: 1,075
On second thought... I'd really prefer to have two subdirs in which I can execute perl scripts. I'd like to have (1) for my website scripts and (2) for my own personal use on my Mac. Can I do this? If so, how?
__________________
Vicki
• 15" MacBook Pro 2.66GHz i7, Mavericks 10.9.1, 8GB RAM
• iPad 4G WiFi 64GB
• iPhone 5 64GB
• 15" MacBook Pro 2.4GHz, Tiger 10.4, 4GB RAM
• G5 Dual 2GHz, Panther 10.3, 1.5GB RAM
• G4 Dual 1GHz, Tiger 10.4, 1.5GB RAM

Using Macs since 1986!
vickishome is offline   Reply With Quote
Old 08-11-2002, 11:24 AM   #13
eriklager
Triple-A Player
 
Join Date: Jan 2002
Location: Sweden
Posts: 122
Quote:
Originally posted by vickishome
On second thought... I'd really prefer to have two subdirs in which I can execute perl scripts. I'd like to have (1) for my website scripts and (2) for my own personal use on my Mac. Can I do this? If so, how?

Yes, just place it in the ~/bin directory and type rehash like Paul instructed. This will allow you to type it's name directly in a Terminal window to run it. This perl script has nothing to do with cgi scripts or web sites, and should not be placed in the apache cgi dir.

Edit: The reason Paul's intructions didn't work is that you don't have a ~/bin directory. Just create it and you will not get that error message.

Erik

Last edited by eriklager; 08-11-2002 at 11:29 AM.
eriklager is offline   Reply With Quote
Old 08-11-2002, 12:24 PM   #14
vickishome
MVP
 
Join Date: Jul 2002
Location: Texas
Posts: 1,075
Thanks, Erik! I got it to work.

But why is it not showing the file, dbz118a.jpg?

Output I receive using my ls2 (an ls modified alias):
Code:
[11:20am] [vicki] [~/Pictures] Exit, and we all die: % ls2
total 124
-rw-r--r--   1 vicki    staff           0 Jul 19 17:07 Icon?
drwxrw-rw-   8 vicki    admin         264 Aug 10 20:38 My Pictures/
drwxr-xr-x  43 vicki    staff        1418 Aug 10 20:38 My Screen Saver Pics/
drwxrw-rw-  10 vicki    admin         296 Aug 10 20:38 Pictures of my G3/
-rw-r--r--   1 vicki    staff       51003 Aug 11 10:37 dbz118a.jpg
drwxr-xr-x  12 vicki    staff         364 Aug 10 20:38 iPhoto Library/
But using lc, dbz118a.jpg is missing:
Code:
[11:20am] [vicki] [~/Pictures] Exit, and we all die: % lc 
+----------------- Directories ------------------------------------------------+
iPhoto Library       My Screen Saver Pics 
My Pictures          Pictures of my G3    
+--------------------- Files --------------------------------------------------+
       .jpg Icon
[11:20am] [vicki] [~/Pictures] Exit, and we all die: %
I know, I ask too many questions.

Edited to add: I also don't understand the Icon? reference. Here's what the Finder shows in that dir:
Code:
dbz118a.jpg
iPhoto Library
My Pictures
My Screen Saver Pics
Pictures of my G3
__________________
Vicki
• 15" MacBook Pro 2.66GHz i7, Mavericks 10.9.1, 8GB RAM
• iPad 4G WiFi 64GB
• iPhone 5 64GB
• 15" MacBook Pro 2.4GHz, Tiger 10.4, 4GB RAM
• G5 Dual 2GHz, Panther 10.3, 1.5GB RAM
• G4 Dual 1GHz, Tiger 10.4, 1.5GB RAM

Using Macs since 1986!

Last edited by vickishome; 08-11-2002 at 12:27 PM.
vickishome is offline   Reply With Quote
Old 08-11-2002, 12:30 PM   #15
mervTormel
League Commissioner
 
Join Date: Jan 2002
Posts: 5,536
Quote:
But why is it not showing the file, dbz118a.jpg?

i think the Icon^M is doing some funny terminal stuff that masks the file.

rm Icon[tab-completion]
mervTormel is offline   Reply With Quote
Old 08-11-2002, 12:36 PM   #16
vickishome
MVP
 
Join Date: Jul 2002
Location: Texas
Posts: 1,075
Thanks, Merv! That did the trick. lc is working correctly now.

Although I remain puzzled as to what that Icon^M file was and how it got there. I wonder how many other Icon^M files I might have hanging around? I wish I had tried locate before blowing that file away so I could see if locate could find those type of files for me.
__________________
Vicki
• 15" MacBook Pro 2.66GHz i7, Mavericks 10.9.1, 8GB RAM
• iPad 4G WiFi 64GB
• iPhone 5 64GB
• 15" MacBook Pro 2.4GHz, Tiger 10.4, 4GB RAM
• G5 Dual 2GHz, Panther 10.3, 1.5GB RAM
• G4 Dual 1GHz, Tiger 10.4, 1.5GB RAM

Using Macs since 1986!
vickishome is offline   Reply With Quote
Old 08-11-2002, 12:49 PM   #17
mervTormel
League Commissioner
 
Join Date: Jan 2002
Posts: 5,536
lc worked correctly before. it is the terminal handling of control chars that is problematic.
Quote:
I wish I had tried locate before blowing that file away so I could see if locate could find those type of files for me.

well, you can still look for them. it's more the carraige return char ^M than just the Icon file. i think the Icon^M file is an OS9 custom icon...
Code:
% locate \* | grep ^V^M | less
that's grep control-V control-M

the above is "list all files from the locate database, look for occurrences of control-M, pipe to less so that they're highlighted."

entering control-V escapes the next character to be a control char, in this case control-M
mervTormel is offline   Reply With Quote
Old 08-11-2002, 04:04 PM   #18
sao
Moderator
 
Join Date: Jan 2002
Location: Singapore
Posts: 4,237
eriklager,

Thanks, the modified script works well.


pmccann,

Problem solved.

iTunes 3 added the Composer, Disc Number, Disc Count, Date Modified, Play Count, Last Played, and My Rating fields to the Library.export file now called Library.text.

I just changed the numbers of the chunks of information in:

my ($artist,$album,$song,$time,$track)=(split "\t",$_)[1,2,0,5,6];

and it works very well again. Thanks.

Cheers...
sao is offline   Reply With Quote
Old 08-11-2002, 04:32 PM   #19
rusto
MVP
 
Join Date: Jan 2002
Location: Boston, MA
Posts: 1,489
one more tweak...maybe?

I've gotten used to having my directories in color using the --color=always switch with ls (I have an alias for it), adding it to the script like this:

Code:
open LS,"ls -aF --color=always -- $ARGV[0]|"; # pipe the output of ls to this ha
ndle
mucks things up a bit, is there way to do it?

EDIT: For that matter, it would be neat if the category headers matched the color of their contents.

__________________
:: 3.4GHz Core i7 iMac 4GB RAM :: Black MacBook SR :: 10.7.2 :: iPhone 4 / iOS 5 ::
rusto is offline   Reply With Quote
Old 08-11-2002, 05:14 PM   #20
eriklager
Triple-A Player
 
Join Date: Jan 2002
Location: Sweden
Posts: 122
I detected a bug in the modified version: I had put a colon on line 8, after adfshrl. The colon makes the script expect an argument to the l option.

I'll edit my previos post to correct the problem.

Erik
eriklager is offline   Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



All times are GMT -5. The time now is 05:36 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.