【问题标题】:Replace a string from a set of string in a file - SED从文件中的一组字符串中替换一个字符串 - SED
【发布时间】:2018-05-07 11:28:12
【问题描述】:

我在替换来自文件中的一组字符串的字符串时遇到问题 所以这就是我希望我的脚本运行的方式

我有这些文件: macadd.file

00:90:8F:56:63:88
00:90:8F:56:63:77
00:90:8F:56:63:6B
00:90:8F:56:63:86
00:90:8F:56:63:87
00:90:8F:56:64:E5

测试文件

host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }

所以我尝试使用

替换它
for i in $(cat macadd); do sed -i "s/00:90:8F:56:63:88/$i/g" test;done

但是,它只从 macadd.file 中的第一个字符串更改它 您可以看到 00:90:8F:56:63:88 是那里的所有条目。我想发生的事情是这样的,结果:

host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:77; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:6B; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:86; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:63:87; fixed-address 192.168.10.29; }
host Accountant { hardware ethernet 00:90:8F:56:64:E5; fixed-address 192.168.10.29; }

【问题讨论】:

标签: linux bash shell loops sed


【解决方案1】:

第一次遍历导致sed 将所有命中替换为第一个值。如果这不是您想要的,请使用不同的 sed 脚本。可能是这样的:

sed 's!.*!s/00:90:8F:56:63:88/&/;n;!' macadd.file

这会在标准输出上生成一个新的 sed 脚本,您可以将其传递给 (... pause ...) sed

sed 's!.*!s/00:90:8F:56:63:88/&/;n;' macadd.file |
sed -f - -i test.file

这是您第一次看到它时要求稍高的模式(sed -f - 并非在所有平台上都适用)但是一旦您明白了,让脚本生成脚本对于您的工具箱来说是一个非常强大且多功能的工具.

... 在 MacOS 上,您不能使用 sed -f - 并且 -i 需要一个参数。如果你有 Bash(或其他一些支持进程替换的 shell),这里有一个解决方法:

sed -f <(sed 's!.*!s/00:90:8F:56:63:88/&/;n;!' macadd.file) -i '' test.file

【讨论】:

    【解决方案2】:

    直接使用 AWK

    awk 'NR==FNR{ a[NR]=$1; next }
         a[FNR]{ sub("00:90:8F:56:63:88", a[FNR]) }1' macadd tesfile > tmp_f && mv tmp_f testfile
    
    • NR - 到目前为止读取的输入记录总数
    • FNR - 到目前为止从当前输入文件中读取的记录数

    最后的testfile内容:

    host Accountant { hardware ethernet 00:90:8F:56:63:88; fixed-address 192.168.10.29; }
    host Accountant { hardware ethernet 00:90:8F:56:63:77; fixed-address 192.168.10.29; }
    host Accountant { hardware ethernet 00:90:8F:56:63:6B; fixed-address 192.168.10.29; }
    host Accountant { hardware ethernet 00:90:8F:56:63:86; fixed-address 192.168.10.29; }
    host Accountant { hardware ethernet 00:90:8F:56:63:87; fixed-address 192.168.10.29; }
    host Accountant { hardware ethernet 00:90:8F:56:64:E5; fixed-address 192.168.10.29; }
    

    【讨论】:

    • 对于MAC地址数是否低于测试文件行数,OP不清楚。我假设它们应该以旋转方式更换;这个脚本只是用完了 MAC 地址,如果目标文件较长,则用空字符串替换它们。 (易于修复;只需在索引下标中添加一个模计算。)
    • @tripleee,如果目标文件“更长”,则不会进行替换,这是显而易见的
    • 我认为这很明显这是不可取的,但无论如何,用这个答案很容易选择一种或另一种行为。
    【解决方案3】:

    如果 MAC 地址在 test.file 中并不总是相同 你可以试试:

    sed -E '
    s/((([[:xdigit:]]){2}:){5}[[:xdigit:]]{2})(.*)((([[:xdigit:]]){2}:){5}[[:xdigit:]]{2})(.*)/\4\1\8/
    # ((([[:xdigit:]]){2}:){5}[[:xdigit:]]{2}) catch the MAC addresse
    s/^\t//
    # remove tab which come from paste
    /^((([[:xdigit:]]){2}:){5}[[:xdigit:]]{2})/d
    # remove lines if maccad.file have more lines than test.file
    '<<< $(paste macadd.file test.file)>test.file
    

    【讨论】:

      【解决方案4】:

      实际上,对于您在问题中提出的示例,没有替换的内容会更加简单明了:

      <macadd.file xargs -I{} printf "host Accountant { hardware ethernet %s; fixed-address 192.168.10.29; }\n" {}
      

      即输入文件中的每一行调用 printf 仅替换 MAC 地址部分。当你有更多的 MAC 地址和更多的结果 IP 地址时,麻烦就来了。

      【讨论】:

        猜你喜欢
        • 2020-01-12
        • 2017-11-14
        • 2016-05-23
        • 2011-12-21
        • 2011-07-01
        • 2018-05-19
        • 2012-10-09
        • 2012-09-13
        • 2019-03-21
        相关资源
        最近更新 更多