Perl One-Liners之参数-p和-n
【上集回顾】: 上一次提到了-e参数,一般在使用perl的单行程序时都会加上-e参数。-e参数就是将后面引号内的内容当作perl代码执行。
这一次来说一说另外两个常见的-p和-n参数,这两个参数与输入输出相关
简介
-p:将参数当作文件读取进来,并且每次读取一行遍历文件,并把执行-e参数之后的perl代码部分得到默认变量$_打印到标准输出中(可以是屏幕也可以进入管道)。
-n:将参数当作文件读取进来,并且每次读取一行遍历文件。
两个看起来共性有点大,那有什么区别呢?
在之前先来看一个例子吧!
例子
首先新建一个文件 123.txt
里面的内容为:
1 | the string is hello |
我怎么知道是不是逐行读取的呢?
在123.txt
所在位置右键,打开git bash here
或者打开终端cd
到当前目录
输入:
1 | perl -n -e '++$n;print "$n $_"' 123.txt |
可以看到程序部分执行了三次,文件是逐行读取的。
-p参数
- 示例1
1 | # 比如我想让含有字符串string的行打印出来 |
可以看到和原来的文件是没有什么两样的
- 示例1.1
1 | # 输入 |
第一行和之前的结果不一样了
但是假如说我想的是“只要那些有string这样字眼的行输出出来呢”?
于是我就想可不可以这样写:
- 示例2
1 | # 输入 |
可以看到文件第一行输出了两次,也就是说
-p
参数不管你的代码中有什么判断语句来控制输出,每读取一行都会输出一下$_
,这个与代码中的print不会合并,它不管究竟有没有print
那它是输出的什么呢,输出什么时候的$_
呢?
来这样试一下:
- 示例3
1 | perl -p -e 's/string/number/;s/hello/world/' 123.txt |
传进来文件第一行的变量$_
在perl代码中其实变换了两次
1 | 最开始时候:the string is hello |
可以看到,-p
参数每次输出的$_
的值是它从代码执行最后的值
再来调戏一下$_
:
- 示例4
1 | perl -p -e 'if(m/string/){$_ = "foo\n"}' 123.txt |
第一行已经变了,就是说$_
是可以被改变,甚至改变巨大都可以
那为了刚才我们的目标,可以这样:
- 示例5
1 | # 如果不能匹配到 string 就将变量$_设置为空字符串,类似于清空 |
哈哈!没难倒我们!达到目标了!
你有没有感觉不太好呢!这里判断条件倒是很简单,所以可以这样做,假如判断条件多了,代码量多了,每次都要这样来思考不是有点不顺吗?
这样吧,开门见山,有请-n
参数登场
-n参数
先来按照-p
的路子试一试-n
- 示例6
1 | # 我想要的是将含有string字符串的行打印出来 |
是的,什么都没有,的确是这样,不是我码字把它码掉了。其实有了上面的-p
的说明,这里-n
已经比较明确了,它其他方面的和-p
一样,但是他不会输出$_
,也就是说程序默认不会输出任何东西(当然不包括错误信息在内)
于是上面的问题就可以这样解了:
- 示例7
1 | perl -n -e 'if(m/string/){print $_}' 123.txt |
到了这里大家应该明白了-p和-n的区别,其实对于命令行来说,-p和-n用的都挺多的,就看你需要什么,怎么做起来更快,就选哪一个。
问题
问:假如我读取文件不想要后面的换行符出现,输出的时候我自己加换行符,怎么做?
答:其实和写perl脚本一样,其实可以这样做
1 | perl -n -e 'chomp;if(/string/){print "$_\n"}' 123.txt |
也就是加一个chomp。其实除了这种方式,还有一种加上参数-l
可以达到先自动chomp
,之后自动在$_
后面加上\n
然后输出
问:这个-p和-n参数的每行读取文件怎么和那个钻石操作符<>
一样啊!
答:的确是这样的
1 | # 平常写perl脚本我们一般写 |
这样看来单行程序在写较短程序上比直接去写perl脚本来的快,来的节省
在这里再引申一下
如果我有一个fasta文件,假设名称为fasta.fasta 内容为
1 | >cox1 |
假如在命令行中这样输入
1 | perl -p -e 'if(/^>/){$_ = <> || ""}' fasta.fasta |
输出为
1 | ATGCGATCGTAGCATGCTAGCTACG |
问:为什么我一直没有输出啊!
答:你是不是把参数顺序写反了
- 错误写法
perl -e -p 'print if /string/' 123.txt
perl -e -n 'print if /string/' 123.txt
perl -ep 'print if /string/' 123.txt
- 正确写法
perl -p -e 'print if /string/' 123.txt
perl -pe 'print if /string/' 123.txt
第三种情况虽然两个参数并在一起写了,可是有先后顺序,其实第三种就是第一种的写法。也就是说引号对引起来的代码需要靠近-e,而且-e参数一般放在所有参数最后一个
perl读取文件的方式
- 放在命令行代码块的末尾
1 | perl -n -e 'print $_' 123.txt |
- 结合Linux工具
1 | cat 123.txt | perl -n -e 'print $_' |
- 使用文件句柄
1 | perl -e ' |