clt60
clt60

Reputation: 63892

Perl script in bash's HereDoc

Is possible somewhat write a perl script in a bash script as heredoc?

This is not working (example only)

#/bin/bash
perl <<EOF
while(<>) {
    chomp;
    print "xxx: $_\n";
}
EOF

Is here some nice way how to embed a perl script into a bash script? Want run perl script from an bash script and don't want put it into external file.

Upvotes: 21

Views: 12429

Answers (4)

clt60
clt60

Reputation: 63892

Only small corection of @John Kugelman's answer. You can eliminate the useless cat and use:

read -r -d '' perlscript <<'EOF'
while(<>) {
    chomp;
    print "xxx: $_\n";
}
EOF

perl -e "$perlscript"

Upvotes: 2

Dave Cronin
Dave Cronin

Reputation: 1

Here's another way to use a PERL HEREDOC script within bash, and take full advantage it.

    #!/bin/sh
    #If you are not passing bash var's and single quote the HEREDOC tag
    perl -le "$(cat <<'MYPL'
    # Best to build your out vars rather than writing directly
    # to the pipe until the end.
    my $STDERRdata="", $STDOUTdata="";
    while ($i=<STDIN>){ chomp $i;
        $STDOUTdata .= "To stdout\n";
        $STDERRdata .= "Write from within the heredoc\n";
    MYPL
    print $STDOUTdata; #Doing the pipe write at the end
    warn $STDERRdata;  #will save you a lot of frustration.
    )" [optional args] <myInputFile 1>prints.txt 2>warns.txt

or

    #!/bin/sh
    set WRITEWHAT="bash vars"
    #If you want to include your bash var's
    #Escape the $'s that are not bash vars, and double quote the HEREDOC tag
    perl -le "$(cat <<"MYPL"
    my $STDERRdata="", $STDOUTdata="";
    while (\$i=<STDIN>){ chomp \$i;
        \$STDOUTdata .= "To stdout\n";
        \$STDERRdata .= "Write $WRITEWHAT from within the heredoc\n";
    MYPL
    print \$STDOUTdata; #Doing the pipe write at the end
    warn \$STDERRdata;  #will save you a lot of frustration.
    )" [optional args] <myInputFile 1>prints.txt 2>warns.txt

Upvotes: 0

John Kugelman
John Kugelman

Reputation: 361585

The problem here is that the script is being passed to perl on stdin, so trying to process stdin from the script doesn't work.

1. String literal

perl -e '
while(<>) {
    chomp;
    print "xxx: $_\n";
}
'

Using a string literal is the most direct way to write this, though it's not ideal if the Perl script contains single quotes itself.

2. Use perl -e

#/bin/bash

script=$(cat <<'EOF'
while(<>) {
    chomp;
    print "xxx: $_\n";
}
EOF
)
perl -e "$script"

If you pass the script to perl using perl -e then you won't have the stdin problem and you can use any characters you like in the script. It's a bit roundabout to do this, though. Heredocs yield input on stdin and we need strings. What to do? Oh, I know! This calls for $(cat <<HEREDOC).

Make sure to use <<'EOF' rather than just <<EOF to keep bash from doing variable interpolation inside the heredoc.

You could also write this without the $script variable, although it's getting awfully hairy now!

perl -e "$(cat <<'EOF'
while(<>) {
    chomp;
    print "xxx: $_\n";
}
EOF
)"

3. Process substitution

perl <(cat <<'EOF'
while(<>) {
    chomp;
    print "xxx: $_\n";
}
EOF
)

Along the lines of #2, you can use a bash feature called process substitution which lets you write <(cmd) in place of a file name. If you use this you don't need the -e since you're now passing perl a file name rather than a string.

Upvotes: 28

David W.
David W.

Reputation: 107040

You know I never thought of this.

The answer is "YES!" it does work. As others have mentioned, <STDIN> can't be used, but this worked fine:

$ perl <<'EOF'
print "This is a test\n";
for $i ( (1..3) ) {
print "The count is $i\n";
}
print "End of my program\n";
EOF
This is a test
The count is 1
The count is 2
The count is 3
End of my program

In Kornshell and in BASH, if you surround your end of here document string with single quotes, the here document isn't interpolated by the shell.

Upvotes: 4

Related Questions