受这个U&L Q&A的启发,如何通过STDIN和命令行参数解析Perl脚本的两个输入?
例如,我想要一个脚本,可以同时从STDIN和命令行参数中读取输入参数:
$ command | my_command.pl arg1 arg2
command
的输出结果将会是:
arg3
arg4
...
因此,当my_command.pl
正在运行时,它将意识到参数arg1、arg2、arg3和arg4。
$ 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
脚本旨在运行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
=====================================
使用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
,但仍然相当可移植。
echo -e "response\ny" | ./command.pl
,而我想要自己的./command.pl
来测试传递数据的各种方法。我想要一个脚本,它可以仅通过STDIN + ARGV获取参数,而不是ARGV文件的内容。 - slm@ARGV
的末尾添加来自STDIN
的输入,保留HTML。push @ARGV, <STDIN> unless -t STDIN;
xargs
包装器可能比直接在 Perl 中实现更容易。 - muruxargs
的功能。 - murumy_command.pl arg1 arg2 $(command)
可以实现你想要的功能,并且不会占用标准输入流,这是额外的好处。 - William Pursell