新手学习Linux和perl:
我想(a)搜索替换字符串,(b)匹配文件名模式.myfile。,(c) 在子目录中递归查找,(d) 打印行号、文件名、原始行和更改的行。
我正在寻找使用sed
和perl
语法的两个版本。我在这找到了一个起点问题但:
第一个:sed
需要:添加模式匹配语法.myfile。,递归搜索,打印行号,并摆脱w /dev/fd/2
--我不知道它的作用,我想将结果打印到终端,而不是输出文件。注意:我在 mac OS 上使用 Visual Studio 终端):
find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;
输出:
./file1:
foo stuff >>> bar stuff
more foo >>> more bar
./file2:
./file3:
foo first >>> bar first
third: foo >>> third: bar
第二:perl:
需要:添加模式匹配语法.myfile。,以及递归搜索。另外,输出的行号也是$.
错误的。对于第一个文件来说它是正确的,但它会不断计数并且在搜索更多文件时不会重置(请参阅用于输出)。
$ find . -type f |
xargs perl -i -ne '$was=$_; chomp($was);
s/abc/def/ && print STDERR "$ARGV($.): $was : $_"'
./foo(1): fooabcbar : foodefbar
答案1
这些代码会就地修改文件(好吧,如果-p
使用 ; 代替-n
; -n
,则适用于 perl 代码,这会导致文件被清空),同时将修改的内容打印到 stderr (通过w /dev/fd/2
或)。print STDERR
然而,这find . | xargs
是错误的,因为 的输出find
与 期望的输入格式不兼容xargs
。此外,perl
包含$.
当前输入行号的 in 不会在文件之间重置,除非您关闭ARGV
每个文件末尾的句柄,因此它应该是:
find . -name '*.myfile' -exec perl -i -pe '
chomp($was = $_);
print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
close ARGV if eof' -- {} +
对于sed
,不确定 macos 支持/dev/fd/2
stderr,但即使在基于 Linux 的系统上(macos 不是 Linux 顺便说一句),使用w /dev/fd/2
也会是错误的,除非 stderr 转到特定类型的文件,例如管道或终端设备。-printf
特定于 GNU 实现,find
并且在包括 macos 在内的任何其他实现中都找不到。
同样在 macos 上,sed
就像在它所基于的 FreeBSD 上一样,您需要-i ''
而不是-i
进行就地编辑。sed
必须=
报告行号,但您不能对其进行任何操作,例如将其嵌入字符串中。在符合 POSIX 标准的实现中,它也不会在文件之间重置sed
(在 GNU 的情况下sed
,它会在使用-i
或-s
非标准选项时重置)。
请注意,它将编辑(和替换)每个.myfile
文件,甚至那些不包含abc
.你可以用以下方法解决这个问题:
find . -name '*.myfile' -type f -exec grep -l --null abc {} + |
xargs -0 perl -i -pe '
chomp($was = $_);
print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
close ARGV if eof' --
Macos上grep
有一个基于某些旧版本 GNU 的 API grep
(因为它曾经有 GNUgrep
或至少是它所基于的 FreeBSD),所以你会在其中找到一些 GNU 选项,其中包括--null
(尽管不是-Z
简短的变体) )。它xargs
也有 GNU 的-0
选项,但不幸的是还没有这个选项,所以如果找不到任何文件,-r
你会得到一个错误。perl
find
如果您不想修改适当的文件,而只想打印匹配项以及它们将如何被替换,那么就会变成:
find . -name '*.myfile' -type f -exec perl -nle '
$was = $_;
print "$ARGV($.): $was : $_" if s/abc/def/;
close ARGV if eof' -- {} +
没有-i
nplace,-n
要在每个周期结束时打印该行n
;自动执行on (并被告知添加on 输出)。我们在 stdout 而不是 stderr 上打印(将整个命令重定向到 stderr ,如果您希望它转到 stderr ;在终端中交互式 shell 的提示下,stdout 和 stderr 都应该转到终端,所以它不应该做出改变)。p
-l
chomp
$_
print
\n
>&2