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 函数。有没有办法轻松地将我的两个命令组合在一起?
当然我更愿意使用 find
或 ls
来获取我的文件。
实际上,对我来说可能最有效的解决方案是为 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;
}
}
'
在 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 函数。有没有办法轻松地将我的两个命令组合在一起?
当然我更愿意使用 find
或 ls
来获取我的文件。
实际上,对我来说可能最有效的解决方案是为 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;
}
}
'