perl -pi -e 在 cygwin 上自动删除 .bak

perl -pi -e remove .bak automatically on cygwin

在 Cygwin 下,perl -pi -e 将始终保存 .bak 个文件。我不完全明白为什么,但我想摆脱它。

我平时用Perl pie是这样的:

git ls-files | egrep '[.](asm|c|h|inc)' | xargs perl -pi -e 's/foo/bar/'

然后我需要执行这个:

git ls-files | egrep '[.](asm|c|h|inc)' | sed 's/$/.bak/' | rm -f 

我试图创建一个函数,但 xargs 不喜欢 bash 函数。有没有办法轻松地将我的两个命令组合在一起?

当然我更愿意使用 findls 来获取我的文件。

实际上,对我来说可能最有效的解决方案是为 perl -pi -e 声明一个别名,它会自动删除不需要的 .bak 文件。

有什么建议吗?

您可以 运行 在 xargs 中编写 Bash 脚本。

git ls-files '*.asm' '*.[ch]' '*.inc' |
xargs bash -c 'perl -pi -e "s/foo/bar/" "$@"; for f; do rm -f "$f.bak"; done' _

另请注意我如何将 egrep 重构为 git ls-files

您可以使用 perl 删除 .bak 个文件,

.. | xargs perl -i.bak -pe 'BEGIN{ @d=@ARGV } s/foo/bar/; END{ unlink map "$_$^I", @d }'

如果你可以使用find来执行这个命令,你可以使用Perl模块File::Find——Perl 5中的核心模块——用Perl程序替换整个命令。

如何在程序文件中而不是单行代码中使用它的示例:

use strict;
use warnings;
use File::Find;
use autodie;      # file operation failures are fatal
use File::Copy;   # for move()

my $dir = shift;  # starting dir
my @files;
find(
    sub { 
        if (/\.(?:asm|c|h|inc)$/) { 
            push @files, $File::Find::name; 
        }
    }, $dir);

for my $file (@files) {
    open my $fh, "<", $file;
    open my $tmp, ">", "$file.bak";
    while (<$fh>) {
        s/foo/bar/;
    } continue { print $tmp $_ }
    close $tmp;
    close $fh;
    move "$file.bak", $file;
}

您也可以将替换作为参数传递,而不是对其进行硬编码,例如

my ($search, $replace, $dir) = @ARGV;  

然后在循环内使用变量:

s/$search/$replace/;

您可以调用它而不是其他带有管道的命令,如下所示:

perl program.pl foo bar /some/dir

在 unix 系统上,

perl -i -pe'...' file

基本相同
exec 3<file
rm file
perl -pe'...' <&3 >file

rm file 删除文件名,但该文件会匿名保留,因为它有一个打开的句柄。 Windows 不支持,所以 Windows 不支持 -i

事实证明,我发布的代码 也适用于 cygwin!

$ echo foo >file

$ exec 3<file && rm file && perl -pe's/foo/bar/' <&3 >file

$ cat file
bar

无论出于何种原因,Cygwin 构建的 Perl 不依赖于对 unix 功能的模拟,并且 -i 的行为与 -i.bak 相同(在 Windows 上有效)。

如果你真的想避免使用临时文件,你可以使用以下方法:

perl -e'
   for $ARGV (@ARGV) {
      open(my $fh, "<", $ARGV)
         or warn("open $ARGV: $!"), next;

      unlink($ARGV)
         or warn("unlink $ARGV: $!"), next;

      open(STDOUT, ">", $ARGV)
         or warn("open $ARGV: $!"), next;

      while (<$fh>) {
         s/foo/bar/;
         print;
      }
   }
'