在bash的HereDoc中使用Perl脚本

20

能否在bash脚本中使用heredoc的方式编写Perl脚本呢?

以下示例并不有效:

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

有没有一种好的方法将Perl脚本嵌入Bash脚本中?想要从Bash脚本中运行Perl脚本,但不想将其放入外部文件中。


你不需要在可执行文件名称后面加一些命令行开关吗?比如 perl -we - TLP
1
@TLP 不是的,OP只是将脚本作为标准输入传递。 - mob
4个回答

27

问题在于脚本被传递到perl的标准输入上,因此尝试从脚本处理标准输入是行不通的。

1. 字符串字面值

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

使用字符串文字是最直接的编写方式,但如果Perl脚本本身包含单引号,则不是理想的方法。

2. 使用 perl -e

#/bin/bash

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

如果你使用perl -e将脚本传递给Perl,则不会有stdin问题,并且你可以在脚本中使用任何字符。但是,这种方法有些绕弯子。Here-docs生成stdin上的输入,但我们需要字符串。怎么办?哦,我知道了!这就需要用到$(cat <<HEREDOC)

确保使用<<'EOF'而不仅仅是<<EOF,以防止bash在这里文档内进行变量插值。

你也可以不使用$script变量来编写这个脚本,不过现在已经变得非常复杂了!

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

3. 进程替换

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

在第二条线上,您可以使用称为“进程替换”的bash功能,它允许您在文件名的位置编写<(cmd)。如果您使用此选项,您就不需要-e,因为您现在传递给perl的是一个文件名而不是字符串。


第二个问题:$_被shell进行了插值,可能会变成一个空字符串。请对其进行转义... print "xxx: \$_\n"; - mob
它每个文件只能使用一次,但 Perl 的 -x 标志可以产生较少的丑陋结果。 - tjd
@john-kugelman,通过heredoc,可以在Perl代码中使用Bash的变量吗? - user3905644
在 Perl 脚本中,您可以使用导出的 bash 变量 $ENV{variable},例如:set | perl -lne 'print if m/$ENV{HOME}/;' - mosh

4

您知道吗,我从未考虑过这个问题。

答案是“是的!”,它确实有效。正如其他人所提到的,无法使用<STDIN>,但这个方法很好用:

$ 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

Kornshell和BASH中,如果你用单引号将Here文档字符串括起来,那么该Here文档就不会被Shell插值。


@JohnKugelman,我在帖子中提到您不能使用STDIN。问题是“_是否可能在bash脚本中编写一个perl脚本作为heredoc_”,而不是您是否可以从STDIN读取。答案是肯定的,它确实有效。 - David W.

2

仅对@John Kugelman的答案进行小修正。您可以消除无用的cat并使用:

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

perl -e "$perlscript"

0
这是另一种在bash中使用PERL HEREDOC脚本并充分利用它的方法。
    #!/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

或者

    #!/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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接