如何让Perl脚本同时接受来自标准输入和命令行参数的参数?

4

这个U&L Q&A的启发,如何通过STDIN和命令行参数解析Perl脚本的两个输入?

例如,我想要一个脚本,可以同时从STDIN和命令行参数中读取输入参数:

$ command | my_command.pl arg1 arg2

command 的输出结果将会是:

arg3
arg4
...

因此,当my_command.pl正在运行时,它将意识到参数arg1、arg2、arg3和arg4。


1
我认为使用 xargs 包装器可能比直接在 Perl 中实现更容易。 - muru
@muru - 我并不是在寻找最简单的方法来做这件事,我只是想为我的答案构建一个代理问题。8-) 由于搜索示例没有显示任何内容,因此在互联网上没有好的使用Perl的示例似乎是一个奇怪的空缺。 - slm
这让我想知道是否有一个模块潜伏在 CPAN 的黑暗角落中,具有类似于 xargs 的功能。 - muru
1
@muru - 我敢打赌肯定有这样的模块。但是不要为此而烦恼。我最初想创建这个问题纯粹是因为没有一个好的例子。如果我猜的话,可能有一个模块用于构建Perl脚本作为Unix cli工具,可以直接提供此功能,即使您可以像我一样自己完成。另一个要考虑的是解析命令行参数的模块。我认为他们也可以做到这一点。 - slm
1
完全没有必要使用这个功能。my_command.pl arg1 arg2 $(command) 可以实现你想要的功能,并且不会占用标准输入流,这是额外的好处。 - William Pursell
显示剩余4条评论
3个回答

4
我设计了以下Perl脚本,可以从标准输入或命令行参数中读取数据,或者两者都可以。

脚本内容

$ cat command.pl 
#!/usr/bin/perl -w

use strict;

if ( -t STDIN and not @ARGV ) {
    print "\n" ."USAGE" . "\n";
    print       "=====" . "\n";
    print "#1:\t $0 <arg1>..<argN>\n";
    print "#2:\t <commands> | $0\n";
    print "#3:\t <commands> | $0 <arg1>..<argN>\n\n";
    exit 1;
}

if ( not -t STDIN ) { 
    print "\n" . "STDIN ARGS" . "\n";
    print        "==========" . "\n";
    print while (<STDIN>); 
    print "\n";
}

if (@ARGV) { 
    print "\n" . "ARGV ARGS" . "\n";
    print        "=========" . "\n";
    foreach (@ARGV) { 
        print "$_\n"; 
    }
    print "\n";
}

工作原理

该脚本利用了@ARGV<STDIN>,根据它们是否被定义来进行操作。如果两者都未定义,则显示使用说明并退出。

测试脚本

为了测试它,我编写了这个名为tests.bash的辅助脚本,它使用各种方法将输入传递给上述脚本。 注意:这些测试标记为T00到T10。

$ cat tests.bash 
#!/bin/bash

echo ""
echo ""

echo "====================================="
echo "T00: no input"
./command.pl
echo "====================================="
echo ""

# http://www.tldp.org/LDP/abs/html/subshells.html
echo "====================================="
echo "T01: 2 args w/ pipe via cmd list '(..) | ...' aka. subshell"
( echo "pipearg1"; echo "pipearg2"; ) | ./command.pl
echo "====================================="
echo ""

# http://www.tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF
echo "====================================="
echo "T02: 2 args w/ pipe via inline group '{..} | ...' aka. code block"
{ echo "pipearg1"; echo "pipearg2"; } | ./command.pl
echo "====================================="
echo ""

echo "====================================="
echo "T03: 2 cli args 'cmd A1 A2'"
./command.pl argv1 argv2
echo "====================================="
echo ""

echo "====================================="
echo "T04: T01 + T03"
( echo "pipearg1"; echo "pipearg2"; ) | ./command.pl argv1 argv2
echo "====================================="
echo ""

