perl-读取

好久没有学perl了,最近python基础已经学完了。然后在学模块,模块也不是一会能弄懂的,所以就抽空学下perl,因为最近发现shell的一个缺点,就是不能跨平台,而我想写的脚本又要支持windows,所以fighting!

夸奖与吐槽:其实shell是真的好,写习惯了shell,再去用python或者perl时,就觉得有点麻烦。比如说读文件,修改文件,格式化等等cat,grep,sed,awk,wc,tr,xargs等等用的真的是舒服,组合一下,一两行就能搞定很多事情,根本不需要去写个函数啥的。但是在写一些较大的数据处理时,还是会觉得shell有些力不从心,比如说,就我了解的shell,就一个数组,然后没了。在涉及二维数组的时候吧,有时候用的确实麻烦,而且最多写写多进程,也没法写多线程,再一个就是不能跨平台了。好了,本来是perl的,怎么说了这么多shell

读取输入

1
2
3
4
5
6
# 将标准输入读入到标量变量中
$variables = <STDIN>
my $variables = <STDIN>
# 将标准输入读入到hash中
@variables = <STDIN>
my @variables = <STDIN>

使用my表示私有变量。这里使用到了特殊的文件句柄STDIN,而符号<>被称为diamond operation,可以读取所有的输入(包括文件)。而STDIN就是默认的一个标准输入的句柄,句柄可以理解为一个变量,用来操作传入的数据。

scalar读取的就是一个字符串,回车结束。可以用函数chomp()来去掉换行符,括号不是必须的

1
2
3
eg:
chomp($a = <STDIN>);
chomp $a = <STDIN>;

array读取的是一个数组,ctrl+d结束。之前写shell的时候,读取了一些列参数,但是想如果读取到-p(指定进程数),这是就自动加上一个-q参数,表示quiet。但是shell读到的数据并不是一个列表,所以不能将这个参数加上去。除非写个循环转列表,但是有点麻烦,如果用perl来写就简单多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 这么写是无法得到结果的,why?
my @a = <STDIN>;
foreach (@a){
if($_ eq '-p'){
push @a,'-q';
}
}
print(@a);

# 这就体现了去掉换行符的重要性。默认行尾有一个换行符,去掉就行了,只不过输出有点不好看。
chomp(my @a = <STDIN>);
foreach (@a){
if($_ eq '-p'){
push @a,'-q';
}
}
print(@a);

# 当然了,也可以不去掉换行符,我们在匹配时加上不就好了吗,不过要使用双引号
#!/usr/bin/perl
use warnings;
use strict;

my @a = <STDIN>;
foreach (@a){
if($_ eq "-p\n"){
push @a,'-q';
}
}
print(@a);

读取文件

open()函数

open(filehandle,mode,filename)

  • Filehandlethat associates with the file
  • Mode: you can open a file for reading, writing or appending.
  • Filename: the path to the file that is being opened.
mode operand description
read < 只读
write > 文件存在会覆盖,不存在则创建
append >> 追加

close()函数

文件打开之后就需要关闭,如果忘记关闭,perl也会自动关闭。但是这样不好,你懂得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/perl

use warnings;
use strict;

my $filename = './my.pl';

open(FILE, '<', $filename) or die $!;

print("file: $filename\n");

while(<FILE>){
print($_)
}

close(FILE);

句柄要大写,小写的话虽然会执行,但是会报错,而且需要使用引号括起来。

or die $!的写法,如果文件不存在则给出错误提示。

  • First, we used the open() function to open a file for reading.
  • Second, the syntax while() is equivalent to while(defined($_ = ). We read a line from a file and assigned it to the special variable $_. The loop is terminated when the end of the file reached.
  • Third, we displayed each line of the file by passing the variable $_ to the printfunction.*

简化

1
2
3
4
5
6
7
#!/usr/bin/perl
use warnings;
use strict;

while(<>){
print $_;
}

执行它既可以读取标准输入,也可以在后面输入文件名,来读取多个文件内容。

这就是<>diamond operation的魅力。


无论是在perl还是python中,读取一个文件都是需要写函数来获得的,还需要关闭,看着比shell复杂,实则这 告诉了我们一个道理,读取文件本来就不是很随意的一件事,就好像shell写多了,忽略了这一点。我发现不论是我写的脚本,还是其它人写的。完全没有考虑到效率问题。频繁的读取关闭文件是一件很浪费时间的事,因为硬盘的读取速度太慢,这也是为什么我们写的脚本执行慢的一个原因吧。所以要将需要从文件中读取的数据一次性读入内存中,然后使用。