2

How to run more than 1 command inside open?

I have a code below. Here, I am running make $i inside open, but now I want to run more than 1 command here, say make $i; sleep 30; echo abc. How can I do that?

foreach $i (@testCases) {
   my $filehandle;
   if ( ! (my $pid = open( $filehandle, "make $i 2>&1 |" ) )) {
       die( "Failed to start process: $!" );
   }
   else {
       print "Test started\n";
   }
}

Just to add the following is not working properly:

if (!($pid = open( my $pipe, "make $i; sleep 30; echo abc |" ))) " {
  print "Problem in openeing a filehandle\n";
} else {
     print "$pid is pid\n";
     my $detailedPs=`tasklist | grep "$pid"`;
     chomp ($detailedPs);
     print "$detailedPs is detailedPs\n";
 }

Here, I am getting $detailedPs as empty. If things would have run correctly, I would have got something in $detailedPs

PPP
  • 329
  • 1
  • 9
  • Re the edit which added the answer to the question: No idea what tasklist is/does, but `$pid` does contain the pid of the child. (The child isn't `make`, but [we've already covered that before](https://stackoverflow.com/a/73113551/589924).) – ikegami Jul 29 '22 at 17:14
  • @ikegami, Yes, child is not make. But, $pid is what I am searching for. And $pid is the pid of shell. It should have come. – PPP Jul 29 '22 at 17:22
  • @ikegami, I modified a lit bit my command like: if ( !($pid = open( $filehandle, "-|" , "sleep 30; make $i " ))) { . And I am getting error: sleep: invalid time interval '30;' – PPP Jul 29 '22 at 17:22
  • Re "*It should have come*", Again, the PID was returned – ikegami Jul 29 '22 at 17:24
  • Re "*And I am getting error: sleep: invalid time interval '30;'*", You passed `'30'` (as if you had done `sleep "'30'"` from the shell) instead of `30` as the argument. The command you posted does not do this. – ikegami Jul 29 '22 at 17:26
  • @ikegami, As you can see in the command mentioned above [if ( !($pid = open( $filehandle, "-|" , "sleep 30; make $i " ))) {], I passed 30, and not '30' – PPP Jul 29 '22 at 17:28
  • @ikegami, FYI: I am running it on windows – PPP Jul 29 '22 at 17:28
  • huh, Windows doesn't have a sleep. (`'sleep' is not recognized as an internal or external command, operable program or batch file.`) Are you perhaps using cygwin or msys rather than Windows? Anyway, the comments is not the place to ask new questions. – ikegami Jul 29 '22 at 17:29
  • Actually, it might explain your second question. What's `perl -v`? (Just the "This is" line) – ikegami Jul 29 '22 at 17:32
  • @ikegami, perl -v:: This is perl 5, version 30, subversion 2 (v5.30.2) built for MSWin32-x64-multi-thread. Yes, I am using cygwin sleep. But, again, why the error of sleep ? Even if I am using [if ( !($pid = open( $filehandle, "-|" , "echo 30; make $i " ))) , second command (here, make$i) is not working. – PPP Jul 29 '22 at 17:35
  • Some of your problems come from mixing two OSes. You are using a Windows build of Perl, and you are trying to run unix commands. Use cygwin's perl. – ikegami Jul 29 '22 at 17:43
  • (Cygwin's will say "built for cygwin-thread-multi") – ikegami Jul 29 '22 at 17:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/246916/discussion-between-ppp-and-ikegami). – PPP Jul 30 '22 at 18:11
  • @ikegami, one more thing. How can I add the output of just "make $i" command to another log file?//FYI: [if ( !($pid = open( $filehandle, "-|" , " make $i 2>&1 logfile.txt" ))) is not working. – PPP Jul 31 '22 at 08:28
  • Aside from getting the syntax wrong, you need something like `tee` if you want the output to go to a log file and still go to where it would go normally. – ikegami Jul 31 '22 at 23:54
  • @ikegami, Thanks! And what if I want the logs if "make $i" to go in a log file, and not where other logs are dumping. – PPP Aug 01 '22 at 10:17
  • No, the place it would go normally is the pipe to your program. It makes no sense to create the pipe if you're not going to use it – ikegami Aug 01 '22 at 12:45

1 Answers1

2
open( my $pipe, "make $i; sleep 30; echo abc |" )
   or die( "Can't launch shell: $!\n" );

my $stdout = join "", <$pipe>;  # Or whatever.

close( $pipe )
   or die( "A problem occurred running the command.\n" );

Preferred:

open( my $pipe, "-|", "make $i; sleep 30; echo abc" )

Short for: (non-Windows)

open( my $pipe, "-|", "/bin/sh", "-c", "make $i; sleep 30; echo abc" )

But note that you have a code injection bug. Fixed:

open( my $pipe, "-|", "/bin/sh", "-c", 'make "$1"; sleep 30; echo abc', "dummy", $i )

With IPC::Run:

use IPC::Run qw( run );

run(
   [ "/bin/sh", "-c", 'make "$1"; sleep 30; echo abc', "dummy", $i ],
   '>', \my $stdout  # Or whatever.
)
   or die( "A problem occurred running the command.\n" );

But you'd be better off avoiding a shell.

use IPC::Run qw( run );

run(
   [ 'make', $i ],
   '|', [ 'sleep', '30' ],
   '|', [ 'echo', 'abc' ],
   '>', \my $stdout
)
   or die( "A problem occurred running the command.\n" );
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I also want the PID of this command ( as mentioned in my question ($pid)) for further monitoring via fork – PPP Jul 29 '22 at 17:07
  • Following is not working correctly: "if (!($pid = open( my $pipe, "make $i; sleep 30; echo abc |" ))) " – PPP Jul 29 '22 at 17:10