|
|
#1 |
|
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 } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
|
|
|
#2 | |||||||||||||||||||
|
Triple-A Player
Join Date: Jan 2002
Posts: 116
|
This is all that I got when I tried running it...
|
|||||||||||||||||||
|
|
|
|
|
#3 |
|
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. |
|
|
|
|
|
#4 |
|
Triple-A Player
Join Date: Jan 2002
Posts: 116
|
Thanks merv!
Works like a charm! I like very much! |
|
|
|
|
|
#5 |
|
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. |
|
|
|
|
|
#6 |
|
MVP
Join Date: Jan 2002
Posts: 1,562
|
Thanks pmccann - works great!
|
|
|
|
|
|
#7 |
|
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 |
|
|
|
|
|
#8 |
|
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 |
|
|
|
|
|
#9 |
|
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 |
|
|
|
|
|
#10 | |||||||||||||||||||
|
Triple-A Player
Join Date: Jan 2002
Location: Sweden
Posts: 122
|
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]
Erik Last edited by eriklager; 08-11-2002 at 05:15 PM. |
|||||||||||||||||||
|
|
|
|
|
#11 |
|
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! |
|
|
|
|
|
#12 |
|
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! |
|
|
|
|
|
#13 | |||||||||||||||||||
|
Triple-A Player
Join Date: Jan 2002
Location: Sweden
Posts: 122
|
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. |
|||||||||||||||||||
|
|
|
|
|
#14 |
|
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/ 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: %
![]() 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. |
|
|
|
|
|
#15 | |||||||||||||||||||
|
League Commissioner
Join Date: Jan 2002
Posts: 5,536
|
i think the Icon^M is doing some funny terminal stuff that masks the file. rm Icon[tab-completion] |
|||||||||||||||||||
|
|
|
|
|
#16 |
|
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! |
|
|
|
|
|
#17 | |||||||||||||||||||
|
League Commissioner
Join Date: Jan 2002
Posts: 5,536
|
lc worked correctly before. it is the terminal handling of control chars that is problematic.
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 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 |
|||||||||||||||||||
|
|
|
|
|
#18 |
|
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... |
|
|
|
|
|
#19 |
|
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 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 :: |
|
|
|
|
|
#20 |
|
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
|
|
|
|
![]() |
|
|