【问题标题】:Replacing numbers in a long list by other numbers用其他数字替换长列表中的数字
【发布时间】:2018-08-23 08:40:03
【问题描述】:

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

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

【问题讨论】:

    标签: bash loops sed


    【解决方案1】:

    存在多个问题。

    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
    

    一) 您对 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 替换为 469.68 或将 416.02 中的 416 替换为 424.32。

    为了防止这种情况发生,我们可以在要匹配的数字之前放置一个空格,并在末尾放置一个匹配空格或行尾的边界:

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

    \b 表示法的优点(优于 [$])我们不需要捕获它,将它推回值中,它是不消耗的。

    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 表达式不远了,那就是:

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

    现在这有点冗长,但我们将循环保存完整:

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

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

    如果你碰巧有海量数据,你可以像这样生成一个文件:

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

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

    sed -f numcorrect.sed inputfile.txt 
    

    【讨论】:

    • 我在我的长文件上试过了,但它只改变了第一个匹配项,其他所有内容都保持原样。你知道为什么会这样吗?
    • 我从 sed 命令中删除了 -i,以保持测试文件完整。只是稍后,在最后一步,我把它放回去了。你是使用带有 .sed 文件的最新建议还是哪个?
    • 太棒了。当我删除 -i 时,它在命令屏幕上工作正常,但不在文件内。我添加了 > outputfile 但没有更改。
    • 取决于您是否使用 for 循环,或者例如结束前不久的版本,没有 sedfile 的版本,每个命令都在给定的输入文件名上发出,所以最后一个命令将看到新的输入文件,修改它,然后才写入输出文件。在每个步骤中使用 -i 可以防止这种情况(但不太方便测试)。使用 sedfile,这不会发生,因为写入只发生在处理整个 sedfile 之后。
    • 类似地,像sed 'cmd1;cmd2;cmd3;cmd4;' infile > outfile 这样的命令将在写入之前处理所有命令,但在这里中间更改不会丢失,而是迭代应用,因此在这两种情况下命令的顺序都很重要。
    猜你喜欢
    • 2017-03-06
    • 2017-12-17
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多