使用 sed 仅在第一次出现的模式匹配后查找并替换文件中的文本

Asi*_*r12 4 linux text-editing bash sed

假设我有以下输入文件:

Server 'Test AB'
    option type 'ss'
    option port '1234'
    option timeout '60'

Server 'Test CD'
    option type 'ss'
    option port '1234'
    option timeout '60'

Server 'Test EF'
    option type 'ss'
    option port '1234'
    option timeout '60'

Server 'Test GH'
    option type 'ss'
    option port '1234'
    option timeout '60'
Run Code Online (Sandbox Code Playgroud)

现在我想使用 sed 将“选项端口'1234'”与“选项端口'9876'”交换,但我只想为服务器“Test EF”执行此操作。所有其他端口应保持不变。

输出应如下所示:

Server 'Test AB'
    option type 'ss'
    option port '1234'
    option timeout '60'

Server 'Test CD'
    option type 'ss'
    option port '1234'
    option timeout '60'

Server 'Test EF'
    option type 'ss'
    option port '9876'
    option timeout '60'

Server 'Test GH'
    option type 'ss'
    option port '1234'
    option timeout '60'
Run Code Online (Sandbox Code Playgroud)

我已经尝试了很多 sed 命令,我发现我可以在行之间搜索

sed '11,15s/port '1234'/port '9876'/g' file
Run Code Online (Sandbox Code Playgroud)

但这对我没有帮助,因为服务器“Test EF”不会始终位于同一行。我需要限制区域而不是 11,15,例如“'测试 EF',选项超时”,但不知道如何实现它。

Sco*_*ott 8

之前的答案相反,\n这就在sed\xe2\x80\x99s 巷子里。\xc2\xa0\n而且,\xc2\xa0与另一个建议(现已删除)相反,\n很容易在 a\xc2\ 中完成xa0 sed进程。

\n
sed "/Server \'Test EF\'/,/Server/ s/option port \'1234\'/option port \'9876\'/" file\n
Run Code Online (Sandbox Code Playgroud)\n

会做你想做的事。

\n

有人说sed代码通常很神秘,\n除非你是\xc2\xa0sed专家。\xc2\xa0\n虽然可能很难\xc2\xa0写,\n我\xc2\xa0相信它\xe2\x80\ x99s 相当容易阅读和\xc2\xa0理解:

\n
    \n
  • 从包含 的行开始Server \'Test EF\'
  • \n
  • 并继续执行包含的下一行Server
  • \n
  • 搜索每一行option port \'1234\'
  • \n
  • 并且,如果找到它,请替换option port \'9876\'.
  • \n
\n

您实际上相当接近。\xc2\xa0\n引用是您的尝试的一个\xc2\xa0大问题:\n您可以\xe2\x80\x99t在\xc2\xa0string\nthat\xe2\ 中使用单引号字符 ( \') x80\x99s 也用单引号分隔(即,以单引号开始和\xc2\xa0 结束)。\xc2\xa0\nOne\xc2\xa0 处理这个问题的方法(这是我的答案,上面,使用)\n 来\xc2\xa0 将字符串\n 用双引号字符 ( ") 括起来;如

\n
  \xe2\x80\xa6 "\xe2\x80\xa6                         \xe2\x80\xa6 s/option port \'1234\'/option port \'9876\'/" \xe2\x80\xa6\n    \xe2\x86\x91                                                                    \xe2\x86\x91\n
Run Code Online (Sandbox Code Playgroud)\n

如果字符串不\xe2\x80\x99t 包含\n任何"字符\xe2\x80\x94 或$,\\`.\xc2\xa0\nIf\xc2\xa0you\xe2\x80\x99re 使用bash(如您所指示的你的标签),\n你可以使用$\'\xe2\x80\xa6\xe2\x80\xa6\\\'\xe2\x80\xa6\xe2\x80\xa6\'; 例如,

\n
echo $\'the cat\\\'s pajamas\'\nthe cat\'s pajamas\n
Run Code Online (Sandbox Code Playgroud)\n

所以你可以做

\n
  \xe2\x80\xa6 $\'\xe2\x80\xa6                     \xe2\x80\xa6 s/option port \\\'1234\\\'/option port \\\'9876\\\'/\' \xe2\x80\xa6\n                                            \xe2\x87\x91\xe2\x87\x91    \xe2\x87\x91\xe2\x87\x91            \xe2\x87\x91\xe2\x87\x91    \xe2\x87\x91\xe2\x87\x91\n
Run Code Online (Sandbox Code Playgroud)\n
\n

这里\xe2\x80\x99是在awk中执行此操作的一种不那么神秘的方法:

\n
awk $\'\n    /Server/             { matched=0 }\n    /Server \\\'Test EF\\\'/ { matched=1 }\n    matched              { gsub("option port \\\'1234\\\'", "option port \\\'9876\\\'") }\n                         { print }\n  \'\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • (仅)当我们\xe2\x80\x99re 在一个节中时,定义一个名为matchedthat is 1\n 的变量Server \'Test EF\'
  • \n
  • 1当我们匹配Server \'Test EF\', \xe2\x80\xa6时将其设置为
  • \n
  • \xe2\x80\xa6 并将其设置0为当我们看到任何其他包含Server.
  • \n
  • matched是非零\n时(即,当我们\xe2\x80\x99re 在一个Server \'Test EF\'节中时),\n在每一行中搜索option port \'1234\'\n并替换option port \'9876\'
  • \n
\n