用其他数字替换长列表中的数字

时间:2018-03-14 17:26:00

标签: bash loops sed

我正在尝试通过其他数字更改长列表中的数字。例如,

cat inputfile.txt
A 254 B 456 C 546
D 548 E 548 F 458

A 244 B 416 C 566
D 148 E 558 F 428

我想通过在其上添加一个百分比来改变B的值。例如,我想将第一个数组中的B增加3%,将下一个中的b增加2%,如下所示:

 cat inputfile.txt
A 254 B 469.68 C 546
D 548 E 548 F 458

A 244 B 424.32 C 566
D 148 E 558 F 428

我尝试了以下但是没有用。

 a=(456  416)
b= (469.68 424.32)
for i in ${a[@]};
for j in ${b[@]}; do
sed -i -- "s/${i}/${j}" inputfile.txt
done

1 个答案:

答案 0 :(得分:4)

有很多问题。

cat inputfile.txt
A 254 B 456 C 546
D 548 E 548 F 458

A 244 B 416 C 566
D 148 E 558 F 428

a=(456  416)
b= (469.68 424.32)
for i in ${a[@]};
for j in ${b[@]}; do
sed -i -- "s/${i}/${j}" inputfile.txt
done

A) 你对b的任务失败了。任务周围没有空间。

b)替代模式尚未结束:

sed -i -- "s/${i}/${j}/" inputfile.txt

c)现在它应该以不为空的值运行,但是这将尝试用469.68替换456然后用424.32替换。这不起作用,因为该值已更改为469.68。然后它将尝试用两个值更改每个416。

a=(456  416)
b=(469.68 424.32)
for i in ${a[@]};
for j in ${b[@]}; do
  sed "s/${i}/${j}/" inputfile.txt
done

您有两个相应的值需要同步,因为您想要将第一个值替换为秒。所以你必须迭代一次,并通过索引:

max=${#a[@]}
for i in $(seq 0 $((max - 1))); do
  sed "s/${a[$i]}/${b[$i]}/" inputfile.txt
done

我从sed中删除了-i进行测试。

最后一个问题是,可能存在数字冲突,例如将1456中的456替换为4169中的469.68或416和424.32。

为了防止这种情况发生,我们可以在匹配的数字前加上一个空格,并在最后匹配空白或行尾的边界:

  sed "s/ ${a[$i]}\b/ ${b[$i]}/" inputfile.txt

\ b-notation具有我们不需要抓住它的优势(超过[$]),将其推回到值中,它是非消费的。

a=(456  416)
b=(469.68 424.32)
max=${#a[@]}
for i in $(seq 0 $((max - 1))); do
  sed -i "s/ ${a[$i]}\b/ ${b[$i]}/" inputfile.txt
done

我不知道你的a和b值的来源 - 也许我的后续推理并不适用,但as和bs在数组中的存储似乎并不是最佳的。它们必须具有相同的长度,但不能保证。您可以对其进行测试,但如果丢失了一个值,则很难找到它的位置,删除相应的b值。

不结合所有原文和所有替换,绑定对似乎是更好的主意:

a=(456 469.68)
b=(416 424.32)

但那距离最终的sed-expression不远,那就是:

a="s/ 456\b/ 469.68/"
b="s/ 416\b/ 424.32/"

现在这个问题有点冗长,但我们保存完整的循环:

  sed -i "${a};${b}" inputfile.txt

并且输入文件只需要读取一次,现在可以在没有-i的情况下完成测试。

如果你碰巧有海量数据,你可以生成如下文件:

s/ 456\b/ 469.68/
s/ 416\b/ 424.32/

并将其命名为numcorrect.sed,并通过以下方式调用:

sed -f numcorrect.sed inputfile.txt