我正在使用sed
来查找和替换文件中的项目:
sed -i "s/$pattern/$replacement/g" ./file.txt
这将替换文件中的所有外观。
有没有办法随机替换整个文件中的一个事件?
答案 0 :(得分:1)
使用perl
,您可以使用rand
功能:
perl -lane '
while ($n = rand @F) {
if ($F[$n] eq "pattern") {
$F[$n] = "replacement";
print "@F";
last
}
}
' file
根据this帖子,shell中的变量可以在perl的%ENV
哈希中找到。使用bash
(以及其他一些shell),您需要采取额外的步骤“导出”shell变量,以便子进程可以看到它。
所以在你的情况下,你必须这样做:
pattern="mypattern"
replacement="myreplacement"
export pattern
export replacement
perl -lane '
while ($n = rand @F) {
if ($F[$n] eq "$ENV{pattern}") {
$F[$n] = "$ENV{replacement}";
print "@F";
last
}
}
' file
当然,这将打印到STDOUT,因此如果您需要进行文件内更改,可以使用-i
命令行选项或将输出重定向到另一个文件。
或者,如果这不是bash
脚本的一部分,并且您希望在perl
中执行此操作,则可以在命令行上传递模式和替换。
perl -lane '
BEGIN { ($patt, $repl) = splice @ARGV, 1 }
while ($n = rand @F) {
if ($F[$n] eq $patt) {
$F[$n] = $repl;
print "@F";
last
}
}' file "pattern" "replacement"
这将每行随机更换一次。如果您希望每个文件执行一次,请发表评论,我将添加该版本。
答案 1 :(得分:1)
使用perl
:
#!/usr/bin/env perl
use List::Util qw(shuffle);
use strict;
use warnings;
my $search = shift @ARGV;
my $repl = shift @ARGV;
my @lines;
my @matches;
while (<>) {
push(@lines, $_);
push(@matches, $.) if /$search/;
}
my @shuffled = shuffle(@matches);
my $index = shift @shuffled;
if ($index) {
$lines[$index - 1] =~ s/$search/$repl/;
}
print @lines;
用法:
perl script.pl string replacement file
答案 2 :(得分:1)
真正随机执行此操作的唯一方法是首先清点PATTERN的所有位置。否则就无法给予适当的加权。
以下通过脚本进行替换。它只替换当前特定行上模式的第一个引用:
use strict;
use warnings;
use autodie;
my $file = '...';
my $pattern = qr/.../;
my $replace = '...';
my @linenums;
local @ARGV = $file;
while (<>) {
push @linenums, $_ if $_ =~ $pattern;
}
my $linenum = $linenums[rand @linenums];
local @ARGV = $file;
local $^I = '.bak';
while (<>) {
s/$pattern/$replace/ if $. == $linenum;
print;
}
# unlink "$file$^I"; # Optionally Delete backup
如果您想让一个模式不止一次出现在线上,可以使用以下增强功能:
use strict;
use warnings;
use autodie;
my $file = '...';
my $pattern = qr/.../;
my $replace = '...';
my @linenums;
local @ARGV = $file;
while (<>) {
my $count = () = $_ =~ /$pattern/g;
push @linenums, {line => $., num => $_} for 0 .. $count - 1;
}
die "No matches found" unless @linenums;
my $pick = $linenums[rand @linenums];
local @ARGV = $file;
local $^I = '.bak';
while (<>) {
if ($. == $pick->{line}) {
s/(?:$pattern.*?){$pick->{num}}\K$pattern/$replace/;
}
print;
}
# unlink "$file$^I"; # Optionally Delete backup