6

In the middle of my perl script I want to execute a bash command. The script takes a long time, so at the beginning of the script I want to see if the command exists. This answer says to just try and run it and this other answer suggests some bash commands to test if the program exists.

Is the latter option the best solution? Are there any better ways to do this check in perl?

Community
  • 1
  • 1
flakes
  • 21,558
  • 8
  • 41
  • 88
  • Are you going to call the command immediately anyway? – ikegami Mar 04 '16 at 16:26
  • @ikegami no, its halfway through the script – flakes Mar 04 '16 at 16:27
  • Then just running it makes no sense. – ikegami Mar 04 '16 at 16:31
  • Do you have the full path to the external program? – ThisSuitIsBlackNot Mar 04 '16 at 16:32
  • @ThisSuitIsBlackNot I'm checking to see if its installed, so I guess the /usr/bin/ directory. – flakes Mar 04 '16 at 16:35
  • If you *know* it will be in /usr/bin and nowhere else, you can test for the existence of the full path to the program like syck showed. If you're relying on the shell to find the program somewhere in your PATH, that approach won't work; then again, you probably shouldn't be relying on PATH anyway. – ThisSuitIsBlackNot Mar 04 '16 at 16:47
  • Do you mean a *bash command* (a built-in that is part of the shell, like `echo`) or do you need to check for the existence of an executable file? Note that, unless your command line contains shell metacharacters, perl will execute it directly without involving the shell – Borodin Mar 04 '16 at 16:49
  • What is *halfway through the script*? Is it 500μs, 30 minutes, or a couple days? And is it preceded by stuff that does things that are difficult to roll back? – Borodin Mar 04 '16 at 16:59
  • This is either a duplicate of one of the linked questions, or it's opinion-based. Just try them both and see which one works better for you. – miken32 Mar 04 '16 at 19:25

4 Answers4

4

My best guess is that you want to check for existence of an executable file that you want to run using system or qx//

But if you want your command line to behave the same way as the shell, then you can probably use File::Which

Borodin
  • 126,100
  • 9
  • 70
  • 144
3

What if we assume that we don't know the command's location? This means that syck's answer won't work, and zdim's answer is incomplete.

Try this function in perl:

sub check_exists_command { 
    my $check = `sh -c 'command -v $_[0]'`; 
    return $check;
}
# two examples 
check_exists_command 'pgrep' or die "$0 requires pgrep";
check_exists_command 'readlink' or die "$0 requires readlink";

I just tested it, because I just wrote it.

marinara
  • 538
  • 1
  • 5
  • 10
  • 2
    Oh that's another interesting option! Just as a personal style note, I think I'd rather use `qx//` over backticks as I find that a bit easier to read! – flakes Jul 18 '20 at 00:45
  • This is vulnerable to command injection and therefore extremely unsafe. If you have to use this approach, never ever pass untrusted data to `check_exists_command`. – Martin von Wittich May 23 '22 at 17:45
2

With perl, you can test files for existence, readability, executability etc., take a look here.

Therefore just use

executeBashStuff() if -x $filename;

or stat it:

stat($filename);
executeBashStuff() if -x _;
syck
  • 2,984
  • 1
  • 13
  • 23
  • 1
    The `open` is superfluous. Just `execute_bash_stuff() if -x $filename`. You would make a lot of people who are familiar with Perl happy if you kept to `snake_case` variables. Ultimately I'm not sure that this answers what the OP is asking – Borodin Mar 04 '16 at 16:38
  • No need to comment on a fix – Borodin Mar 04 '16 at 16:56
1

To me a better check is to run the program at the beginning of the script (with -V say).

I'd use the same invocation as you use to run the job later (via shell or not, via execvp). Once at it, make sure to see whether it threw errors. This is also discussed in your link but I would in fact get the output back (not send it away) and check that. This is the surest way to see whether the thing actually runs out of your program and whether it is what you expect it to be.

Checking for the executable with -x (if you know the path) is useful, too, but it only tells you that a file with a given name is there and that it is executable.

The system's which seems to be beset with critism for its possible (mis)behavior, it may or may not be a shell-builtin (which complicates how exactly to use it), is an external utility, and its exact behavior is system dependent. The module File::Which pointed out in Borodin's answer would be better -- if it is indeed better than which. (What it may well be, I just don't know.)


Note. I am not sure what "bash command" means: a bash shell built-in, or the fact that you use bash when on terminal? Perl's qx and system use the sh shell, not bash (if they invoke the shell, which depends on how you use them). While sh is mostly a link, and often to bash, it may not be and there are differences, and you cannot rely on your shell configuration.

Can also actually run a shell, qx(/path/bash -c 'cmd args'), if you must. Mind the quotes. You may need to play with it to find the exact syntax on your system. See this page and links.

zdim
  • 64,580
  • 5
  • 52
  • 81