报告 sed 更改 + 相应的 perl 语法

报告 sed 更改 + 相应的 perl 语法

新手学习Linux和perl:

我想(a)搜索替换字符串,(b)匹配文件名模式.myfile。,(c) 在子目录中递归查找,(d) 打印行号、文件名、原始行和更改的行。

我正在寻找使用sedperl语法的两个版本。我在这找到了一个起点问题但:

第一个: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/2stderr,但即使在基于 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你会得到一个错误。perlfind

如果您不想修改适当的文件,而只想打印匹配项以及它们将如何被替换,那么就会变成:

find . -name '*.myfile' -type f -exec perl -nle '
  $was = $_;
  print "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' -- {} +

没有-inplace,-n要在每个周期结束时打印该行n;自动执行on (并被告知添加on 输出)。我们在 stdout 而不是 stderr 上打印(将整个命令重定向到 stderr ,如果您希望它转到 stderr ;在终端中交互式 shell 的提示下,stdout 和 stderr 都应该转到终端,所以它不应该做出改变)。p-lchomp$_print\n>&2

相关内容