【问题标题】:sed multiple replacements with line rangesed 使用行范围进行多次替换
【发布时间】:2020-03-28 05:34:29
【问题描述】:

我有一个包含以下记录的文件

user1,fuser1,luser1,user1@test.com,data,user1
user2,fuser2,luser2,user2@test.com,data,user2
user3,fuser3,luser3,user3@test.com,data,user3

我想从

执行一些文本替换

user1,fuser1,luser1,user1@test.com,data,user1

New_user1,New_fuser1,New_luser1,New_user1@test.com,data,New_user1

所以我写了下面的 sed 脚本。

sed -i -e 's/user/New_user/g; s/fuser/New_fuser/g; s/luser/New_luser/g' file

这很完美。现在我有一个要在特定行范围内替换的要求。

start=2
end=3
sed -i -e ''${start},${end}'s/user/New_user/g; s/fuser/New_fuser/g; s/luser/New_luser/g' file

但此命令正在替换所有行中的模式。示例输出是,

user1,New_fuser1,New_luser1,user1@test.com,data,New_user1
user2,New_fuser2,New_luser2,user2@test.com,data,New_user2
user3,New_fuser3,New_luser3,user3@test.com,data,New_user3

看起来范围仅应用于第一个表达式,而其余表达式则应用于整个文件。如何将此范围应用于所有表达式?

【问题讨论】:

  • 我不认为sed 脚本工作完美New_user1,fNew_user1,lNew_user1。您对该输入数据的预期输出是什么?

标签: bash shell unix sed


【解决方案1】:

您可以使用awk 变量来实现此功能,控制用于替换的行号和列号

awk -vFS="," -vOFS="," -v columnStart=2 -v columnEnd=3 -v rowStart=1 -v rowEnd=2 \
     'NR>=rowStart&&NR<=rowEnd{for(i=columnStart; i<=columnEnd; i++) \
           $i="New_"$i; print }' file

其中awk 变量columnStartcolumnEndrowStartrowStart 确定哪些列和行要替换为, 作为采用的分隔符。

对于您的输入文件:-

$ cat input-file
user1,fuser1,luser1,user1@test.com,data,user1
user2,fuser2,luser2,user2@test.com,data,user2
user3,fuser3,luser3,user3@test.com,data,user3

假设我想在第 3-4 列的第 2 行和第 3 行中进行替换,我可以将我的 awk 设置为

awk -vFS="," -vOFS="," -v columnStart=3 -v columnEnd=4 -v rowStart=2 -v rowEnd=3 \
     'NR>=rowStart&&NR<=rowEnd{for(i=columnStart; i<=columnEnd; i++) \
           $i="New_"$i; print }' file
user2,fuser2,New_luser2,New_user2@test.com,data,user2
user3,fuser3,New_luser3,New_user3@test.com,data,user3

要应用于最后一列,请将columnStartcolumnEnd 设置为相同的值,例如只在第 6 列和 最后 行说。

awk -vFS="," -vOFS="," -v columnStart=6 -v columnEnd=6 -v rowStart=3 -v rowEnd=3 \
     'NR>=rowStart&&NR<=rowEnd{for(i=columnStart; i<=columnEnd; i++) \
           $i="New_"$i; print }' file
user3,fuser3,luser3,user3@test.com,data,New_user3

【讨论】:

    【解决方案2】:

    使用 GNU Sed 时(存在于 Ubuntu,可能是 Debian,也可能是其他人)。

    有一个功能可以让这变得简单: https://www.gnu.org/software/sed/manual/sed.html#Common-Commands

    一组命令可以包含在 { 和 } 字符之间。这个 当您想要一组命令时特别有用 由单个地址(或地址范围)匹配触发。

    示例:执行替换然后打印第二个输入行:

    $ seq 3 | sed -n '2{s/2/X/ ; p}'
    X
    

    鉴于最初的问题,这应该可以解决问题:

    sed -i -e '2,3 {s/user/New_user/g; s/fuser/New_fuser/g; s/luser/New_luser/g}' file
    

    【讨论】:

      【解决方案3】:

      以下对我有用:

      START=2
      NUM=1
      sed -i -e "$START,+${NUM} s/user/New_user/g; $START,+${NUM} s/fuser/New_fuser/g; $START,+${NUM}  s/luser/New_luser/g" file
      

      如您所见,有几个变化:

      1. 行范围必须出现在每个表达式中
      2. 范围应表示(在这种情况下)为起始行数和行数(受影响的行数为 NUM+1)
      3. 您添加了额外的撇号。

      【讨论】:

        【解决方案4】:

        使用单个s 命令:

        start=1
        end=2
        sed -e "$start,$end s/\([fl]*\)user/New_\1user/g" file
        

        [fl]*user 将匹配 user 与可选的 fl 首字母

        输出:

        New_user1,New_fuser1,New_luser1,New_user1@test.com,data,New_user1
        New_user2,New_fuser2,New_luser2,New_user2@test.com,data,New_user2
        user3,fuser3,luser3,user3@test.com,data,user3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-04
          • 2015-09-04
          • 2022-01-19
          • 1970-01-01
          • 2013-10-04
          • 1970-01-01
          相关资源
          最近更新 更多