Thursday, October 27, 2022

[SOLVED] Can't run "compgen -c" from perl script

Issue

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?


Solution

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.

This compgen is a bash builtin. One way to discover that is to run man compgen (in bash) -- and the bash manual pops up. Another way is type as Dave shows.

To use builtins we generally need to run an explicit shell for them, and they have a varied behavior in regards to whether the shell is "interactive" or not. I can't find a discussion of that in bash documentation for this builtin but experimentation reveals that you need

my @completions = qx(bash -c "compgen -c")

The quotes are needed so to pass a complete command to a shell 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 in the command, by adding 2>&1 (redirect to STDOUT) 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.)


This can be facilitated with -i

my @output_lines = qx(bash -i -c "command with arguments")


Answered By - zdim
Answer Checked By - Dawn Plyler (WPSolving Volunteer)