echo "====================================="
echo "T05: T02 + T03"
{ echo "pipearg1"; echo "pipearg2"; } | ./command.pl argv1 argv2
echo "====================================="
echo ""

echo "====================================="
echo "T06: echo with newline: $'..\n..'"
echo $'pipearg1\npipearg2' | ./command.pl
echo "====================================="
echo ""

echo "====================================="
echo "T07: echo -e with newline: '..\n..'"
echo -e "pipearg1\npipearg2" | ./command.pl
echo "====================================="
echo ""

echo "====================================="
echo "T08: 2 cli args via HEREDOC 'cmd <<EOF ... EOF'"
./command.pl <<EOF
arghd1
arghd2
EOF
echo "====================================="
echo ""

echo "====================================="
echo "T09: 2 cli args via process substitution 'cmd < <(...cmds...)'"
./command.pl < <(echo argps1; echo argps2)
echo "====================================="
echo ""

echo "====================================="
echo "T10: T03 + T09"
./command.pl argv1 argv2 < <(echo argps1; echo argps2)
echo "====================================="
echo ""

tests.bash 的输出

tests.bash 脚本旨在运行11个不同的测试,涵盖从使用 HEREDOCS 到子 shell,再到传递命令行参数等多种情况。它还将这些组合起来,全面测试 Perl 脚本command.pl

$ ./tests.bash 


=====================================
T00: no input

USAGE
=====
#1:  ./command.pl <arg1>..<argN>
#2:  <commands> | ./command.pl
#3:  <commands> | ./command.pl <arg1>..<argN>

=====================================

=====================================
T01: 2 args w/ pipe via cmd list '(..) | ...' aka. subshell

STDIN ARGS
==========
pipearg1
pipearg2

=====================================

=====================================
T02: 2 args w/ pipe via inline group '{..} | ...' aka. code block

STDIN ARGS
==========
pipearg1
pipearg2

=====================================

=====================================
T03: 2 cli args 'cmd A1 A2'

ARGV ARGS
=========
argv1
argv2

=====================================

=====================================
T04: T01 + T03

STDIN ARGS
==========
pipearg1
pipearg2


ARGV ARGS
=========
argv1
argv2

=====================================

=====================================
T05: T02 + T03

STDIN ARGS
==========
pipearg1
pipearg2


ARGV ARGS
=========
argv1
argv2

=====================================

=====================================
T06: echo with newline: $'..\n..'

STDIN ARGS
==========
pipearg1
pipearg2

=====================================

=====================================
T07: echo -e with newline: '..\n..'

STDIN ARGS
==========
pipearg1
pipearg2

=====================================

=====================================
T08: 2 cli args via HEREDOC 'cmd <<EOF ... EOF'

STDIN ARGS
==========
arghd1
arghd2

=====================================

=====================================
T09: 2 cli args via process substitution 'cmd < <(...cmds...)'

STDIN ARGS
==========
argps1
argps2

=====================================

=====================================
T10: T03 + T09

STDIN ARGS
==========
argps1
argps2


ARGV ARGS
=========
argv1
argv2

=====================================

参考资料


3

使用perl的钻石操作符相当容易实现。

push(@ARGV, "/dev/stdin");
while(<>) {
  print;
}

例如:

$ echo A > a
$ echo B > b
$ echo C | perl test.pl a b
A
B
C

不幸的是,这确实依赖于/dev/stdin,但仍然相当可移植。


我应该将OP展示的示例添加到我的问题中。他最终想要使这个工作:echo -e "response\ny" | ./command.pl,而我想要自己的./command.pl来测试传递数据的各种方法。我想要一个脚本,它可以仅通过STDIN + ARGV获取参数,而不是ARGV文件的内容。 - slm

1
你可以在@ARGV的末尾添加来自STDIN的输入,保留HTML。
push @ARGV, <STDIN> unless -t STDIN;

1
if -p STDIN 也可以使用 代替 unless -t STDIN - mpapec

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