【问题标题】:Using sed to modify line not containing string使用 sed 修改不包含字符串的行
【发布时间】:2013-04-08 17:47:40
【问题描述】:

我正在尝试编写一个 bash 脚本,该脚本使用 sed 来修改配置文件中不包含特定字符串的行。举例说明,我可以...

/some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squash)
/some/file/path2 ipAddress1/subnetMask(rw,sync,no_root_squash,anonuid=-1)
/some/file/path3 ipAddress2/subnetMask(rw,sync,no_root_squash,anonuid=0)
/some/file/path4 ipAddress2/subnetMask(rw,sync,no_root_squash,anongid=-1)
/some/file/path5 ipAddress2/subnetMask(rw,sync,no_root_squash,anonuid=-1,anongid=-1)

我希望更改每一行的括号列表,使其在括号中包含字符串anonuid=-1anongid=-1 ...

/some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squash,anonuid=-1,anongid=-1)
/some/file/path2 ipAddress1/subnetMask(rw,sync,no_root_squash,anonuid=-1,anongid=-1)
/some/file/path3 ipAddress2/subnetMask(rw,sync,no_root_squash,anonuid=-1,anongid=-1)
/some/file/path4 ipAddress2/subnetMask(rw,sync,no_root_squash,anongid=-1,anonuid=-1)
/some/file/path5 ipAddress2/subnetMask(rw,sync,no_root_squash,anonuid=-1,anongid=-1)

从示例中可以看出,anonuidanongid 可能都已经存在于括号中,但原始括号列表可能只有一个字符串而没有另一个(第 2、3 和 4 行) ),列表都没有(第 1 行),列表都已正确设置(第 5 行),或者甚至其中一个或两个都设置不正确(第 3 行)。当anonuidanongid 设置为-1 以外的值时,必须将其更改为-1 的正确值(第3 行)。

使用 sed 编辑我的配置文件的最佳方法是什么,以便 anonuid=-1anongid=-1 包含在每行的括号列表中,当然用逗号分隔符分隔?

