I want to check if a command exists on my machine (RedHat) inside a perl script.
Im trying to check if compgen -c
contains the desired command, but running it from inside a script just gives me an empty output. Other commands work fine.
example.pl:
my $x = `compgen -c`;
print $x;
# empty output
my $y = `ls -a`;
print $y;
# .
# ..
# example.pl
Are there possible solutions for this? Or is there a better way to check for commands on my machine?
CodePudding user response:
First, Perl runs external commands using /bin/sh
, which is nowadays a link to a shell that is a default-of-sorts on your system. Much of the time that is bash
, but not always; on RedHat it is.
Now this compgen
is a shell (bash) builtin. One way to see that is to run man compgen
(in bash) -- and the bash
manual pops up. Another way is type
as Dave shows.
But then this bash builtin can run only in an "interactive" shell. So you need
my @completions = qx(bash -i -c "compgen -c")
The quotes are needed since we are passing a command to a subshell that will be started.
Note that this way you don't catch any STDERR
out of those commands. That will come out on the terminal, and it can get missed that way. Or, you can redirect that stream inside your command, by adding 2>&1
at the end of it.
This is one of the reasons to use one of a number of good libraries for running and managing external commands instead of the builtin "backticks" (the qx I use above is an operator form of it.)
CodePudding user response:
It's because compgen
is a bash
built-in command, not an external command. And when you run a command using backticks, you get your system's default shell - which is probably going to be /bin/sh
, not bash
.
The solution is to explicitly run bash
, using the -c
command-line option to give it a command to run.
my $x = `bash -c compgen -c`;
From a bash
prompt, you can use type
to see how a command is implemented.
$ type ssh
ssh is /usr/bin/ssh
$ type compgen
compgen is a shell builtin