【问题标题】:Replacing a repeating number in a file with random numbers用随机数替换文件中的重复数字
【发布时间】:2015-06-02 11:04:12
【问题描述】:

我想使用“sed”在文件的每一行中用随机数替换所有出现的数字。 例如,如果我的文件每行都有数字 892,我想用 800 到 900 之间的唯一随机数替换它。

输入文件:-

temp11;djaxfile11;892  
temp12;djaxfile11;892  
temp13;djaxfile11;892  
temp14;djaxfile11;892  
temp15;djaxfile11;892

预期的输出文件:-

temp11;djaxfile11;805  
temp12;djaxfile11;846  
temp13;djaxfile11;833  
temp14;djaxfile11;881  
temp15;djaxfile11;810

我正在尝试以下方法:-

sed -i -- "s/;892/;`echo $RANDOM % 100 + 800 | bc`/g" file.txt

但它正在用 800 到 900 之间的单个随机数替换所有出现的 892。

输出文件:-

temp11;djaxfile11;821  
temp12;djaxfile11;821  
temp13;djaxfile11;821  
temp14;djaxfile11;821  
temp15;djaxfile11;821

您能帮忙更正我的代码吗?提前致谢。

【问题讨论】:

  • 您必须绝对在 sed 中执行此操作吗?在 Python 或 PERL 中会很容易。
  • 所以你的文件永远不会超过 101 行,对吗?而且这个数字实际上并不是随机的,因为它至少部分是由前面的几行决定的?
  • 我的文件实际上有数千条记录。 Wintermute 给出的 sed 建议运行良好,尽管需要一些时间。从性能的角度来看,awk 更快吗?有什么想法吗?

标签: string bash sed


【解决方案1】:

使用 GNU sed,您可以执行类似的操作

sed '/;892$/ { h; s/.*/echo $((RANDOM % 100 + 800))/e; x; G; s/892\n// }' filename

...但是使用 awk 会更明智:

awk -F \; 'BEGIN { OFS = FS } $NF == 892 { $NF = int(rand() * 100 + 800) } 1' filename

为确保随机数唯一,修改awk代码如下:

awk -F \; 'BEGIN { OFS = FS } $NF == 892 { do { $NF = int(rand() * 100 + 800) } while(!seen[$NF]++) } 1'

用 sed 来做这件事对我来说太疯狂了。 请注意,仅当文件中最后一个字段为 892 的行数少于 100 行时,这才有效。

说明

sed 代码读取

/;892$/ {                              # if a line ends with ;892
  h                                    # copy it to the hold buffer
  s/.*/echo $((RANDOM % 100 + 800))/e  # replace the pattern space with the
                                       # output of echo $((...))
                                       # Note: this is a GNU extension
  x                                    # swap pattern space and hold buffer
  G                                    # append the hold buffer to the PS
                                       # the PS now contains line\nrandom number
  s/892\n//                            # remove the old field and the newline
}

awk 代码要简单得多。使用-F \;,我们告诉 awk 以分号分隔行,然后

BEGIN { OFS = FS }  # output field separator is input FS, so the output
                    # is also semicolon-separated
$NF == 892 {        # if the last field is 892
                    # replace it with a random number
  $NF = int(rand() * 100 + 800)
}
1                   # print.

修改后的awk代码替换

$NF = int(rand() * 100 + 800)

do {
  $NF = int(rand() * 100 + 800)
} while(!seen[$NF]++)

...换句话说,它保留了一张它已经使用过的随机数表,并一直在绘制数字,直到它得到一个它以前从未见过的数字。

【讨论】:

  • 非常感谢!我尝试了您建议的 sed 代码,它运行良好。我将尝试 awk 选项并探索哪种方法是最快和最好的。
  • 回答了我自己(现已删除)的问题:(1) awk 数组将接受字符串键,因此这应该适用于字符串替换和 (2) 如果您遇到奇怪的行为并使用 system调用,它可能会返回状态码并打印(不返回)输出。
猜你喜欢
  • 2022-07-25
  • 2012-06-24
  • 2020-08-14
  • 1970-01-01
  • 2017-05-20
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多