【问题讨论】:

    标签: bash


    【解决方案1】:

    我认为这是你想要的:

    sed -e '/anonuid/{s/anonuid=[-0-9]*/anonuid=-1/;b gid;};s/)$/,anonuid=-1)/;:gid;/anongid/{s/anongid=[-0-9]*/anongid=-1/;b;};s/)$/,anongid=-1)/'
    

    基本上,它有两个几乎相同的部分,第一个处理 anonuid 和第二个 anongid,每个部分都有一些逻辑来决定是否需要替换或添加适当的值。 (它不需要检查值是否已经正确,这只会使事情复杂化,而不会改变结果。)

    【讨论】:

    • 谢谢威廉!看起来这几乎可以解决问题。您唯一忘记的是最后的右括号。您能否编辑您的答案以具有该功能?谢谢!
    • 它仍然不会将第 1 行之类的东西放在括号中...echo "/home/cdg/jas_inbound_backup 192.168.5.175/255.255.255.0(rw,sync,no_root_squash)" | sed '/anonuid/{s/anonuid=[-0-9]*/anonuid=-1/;b gid;};s/)$/,anonuid=-1)/;:gid;/anongid/{s/anongid=[-0-9]*/anongid=-1)/;b;};s/)$/,anongid=-1/' 导致没有右括号。
    • 另外,一个或两个字符串已经在这些结果中会导致多个结尾括号...echo "/some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squash,anongid=0)" | sed '/anonuid/{s/anonuid=[-0-9]*/anonuid=-1/;b gid;};s/)$/,anonuid=-1)/;:gid;/anongid/{s/anongid=[-0-9]*/anongid=-1)/;b;};s/)$/,anongid=-1/' 导致/some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squash,anongid=-1),anonuid=-1)
    • 对不起,我意识到它丢失了最后一个括号,编辑它并不小心把它放在了错误的地方。现已修复并经过测试。
    【解决方案2】:

    您可以使用 sed 指定您感兴趣的行:

    $ sed '/anonuid=..*,anongid=..*)$/!p' $file
    

    上面将打印 (p) 所有与两个斜杠之间的正则表达式不匹配的行。我使用!否定了表达式。这样一来,您就不会匹配同时包含 anaonuidanongid 的行。

    现在,您可以使用 sed s 命令处理不匹配的行并编辑它们:

    $ sed '/anonuid=..*,anongid=..*)$/!s/from/to/`
    

    操作可能相当复杂,您可能会传递多个 sed 命令以使一切恰到好处

    但是,如果字符串no_root_squash出现在您要更改的每一行中,为什么不采取简单的方法:

    $ sed 's/no_root_squash.*$/no_root_squash,anonuid=-1,anongid=-1)/' $file
    

    这正在寻找那个no_root_squash 字符串,并用你想要的文本替换从那个字符串到行尾的所有内容。是否有您触摸的线条不需要编辑?是的,但你并没有真正改变这些线路。您基本上是用相同的/no_root_squash,anonuid=-1,anongid=-1) 替换/no_root_squash,anonuid=-1,anongid=-1)

    这可能会更快,即使它正在替换不需要替换的文本,因为正在进行的处理较少。另外,将来更容易理解和支持。

    响应

    谢谢大卫!是的,我正在考虑走那条路,但我不想 100% 依赖包含 no_root_squash 的每一行。我当前的配置文件仅以该字符串结尾,但我只是不能 100% 确定该字段不会有所不同。你认为有没有办法改变它,所以它只是从最后一个不包含 anonuid=-1 或 anongid=-1 的字符串的末尾开始覆盖?

    你能保证每一行都有什么?

    你也许可以做一个捕获组:

     sed 's/\(sync,[^,)]*\).*/\1,anonuid=-1,anongid=-1)/' $file
    

    \(..\) 是一个捕获组。它基本上捕获了匹配正则表达式的那部分,然后允许您通过\1 重用它。我从单词sync 捕捉到一组不包括逗号或右括号的字符。然后,我将附加捕获组、逗号以及您的匿名 uid 和 gid。

    这行得通吗?

    【讨论】:

    • 谢谢大卫!是的,我正在考虑走这条路,但我不想 100% 依赖于包含no_root_squash 的每一行。我当前的配置文件仅以该字符串结尾,但我只是不能 100% 确定该字段不会有所不同。你认为有没有办法改变它,所以它只是从最后一个不包含 anonuid=-1anongid=-1 的字符串的末尾覆盖?
    • @David W. 这似乎也是一个很棒、简洁的解决方案。但理想情况下,我不想保证配置文件中预先存在任何特定的字符串。我很抱歉没有在我的描述中明确说明这一点,并在我的示例中展示了这种趋势。我所能保证的是会有一个由逗号分隔的括号列表,并且需要修改它以包含我描述的两个字符串。
    【解决方案3】:

    也许我过于简单化了:

    sed 's/anonuid=[-0-9]*[^)]//g;s/anongid=[-0-9]*[^)]//g;s/[)]/anonuid=-1,anongid=-1)/g' test.txt > test3.txt
    

    这只是删除anonuidanongid 的任何当前实例并添加字符串 "anonuid=-1,anongid=-1" 放入括号中

    【讨论】:

    • 这个解决方案似乎在很大程度上也适用于斯科特。我对几个案例进行了简单的测试,发现在以下案例中缺少逗号。 echo "/some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squash)" | sed 's/anonuid=[-0-9]*[^)]//g;s/anongid=[-0-9]*[^)]//g;s/[)]/anonuid=-1,anongid=-1)/g' 导致 /some/file/path1 ipAddress1/subnetMask(rw,sync,no_root_squashanonuid=-1,anongid=-1)
    • 感谢您的回复,我目前正在借助此网站和其他网站自学 bash 脚本,我将尝试对其进行调整以使其成为学习挑战
    猜你喜欢
    • 1970-01-01
    • 2012-06-30
    • 2012-03-21
    • 2021-12-30
    • 2015-10-04
    • 2014-06-09
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多