curtisb has asked for the wisdom of the Perl Monks concerning the following question:

Ok, monks,
Once again I've come to a point where I throw myself to your mercy.

what I'm trying to do is run the following:

#!/usr/bin/perl -w use strict; system("lsnrctl")<<"EOF"==0 or die "couldn't run listener control: $!" + ; status EOF

I already know that this is not right. What I want to do is run the lsnrclt command and have it do all the steps that I need before the EOF marker. Something like this:

#!/usr/bin/perl -w use strict; system("lsnrctl")<<"EOF"==0 or die "couldn't run listener control: $!" + ; set password set current_listener status EOF

Please help.


I just answered my own question

#!/usr/bin/perl -w use strict; my $command = <<EOF; lsnrctl set password 'oracle' set current_listener 'LISTENER' status EOF system($command)==0 or die "couldn't run listener control: $!" ;

thanks, Bobby

Replies are listed 'Best First'.
Re: Heredoc with system call
by Tanktalus (Canon) on Dec 18, 2008 at 04:54 UTC

    While I'm glad you've answered your own question, I have to admit that I'm confused by it. I would expect that the "set"s and the "status" are commands that lsnrctl should receive, and not be separate commands. In that case, I would have expected that they needed to be sent to lsnrctl's STDIN. The easiest way to do that would be:

    system(<<EOF) and die "couldn't run listener control: $?"; echo "set password 'oracle' set current_listener 'LISTENER' status" | lsnrctl EOF
    though that's definitely not the most perlish (and probably won't quite work as-is on Windows). Something more like:
    open my $fh, "|-", "lsnrctl" or die "can't run listener control: $?"; print $fh <<EOF; set password 'oracle' set current_listener 'LISTENER' status EOF close $fh;
    is probably closer, and far more perlish.

      Your open $fh approach worked. Will this same solution work on UNIX as well as windows?


        It will work at least as well, possibly better on unix.
      Sorry for opening an old thread but I arrived to this one as one of my requirements is to also pass arguments to the command as $0 and $1. Can you please suggest how to append this code that it also works with arguments ?
      echo "$var1 and $var2 can be read here"; open my $fh, "|-", "sudo su - APP" or die "can't run sudo: $ +?"; print $fh <<' _EOF_'; ls echo "$var1 and $var2 can't be found here ? :( " _EOF_ close $fh;

      2019-04-23 Athanasius added code tags

        a quick hack is to remove the single quotes from the heredoc marker. In this way the heredoc contents will be processed by perl and any variables within it will be interpolated (and if you do not have use strict; use warnings; all perl-looking variables - declared in your program or not - will be replaced). However, better than a heredoc is to construct a string with your specifications under your full control, using for example, sprintf(), escaping sigils and single quotes. For example, my $var1 = ...; my $str = "echo '$var1' | awk '{print \$1}'";

        See also, Re^2: Ubuntu File Names with spaces and special characters

        On bash like systems xargs is supposed to transform STDIN to positionals args

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Heredoc with system call
by diotalevi (Canon) on Dec 18, 2008 at 04:53 UTC

    Are you sure you answered your own question? It looked like you wanted to pipe some data to the STDIN of the lsnrctl program (whatever that is).

    PS, you should be looking at $?, not $!. $! is for system calls, not the function which happens to be called "system."

    #!/usr/bin/perl -w use strict; system("lsnrctl <<\"EOF\" set password 'oracle' set current_listener 'LISTENER' status EOF ") == 0 or die "Couldn't run listener control: $?"; system($command)==0 or die "couldn't run listener control: $!";

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      I can see what you are saying, but when I tried your code, I got this error;
      system("lsnrctl <<\"EOF\" set password oracle set current_listener LISTENER status EOF ") == 0 or die "Couldn't run listener control: $?";

      << was unexpected at this time. Couldn't run listener control: 256 at C:\ line 4.


        Oh, right. What I wrote would be valid for something like a bash shell but not for anything on Windows where it doesn't understand anything like heredocs. Since win32 perl only pretends to use fork, I found myself quickly unable to write a native CreateProcess call and then write to its stdin. I dunno. I'm just not a Windows programmer.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Heredoc with system call
by Anonymous Monk on Dec 19, 2008 at 07:34 UTC
    I can't tell whether you want the command status or whatever feeding lcnrctl "status" may say. I suspect the latter over the former; if so, then why not write the simpler:
    $their_stdout = <<`END_CMDS`; die "oops: wstat $?, errno $!" if $?; ( echo set password 'oracle'; echo set current_listener 'LISTENER'; echo status; ) | lsnrctl END_CMDS

    Well, ok: just because you can backtick your heredoc, doesn't automatically mean you (always?) should. It does seem a wee bit convoluted over using `shell commands` or qx{shell commands} directly. Remember you don't want system(shell commands) if you must inspect the command's (or commands') output. The system function is reserved for those (perhaps fewer) scenarios when you care only for the process's (or subshell's) exit status, disregarding whatever that command may splutter on its STDOUT and STDERR, leaking out to the user.

    Like any normal situation in Perl, the default behaviour is to replace (certain) variables with their values -- unless and until you ask this not to happen. The pseudo-literal `shell commands` always interpolates, whether in normal use or applied to the <<`END_TOKEN` string.

    Maybe, probably, perhaps that's ok. Usually.

    But with backticks' alias to `shell commands` via the nifty pick-your-own-delimiters qx{shell commands} notation, now you decide where, when, and whether entire strings or individual variables expand.

    Much more flexible this way: if you need some things to interpolate but others not to, choose interpolative syntax and "escape" those you don't want to expand by \backslashing them.

    # variables normally expand $bunches = "\t@these + @those\n"; # but not if escaped; the hats are literals now $bunches = "\t\@these + \@those\n"; # or suppress them all in one swell foop $cost = '39 widgets @$1.59 apiece'; # selectively suppressed variable expansion system qq{Mail -s "gotta problem" helpdesk\@support <$complaints}; # variables normally expand @many = ( @these, @those); # suppress variable expansion @rpair = (\@these, \@those); # *distributively* suppress variable expansion @rpair = \(@these, @those);

    You're free to delimit the commands with suppressive single-quotes via the qx'shell commands' form, just as with all these and more:

    • 'string'
    • m'pattern'
    • qr'pattern'
    • s'pattern'replacement'
    • <<`END_TOKEN`

    Contrary to popular misunderstanding, even hash subscripts or the RHS of the double-barrelled comma may sometimes need quoting. These are different:

    $place{ 040 } = 1; $place{'040'} = 2; # similarly... %place = ( 040 => 1, '040' => 2, );

    This all assumes you want the main program to pause until the subshell exits. Asynchronous executions through variations of perlian cognates to popen and kin are also possible, but don't seem especially applicable to what you appear intent on doing.

    HTH && HAND || SAD;