From: zy on
On Mar 7, 11:58 am, zy <zyc...(a)gmail.com> wrote:
> I have written a perl script to do this task.
> I think I can handle quotes correctly now, including those in
>   "pwd" ; ls
>
> but these still remains a problem:
> var=cmd;$var
> or
> alias var='cmd'

This script is structurally ill in my view, but works anyway,
disregarding the problems.

#!/usr/bin/perl
# list_external.pl: List external programmes that are possibly
executed by a given bash script.
# zy....(a)gmail.com (zy)
use strict;
use Switch;
use Set::Scalar;
our $DP=0;
my @list;
my $word="", my $is_function=0, my $is_case=0;
my $list=Set::Scalar->new;
my $keywords=Set::Scalar->new( qw( case do done elif else esac fi for
function if in select then until while time ));
my $builtins=Set::Scalar->new( qw(
alias bg bind break builtin cd command compgen complete continue
declare dirs disown echo enable eval exec exit export fc fg getopts
hash help history jobs kill let local logout popd printf pushd pwd
read readonly return set shift shopt source suspend test times trap
type typeset ulimit umask unalias unset wait) );
my $basics=Set::Scalar->new( qw( ) );
my $exclude=Set::Scalar->new;
$exclude= $basics + $builtins + $keywords;

my $functions=Set::Scalar->new;

sysopen(FILE , $ARGV[0], "r" ) or open(FILE, "<&=STDIN");

sub save
{
if( $word eq ""){ $is_function=0;return; }
my $ins= $is_function?$functions:$list;
$ins->insert($word);
# print '=====<<',$word,'>>=====';
$word=""; $is_function=0;
}

sub parse
{
# print "\n";
# $DP++;
# print "=<",$DP,"=";
my $delimiter=@_[0], my $skip=@_[1], my $init=@_[2];

my $q1=0, my $q2=0, my $sl=0;
my $dollar=0, my $comment=0, my $crop_word=1;
my $c, my $cc=undef;
while(defined($c=getc(FILE)))
{
# print "$c";
if ( $comment and $c ne "\n" ){next;}
if(not defined($cc) and $c eq '(' and $init eq '$(')
{ parse(')',1); }
if(defined($delimiter))
{
if( $c eq $delimiter and $cc ne '\\' ){
# print " ";
# print "=>",$DP,"=";
# $DP--;
# print "\n";
save();
return;
}
}
if($sl == 1)
{
$sl=0;
next;
}
# variables or cases
$c =~ /[(]/ && do { if($word ne ""){$is_function=1;}};
$c =~ /[=]/ && do { $word=""; $crop_word=0};
$c =~ /[)]/ && do { if($is_case == 1)
{$is_case=0;$crop_word=1;$word="";} };
$c !~ /[A-Za-z0-9_\-~.\/]/ && do {
if ( $word eq "if" )
{
$crop_word=1;$word="";
next; #while
}
if ( $word eq "." or $word eq "source" )
{
$crop_word=1;$word="";
next; #while
}
if ( $word eq "function" )
{
# print "FUNCTION";
$crop_word=1;$word="";$is_function=1;
next; #while
}
if ( $word eq "case" )
{
# print "CASE";
$crop_word=0;$word="";$is_case=5;
next; #while
}
if ( $word eq "esac" )
{
# print "ESAC";
$crop_word=0;$word="";$is_case=0;
next; #while
}
# e.g. A command quoted with " and head of line;
if ($word ne "" and not $is_case) { $crop_word=0;save(); }
};
switch($c)
{
case '\\' { $sl=1;last; }
case '#' { $comment=1;last; }
case ' ' {
# print ' ';
$dollar=0;
}
case ';' {
$is_case= $cc eq ';'? 1:0 ;
if ( $word ne "" ){
save();
}
if( not $q1 and not $q2 and not $is_case){
$crop_word=1;
}
last;
}
case "\n" {
# print "\n";
$dollar=0; $comment=0;
if($is_case != 0){$is_case=1;}
if ( $word ne "" ){
save();
}
if( not $q1 and not $q2){
$crop_word=1;
}
last;
}
case "'" {
if($q2 != 1){ $q1= $q1?0:1; }
last;
}
case '"' {
if($q1!=1){ $q2= $q2?0:1; }
last;
}
case '[' {
if( not $q1 && not $q2 ){
parse(']',1);
last;
}
}
case '$' {
$dollar=1;
last;
}
case '(' {
if($dollar == 1){
parse(')', 0, '$(');
# print 'returned;$q2=',$q2,"\n";
last;
}
if( $cc eq '('){ parse(')',1,'((');parse(')',1); }
}
case '{' {
if($dollar == 1){
parse('}',1);
last;
}
}
case '`' {
parse('`');
}
case /[|;]/ {
if( $q1 || $q2 ){ last; }
$crop_word=1;
}
case '&' {
if( $q1 || $q2 || $cc ne '&' ){ last; }
$crop_word=1;
}
case /[()\[\]\{\}]/ {
last;
}
else{
if($dollar==1){$dollar=2}
if(not $skip and not $dollar and not $comment){
# print $c;
if($crop_word && $c =~ /[A-Za-z0-9_\-~.\/]/ )
{$word=$word . $c; }
}
}

#switch
}
$cc=$c;
#while
}
save();
}

