2

I need to run a shell command within a perl script(It needs to be a shell command) but I need to use a variable in a perl loop

Ex. doing something like

#!/usr/bin/perl
for my $i (0..9) {
     `echo $i`;
}

should produce the output

0
1
2
3
4
5
6
7
8
9
Sam
  • 1,765
  • 11
  • 82
  • 176
  • 3
    *"I received some commands from a website"* Web sites don't generally issue commands to people; you must be more specific. Are you saying that you have a web server that needs to execute shell commands? – Borodin Jun 03 '16 at 20:34
  • The command pulls information off it's website, The important part is that there is not an equivalent perl command, I received through email from an online database. – Sam Jun 03 '16 at 21:17
  • 3
    @C.Monster: Your question is close to being closed (as of this writing, 3 votes to close, because it is "unclear what you're asking"). To prevent that, add information _directly to your question_ and consider providing an [MCVE (Minimal, Complete, and Verifiable Example)](http://stackoverflow.com/help/mcve); See http://stackoverflow.com/help/how-to-ask for tips on how to ask good questions. – mklement0 Jun 03 '16 at 21:37
  • 1
    @C.Monster Specifically, I'd suggest to address the comment by Borodin, and perhaps provide example(s) of a command to be run. – zdim Jun 03 '16 at 21:39
  • Why would you expect `0123456789`, with all contents on one line, not `0` on one line, `1` on the next, etc? Is quashing newlines part of the specification for an answer to resolve? – Charles Duffy Jun 03 '16 at 22:04
  • @C.Monster Thank you for updating your question, it is much clearer now. Just wanted to let you know that I updated my answer as well, you may want to have a look as it may be clearer now. – zdim Jun 08 '16 at 05:33

2 Answers2

5

You can do it in several ways, depending on what exactly is needed. Generally, this involves use of system, backticks (with operator form qx), or open. There is also a number of great modules for it.

The qx returns its STDOUT to the program. If you need it assign it to a variable.

for my $i (0..9) {
    my $cmd = "external-command $i";
    my $cmdout = qx($cmd);             # needs error checking ($?)
    print $cmdout;                     # process as needed
}

The output can also be assigned to an array, when each line becomes one array element. Depending on what your command is you may have to pay close attention to how to quote it correctly, and String::ShellQuote can help a lot. If you want to get the command's STDERR as well use

my $cmd = "external-command $i 2>&1";

See qx in perlop (or readpipe), which also discusses error checking; also see $? in pervar.

If you don't need the command's output in your script, or specifically want it to wind up together with your script's other output, use system. Commands run by it inherit the script's STDOUT and STDERR so what they print to standard streams will go where your script's output goes (unless it is redirected by the command invocation).

for my $i (0..9) {
    my $cmd = "external-command $i";
    my $ret = system($cmd);
    if ($ret != 0) {
        warn "Error running $cmd: $ret";
        # interrogate further, see documentation for 'system'
    }
}

The error handling above is rudimentary, see docs for more. Finally, there are various forms of open that run a process. For example, see it in perlfaq8, along with a full review of what you are asking.

And then there are modules, that make this kind of work far easier and better. From simple to more capable, some of well-known ones are IPC::System::Simple, Capture::Tiny, IPC::Run3, and IPC::Run. Also see links (examples) assembled in this post, for example.

A command can be executed via a shell or not (but via execvp) depending on how exactly it is invoked, as discussed in the docs. The phrase "shell command" strictly refers to a facility provided by the shell itself, in which case you of course want to run it that way. However, it is also often used for a program that we normally execute by typing in a terminal, so it gets executed by the shell. In this case you may (or may not) want to bypass the shell.

Also note that the above all block (do not return control before completing), so the script continues only after they're done. This seems to be what you want.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • 5
    @C.Monster I am glad that what I posted answered your need, thanks for attribution. Still, I suggest that you now edit and clarify your question. Please appreciate that people later search for and come to these posts and leaving them behind in a good shape can help many later. In doing so we need to be careful not to _change_ the question in a way that invalidates the answers. – zdim Jun 03 '16 at 21:46
0

If you just want to pass through the shell output, simply do

print STDOUT `echo $i`;
GWP
  • 131
  • 2