标准输入<STDIN>
<STDIN>表示从标准输入中读取内容(来自键盘的输入),如果没有输入会继续等待,默认读取的内容会带换行符;
#!/usr/bin/perl
use 5.10.1;
my $line = <STDIN>;
if($line -eq "\n")
{
print("blank line\n");
}
else
{
chomp($line);
print("not blank:$line\n");
}
<STDIN>标准输入的结束表示是换行符 \n,在输入中如果发现换行符则会结束读取,换行符后面的内容不会读取,如下:
echo "hello\nworld" | perl stdin.pl
perl脚本中只会读取到 hello\n,而world 则不会读取到;
由于<STDIN>是读取标准输入,如果想用来读取文件的内容,则需要使用 shell 的重定向功能,如下所示:
perl stdin.pl <a.txt
但是上面的代码只能读取到 a.txt 的一行内容,如果要读取全部内容,需要使用 while 进行循环:
while(defined($line=<STDIN>))#推荐
{
print("$line");
}
foreach(<STDIN>)#不推荐
{
print("$_");
}
上面的while 循环中,每次从标准输入中读取一行并赋给变量 $line,并检查变量是否定义;也可以不将读取的内容赋给变量,此时读取内容会默认存入变量 $_中,如上面的foreach 循环中所示;
但是上面两种循环的遍历方式是有区别的,while为标量上下文,也就是每次仅仅读取文件的一行;而foreach 则是列表上下文,它首先会将文件全部读取放入一个列表,然后再在列表中每次取一个元素,foreach这种方式不推荐!!
需要注意的是,默认变量 $_ 与 <STDIN> 并没有直接的关系,只是在上面的循环体中默认将读取的内容赋给了变量 $_ 罢了;
读取文件输入<>
perl中使用两个尖括号符号来逐行读取来自文件的输入,例如从命令行传递文件作为输入源,这两个尖括号称为 钻石操作符;需要注意的是,钻石操作符也支持读取标准输入
while (defined($line = <>))
{
print("$line");
}
#简化版
while (<>)
{
print("$_");
}
然后在命令行中指定输入文件,这样就会依次读取文件的每一行,如下:
perl zuanshi.pl a.txt
如果想让钻石操作符在读取完输入文件后继续读取标准输入,那么只需要在命令行中加入 - 就可以了,如下:
perl zuanshi.pl a.txt -
上面的命令在用钻石操作符依次读取完 a.txt 后,然后会去读取标准输入;钻石操作符也可以依次读取打开的文件,如下:
open FILE, "a.txt"
while(defined(<FILE>))#依次读取a.txt的每一行
{
print "$_";
}
close FILE;
chomp
前面提到过不管是 <STDIN>还是<> 在读取输入时默认都是会读取换行符的,而chomp 用于去掉字符串或者读取到的输入的一个 换行符;格式如下所示:
chomp(标量);
#不带参数的话,默认参数为默认变量$_
注意,这个函数是在原处修改字符串,但这个函数有自己的返回值:
- 如果能去掉换行符,则返回移除的字符数,也就是数值1。这是个没什么用的返回值,因为我们都已经知道了;
- 如果没有换行符,则返回数值0;
- 如果结尾有两个换行符,则只去掉一个;
一般来说,while循环中用<>或<STDIN>读取输入后(也包括open关键字打开文件再读取行的情况),第一行要做的就是去除掉行尾的换行符,所以大多采用如下的通用格式:
while (<FILE_HANDLE>)
{
chomp;
commands;
}
while (<STDIN>)
{
chomp;
commands;
}
perl的输出函数
print say printf sprintf 都可以输出字符串到显示器,四个函数的应用场景不同;
print和say 的区别在于: print 不带换行,say 自带换行;
printf用于格式化输出,用法与C语言相同;
对于常用的 print/say ,这里有一点需要注意:
print (3+4)*4
上面返回的是7而不是28,这是怎么计算的?
Perl中很多时候是可以省略括号的,这往往让我们忘记括号的归属,而Perl中又有上下文的概念,在不同上下文执行同一个操作的结果是不一样的
- print不加括号的时候,它需求的参数是一个列表上下文,它后面的所有内容都会被print输出,也就是说print 后面的所有字符串都会被依次输出
- print加括号的时候,它只会输出括号中的内容
所以上面的语句等价于:
(print (3+4))*4
它首先执行 print(7),然后拿到print的返回值1,将其乘以4,由于没有赋值给其它变量,所以这个乘法的结果被丢弃;
另外,由于print/say不使用括号的时候,它们会输出其后面的列表,所以有以下技巧:
- 与cat 类似,可以用 print <> 来读取并打印文件的所有内容;
- 与 sort 类似,可以用 print sort <> 来对文件内容进行排序;
下面来看一个printf 的例子:
my @items = qw/aaa bbb ccc/;
printf "%d\n"x@items, @items;
打印结果如下:
aaa
bbb
ccc
可以看到,perl中存在和python 类似的操作,通过 x 来将字符串复制若干遍;
perl 命令行参数
perl的命令行参数默认存进数组 @ARGV 中,既然是数组,那么可以通过 $ARGV[index] 的方式访问、遍历甚至修改数组元素;如下:
perl test.pl a b c
a b c 会依次存入 ARGV[0],ARGV[1],ARGV[2]中;默认的,perl 会将这些参数视为 perl程序的数据输入源,也就是说依次将它们当成文件读取;
需要区分ARGV变量和ARGV数组:
- $ARGV 表示命令行参数列表中当前被处理的文件名
- @ARGV 表示命令行参数数组
- $ARGV[n] 表示命令行参数数组的元素
- ARGV 表示<>当前正在处理的文件句柄