我有以下三个文件,内容如下:
1.txt 2.txt 3.txt
------------------------------------------
1.txt 2.txt 3.txt
text sample text sample text sample
sample text sample text sample text
在使用单个bash命令行和perl代码编写代码以将所有三个文件中的单词“sample”替换为单词“changed”时,我意识到为了修复使用以下代码时遇到的问题,我错过了理解bash和/或perl的一些重要部分:
$ perl -pe 's/sample/changed/' < 1.txt 2.txt 3.txt > 1a.txt 2a.txt 3a.txt
执行上面一行的结果是:
1a.txt 2a.txt 3a.txt
------------------------------------------
2.txt NOT NOT
text changed CREATED CREATED
changed text
3.txt
text changed
changed text
为了解决以下问题:
Can't open 2a.txt: No such file or directory, <> line 6.
Can't open 3a.txt: No such file or directory, <> line 6.
我已将代码更改为:
$ perl -pe 's/sample/changed/' < 1.txt 2.txt 3.txt > 1a.txt > 2a.txt > 3a.txt
其运行没有任何抱怨,但作为结果给出:
1a.txt 2a.txt 3a.txt
------------------------------------------
EMPTY EMPTY 2.txt
FILE FILE text changed
changed text
3.txt
text changed
changed text
而不是我所期望的
1a.txt 2a.txt 3a.txt
------------------------------------------
1.txt 2.txt 3.txt
text changed text changed text changed
changed text changed text changed text
在这方面,我的问题是:
我在理解bash和perl是如何工作的,以便提供正确的命令来执行替换时,我遗漏了什么信息?尤其是,我遗漏了什么信息,无法理解文件1.txt
的结果是如何不以两种大写形式写入输出文件的?
5条答案
按热度按时间wpx232ag1#
缺失的信息:重定向只接受一个文件。
如何修复代码:使用
-i
标志。它将“原地”更改文件,保留1. txt ~、2. txt ~和3. txt ~作为备份。
cwdobuhd2#
等于
显然错了。
因为只有一个标准输出。
等于
显然错了。
你可以用
如果确实需要
1a.txt
,可以使用以下命令:或
atmip9wb3#
你需要理解文件描述符的概念。默认情况下,shell和大多数程序将输出发送到FD 1,将stderr发送到FD 2,并从FD 0读取输入。简化后的重定向就是分配这些文件描述符所代表的文件或设备。如果你指定了多个
>
,那么只有最后一个文件描述符才能被FD 1有效地表示。至少在概念上是这样。重定向也是由shell管理的,而不是由被调用的程序管理的。如果希望单独处理
1.txt
、2.txt
和3.txt
,并将结果保存在它们的“a”对应项上,可以使用循环。我认为这也可以在Perl内部完成,但我不了解Perl。
tez616oj4#
您遗漏的信息以及导致您混淆的信息是对shell重定向缺乏正确的理解。
在此情况下,必须理解:
*重定向是一个独立的命令/指令,不需要命令行上的任何其他内容即可执行。因此,**独立的
~ $ > fname.ext
**可以*shell重定向由shell管理,而不是由被调用的程序管理
*重定向发生在单个指令中的何处并不重要。因此
> txt.1 echo "sample text"
的作用与echo "sample text" > txt.1
相同*重定向仅采用一个文件因此
< 1.txt 2.txt 3.txt
仅使1.txt
文件的内容在stdin
上可用(不包括2.txt和3.txt的内容)*重定向发生(执行)在其他操作之前
> file.ext
(也包括单独出现的位置)将导致:file.ext
不存在,则创建它file.ext
(如果存在)(使其为空/无内容)stdout
分配给文件现在,与所有上述牢记让我们解释它是如何来你在你的问题中描述:
执行时的原因
未创建文件2a.txt和3a.txt的原因是重定向仅采用一个文件,即
1a.txt
,因此将2a.txt和3a.txt作为参数传递给perl,perl随后抱怨它们不存在。执行时的原因
文件
1.txt
被pearl从考虑中跳过是重定向< 1.txt
,它从传递给pearl的命令行参数列表中取出1.txt
文件。将stdin分配给1.txt在这里没有效果,因为pearl将不使用stdin,因为它发现2.txt和3.txt作为文件使用作为输入,因此忽略stdin。1a.txt和2a.txt为空的原因是重定向
> 1a.txt
和> 2a.txt
创建/截断了这些文件。3.txt文件包含perl脚本输出,因为命令行是由bash从左到右评估的,结果是对stdout的最后一次分配是将3a.txt文件分配给它,然后对stdout的所有perl输出都转到3a.txt。
ac1kyiln5#
主要的问题,关于重定向,在这个例子中,已经得到了回答。然而,如果有更多的事情要做,在shell中处理重定向可能会变得混乱,我想提醒的是,一旦Perl程序 * 是 * 无论如何,它是简单的,也处理它的文件。
因此,读取和处理输入文件以及写入相应的输出文件都是用Perl一个接一个地完成的。
这使用一个库来方便地读写文件,我使用Path::Tiny。还有其他库可以完成这些任务,或者可以手工完成(简单但更冗长)。
一些细节
@ARGV
包含命令行参数,因此这里是要处理的文件名Path::Tiny
库通过为现有文件或新(要写入的)文件创建对象path($filename)
并对其应用方法来操作path($_)->slurp
将名为$_
的文件(来自@ARGV
)读入一个字符串,正则表达式可以直接绑定到该字符串/r
时,正则表达式返回经过处理的字符串path("new_$_")->spew(...)
文件中