parse;
print $list->difference($exclude+$functions), "\n";
close(FILE);

From: bsh on

On Mar 6, 7:43 pm, zy <zyc...(a)gmail.com> wrote:
> > My *guess* is that the OP wants to create a list of programs ....
> Your guess is indeed right....
> Unfortunately, the problem of "CMD=pwd; $CMD" does exist....

There have been several toolsuites over the years
addressing this issue, usually in the context of
executable or script migration between Unix hosts.

Unfortunately, all of them are either currently
inaccessable or (probably) not pertainent to your
environment -- are you programming on a Solaris host?

The Solaris executable "scriptran", component of SLPT
(Solaris-Linux Porting Tools), addressed your concern
precisely. Others are "shanalyze" and "Linux-it".
Too bad, but they are probably too complex and broad
for what you are endeavoring to do.

Previous discussions of mine can be found in previous
posts:

"convert solaris to linux"
http://groups.google.com/group/comp.unix.shell/msg/99da9e2d6c2e79f6

"Converting from MKS Korn Shell to Linux"
http://groups.google.com/group/comp.unix.shell/msg/51ed6773be861c72

However, the only solution which has not been
discussed is the most obvious one! Use "truss"
(Use "strace" on Linux), and "grep" for keywords
(IIRC) "execve(" and (IIRC) "ENOENT" to find
those external calls which are not resolved.

The advantage of the above technique is that
calls obfusticated by shell semantics, including
variable substitution, will not be shrouded.

=Brian
From: zy on
On Mar 11, 7:50 am, bsh <brian_hi...(a)rocketmail.com> wrote:


> Unfortunately, all of them are either currently
> inaccessable or (probably) not pertainent to your
> environment -- are you programming on a Solaris host?
I write scripts on my Debian laptop, and upload it to another Debian.

> However, the only solution which has not been
> discussed is the most obvious one! Use "truss"
> (Use "strace" on Linux), and "grep" for keywords
> (IIRC) "execve(" and (IIRC) "ENOENT" to find
> those external calls which are not resolved.
The dynamic approaches are not very suitable to my situation.
My scripts works over the network and act differently according to
received data from some servers. It is hard to transverse through all
the routes.
And generally, some code is not meant to be executed at arbitary time.

I would be very glad if there are some robust shell syntax analyzers
available besides the interpreters, though they are not likely to be
able to solve the issue of substituted commands.
From: bsh on
On Mar 10, 9:07 pm, zy <zyc...(a)gmail.com> wrote:
> On Mar 11, 7:50 am, bsh <brian_hi...(a)rocketmail.com> wrote:
>
> > Unfortunately, all of them are either currently
> > inaccessable or (probably) not pertainent to your
> > environment -- are you programming on a Solaris host?
>
> I write scripts on my Debian laptop, and upload it to another Debian.
>
> > However, the only solution which has not been
> > discussed is the most obvious one! Use "truss"
> > (Use "strace" on Linux), and "grep" for keywords
> > (IIRC) "execve(" and (IIRC) "ENOENT" to find
> > those external calls which are not resolved.
>
> The dynamic approaches are not very suitable to my situation.
> My scripts works over the network and act differently according to
> received data from some servers. It is hard to transverse through all
> the routes.
> And generally, some code is not meant to be executed at arbitary time.
>
> I would be very glad if there are some robust shell syntax analyzers
> available besides the interpreters, though they are not likely to be
> able to solve the issue of substituted commands.

Hmmm. This is considerably tougher.

Amusing, _I_ am that author of a robust shell syntax parser /
analyzer, as I contritely make C.U.S. periodically aware, as
it is stuck on a dead workstation.

I can now only suggest downloading and experimenting with
the bash debugger, bashdb, at:

"bashdb.bash": bash(1) debugger
http://sf.net/projects/bashdb/
http://bashdb.sf.net/

I have used the standalone ksh debugger script, precursor to bashdb,
which in bash I also understand is built into version 3 and newer.
Beyond the aforementioned longstanding project of a k/sh IDE
including debugger suite and parser, I have no experience with
this utility. I'm thinking that your script can be modified to
"automagically" invoke the debugger, and trace data be written
to a logfile, for your purposes.

=Brian

From: Mark Hobley on
zy <zyconf(a)gmail.com> wrote:
> I would be very glad if there are some robust shell syntax analyzers
> available besides the interpreters, though they are not likely to be
> able to solve the issue of substituted commands.

If you know perl and want to attempt this, it would be cool to add a -r switch
to the checkbashisms tool to cause additional checks according to the
traditional restricted rsh shell (which does not allow external commands to be
executed).

ftp://markhobley.yi.org/devtools/checkbashisms/

My email is down at this time, but I can receive update submissions via the
comp.sources.unix newsgroup.

Mark.

--
Mark Hobley
Linux User: #370818 http://markhobley.yi.org/