我有一个文件,其中我必须替换所有单词,如$ xyz,对于它们,我必须替换为以下内容:
$xyz with ${xyz}. $abc_xbs with ${abc_xbc} $ab,$cd with ${ab},${cd}
这个文件也有一些像$ {abcd}这样的词,我不必更改。我正在使用此命令
sed -i’s?\ $([A-Z _] +)?\ $ {\ 1}?g’文件
它可以在命令行上正常工作,但不能在perl脚本中作为
sed -i 's?\$\([A-Z_]\+\)?\$\{\1\}?g' file;
sed -i 's?\$\([A-Z_]\+\)?\$\{\1\}?g' file
我想念什么?我认为添加一些反斜杠会有所帮助。我尝试添加一些但没有成功。
谢谢
在Perl脚本中,您需要有效的Perl语言,就像在C程序中需要有效的C文本一样。在终端sed..中,shell是作为命令来理解和运行的,但是在Perl程序中,它只是一堆单词,而该行sed..不是有效的Perl。
sed..
您可能需要在内部qx()(反引号)或system()使其作为外部命令运行。然后,您确实需要“ 一些反斜杠 ”,这会使事情变得有些挑剔。
qx()
system()
但是,为什么sed要从Perl脚本运行命令?用Perl完成工作
sed
use warnings; use strict; use File::Copy 'move'; my $file = 'filename'; my $out_file = 'new_' . $file; open my $fh, '<', $file or die "Can't open $file: $!"; open my $fh_out, '>', $out_file or die "Can't open $out_file: $!"; while (<$fh>) { s/\$( [^{] [a-z_]* )/\${$1}/gix; print $fh_out $_; } close $fh_out; close $fh; move $out_file, $file or die "Can't move $out_file to $file: $!";
正则表达式使用一个 否定的字符类 ,[^...]以匹配比以外的任何字符{之后$,因此排除了已掺进字。然后,它与字母或下划线序列相匹配,如在问题中一样(可能没有,因为第一个非字母{已经提供了至少一个)。
[^...]
{
$
在5.14+中,您可以使用 非破坏性 /r 修饰符
/r
print $fh_out s/\$([^{][a-z_]*)/\${$1}/gir;
用来返回更改后的字符串(并且原始字符串不变)的右侧print。
print
最后,应使用File ::Temp制作输出文件,并移至原始文件上方。以此方式覆盖原始文件将更改$fileinode的编号;
$file
单行(命令行)版本,易于测试
perl -wpe's/\$([^{][a-z_]*)/\${$1}/gi' file
这仅打印到控制台。更改原始添加-i(就地)或-i.bak保留备份。
-i
-i.bak
出现了一个合理的问题“ 没有更短的方法了 ”。
这是一个使用方便的Path :: Tiny的文件,它不大,因此我们可以将其读取为字符串。
use warnings; use strict; use Path::Tiny; my $file = 'filename'; my $out_file = 'new_' . $file; my $new_content = path($file)->slurp =~ s/\$([^{][a-z_]*)/\${$1}/gir; path($file)->spew( $new_content );
第一行将文件读入一个字符串,在该字符串上进行替换;更改后的文本将返回并分配给变量。然后,带有新文本的变量将覆盖原始变量。
通过将表达式从第一行而不是变量放在第二行,可以将这两行压缩为一个。但是,在一个(复杂)语句中两次打开同一文件并不是完全可靠的做法,因此我不建议您使用这种代码。
但是,由于模块的版本为0.077,您可以很好地执行
path($file)->edit_lines( sub { s/\$([^{][a-z_]*)/\${$1}/gi } );
或使用edit将文件插入字符串并对其应用回调。
因此,这毕竟将其切成一条漂亮的线。
我想补充一点,删节代码行几乎是不值得的,但是如果它干扰了对代码结构和正确性的关注,那肯定会导致麻烦。但是,这Path::Tiny是一个很好的模块,这是合法的,尽管它确实使事情大大缩短了。
Path::Tiny