Perl command call check

N

neilsolent

Before calling a command with system() or with backticks, is there a
neat way to check that the executable exists in the path (i.e. like
the UNIX "which" command) ?

Seems a bit untidy to attempt to run the command blindly and then use
the return code / output to first check whether the command was even
found.

thanks,
Neil
 
T

Tad J McClellan

neilsolent said:
Before calling a command with system() or with backticks, is there a
neat way to check that the executable exists in the path (i.e. like
the UNIX "which" command) ?


It is a Really Good Idea to use a full pathspec for external
commands rather than relying on PATH.

If PATH=/opt/badbin:/bin and there is an "ls" in badbin/ then
system 'ls *'
will run badbin/ls whereas
system '/bin/ls *'
will run /bin/ls.

Seems a bit untidy to attempt to run the command blindly and then use
the return code / output to first check whether the command was even
found.

If you adopt the security measure suggested above then:

die "/bin/ls could not be executed" unless -x '/bin/ls';

:)
 
N

neilsolent

It is a Really Good Idea to use a full pathspec for external
commands rather than relying on PATH.

Thanks for you post.
I disagree - at least this depends on the context.
If I fix paths to executables - I seriously reduce the portability.
If I end up calling a bad version of a command - then the system was
in a bad state to start with!
I think it is a fair enough assumption that the PATH is setup
correctly and won't cause bad things to happen. If not - much more is
likely to break than just this script.
 
N

neilsolent

Before calling a command with system() or with backticks, is there a
File::Which. Note that this won't find shell builtins, even though you
can invoke them with system.

It is worth mentioning that there is a race condition between this check
and the actual invocation, and that trying something and letting it fail
is usually a better strategy than trying to second-guess the answer;
however, I'm pretty sure that all implementations of system that search
the PATH have the same race condition internally, so it doesn't matter
much in this case.

Thanks for that.
Hmm race condition - don't like the sound of that! I think you are
right - I will just submit the commands and work out what happened
after.
 
T

Tim McDaniel

It is a Really Good Idea to use a full pathspec for external
commands rather than relying on PATH.

If PATH=/opt/badbin:/bin and there is an "ls" in badbin/ then
system 'ls *'
will run badbin/ls whereas
system '/bin/ls *'
will run /bin/ls.

As another reply said, hard-coding paths is also a bad idea. On one
system I use, perl is in /usr/bin. On another, it is in /bin and
/usr/bin. On another, it is in /usr/local/bin -- and that's the one
system I have no control over, so I can't symlink on it. And I copy
my utility scripts to all systems that I use.

If someone sets up a path with their own version of a command that's
usually gotten from the system,

- there's often a good reason. I've written wrappers and put them in
~/bin to paper over differences in locations as above. I use my own
version of hostname that compensates somewhat for different syntaxes
and behaviors on different OSes.

- if their own version makes another program misbehave, it's their own
damned fault and they got what they deserved.
 
S

Skye Shaw!@#$

I will just submit the commands and work out what happened
after.

Well with system() or backticks, how do know if it's telling you that
the command doesn't exist vs. exit failure?

~ >uname
Linux
~ >perl -e'print(system("bass > /dev/null 2>&1")>>8)'
127
~ >grep '\<127\>' /usr/include/asm-generic/errno.h
#define EKEYEXPIRED 127 /* Key has expired */

Hum, not sure what that means, let’s try something familiar:

~ >perl -e'print(system("ls nope > /dev/null 2>&1")>>8)'
2
~ >grep '\<2\>' /usr/include/asm-generic/errno-base.h '
#define ENOENT 2 /* No such file or directory */

Ah ok. Let’s see what the exit value of an inaccessible command is on
Solaris?

~ >uname
SunOS
~ >perl -e'print(system("bass > /dev/null 2>&1")>>8)'
sh: bass: not found
1

I'd stick with the Which module.

-Skye
 
N

neilsolent

I will just submit the commands and work out what happened
Well with system() or backticks, how do know if it's telling you that
the command doesn't exist vs. exit failure?

I find $? (within the Perl process) gets set to -1, and $! is set to
something like "file not found".
Does your platform do something different ?
 
A

A. Sinan Unur

I find $? (within the Perl process) gets set to -1, and $! is set to
something like "file not found".
Does your platform do something different ?

The documentation for the system function explains:

You can check all the failure possibilities by inspecting $?
like this:

if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}

Alternatively you might inspect the value of
"${^CHILD_ERROR_NATIVE}" with the W*() calls of the POSIX
extension.

Read the rest of the documentation for potential pitfalls when the shell
is involved.

Sinan
--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
N

neilsolent

The documentation for the system function explains:

Read the manual eh ? Good idea :)

Thanks for the post - think that has cleared this thread up
I already discovered the common -1 code for $?, but it is useful to
see the official explanation.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top