AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 772804
Accepted
futurewave
futurewave
Asked: 2024-03-21 07:33:44 +0800 CST2024-03-21 07:33:44 +0800 CST 2024-03-21 07:33:44 +0800 CST

如何让 sed 取消注释由换行符分隔的多个段落之一?

  • 772

说明:使用 GNU sed。

现状 - ~/.screenrc,最后几行:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

目的:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

我当前的尝试几乎可以完成工作,但一旦出现该行就无法停止,这只是一个新行,没有任何注释符号或字母数字字符:

sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc

解释、意图:

  • '一系列要做的事情的开始

  • s代替

  • +使用“+”作为分隔符

  • # …逐行浏览,直到找到以“#”开头的行...

  • \(启动组以供稍后反向参考

  • name thrashmetal并继续“名称thrashmetal”

  • \)组结束

  • +\1+仅用组部分替换该行中的第一个匹配项,不带“#”

  • ;然后,从那时起,做另一件事……

  • :a做一个名为“a”的循环

  • ;s对于接下来的每一行,您逐行替换...

  • +设置“+”作为分隔符

  • # 该行中“#”的第一个匹配项,无论该行中其后的内容如何...

  • ++什么都没有,有效地删除它

  • ;ta只要你失败了,就这样做,这应该是当你到达段落末尾,然后是分隔 thrashmetal-block 和 darkwave-block 的 2 个换行符,然后返回到“a”所在的位置

  • '一系列要做的事情的结束

  • .screenrc执行有关我当前目录中的文件“.screenrc”的一系列操作 - 我的主目录

标准输出:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

name darkwave
screen -t script emacs -nw /home/$USER/bin/darkwave

如何解决这个问题?我做错了什么,循环不会在到达 thrashmetal 段落末尾时立即停止,而是简单地跳到下一段(darkwave 段落)并继续?

我猜想,那个循环中的任何东西都一定是错误的……也许是“t”,但“T”或“b”也不会删掉它……

text-processing
  • 4 4 个回答
  • 206 Views

4 个回答

  • Voted
  1. Best Answer
    Kusalananda
    2024-03-21T17:24:22+08:002024-03-21T17:24:22+08:00
    sed '/^# name thrashmetal$/,/^$/ s/^# //' file
    

    这将应用替换,#从范围内的每一行中删除初始和后续的空格字符。

    该范围从匹配的行开始^# name thrashmetal$,到第一个后续匹配的行^$(空行)结束。

    或者,直接翻译成awk:

    awk '/^# name thrashmetal$/,/^$/ { sub(/^# /, "") }; 1' file
    

    此处,尾随1是{ print $0 }or的缩写{ print },导致输出当前(可能已修改)行(文本的打印在脚本中是隐式的sed)。


    对于任何对ed编辑器感兴趣的人,您可以使用以下编辑命令来解决此问题:

    /^# name thrashmetal$/;.,/^$/ s/^# //
    

    这会将光标移动到所需段落的第一行,并将替换应用于该行以及后面的所有行,直到到达空行。

    我们不能使用

    /^# name thrashmetal$/,/^$/ s/^# //
    

    ...因为地址是相对于当前行计算的,并且当我们启动编辑器时当前行位于文件的末尾。由于我们位于文件的末尾,因此命令中的范围将无效,因为地址/^$/将是比起始地址更早的行(相对于当前行,第一个空行位于段落开头之前) 。


    您自己的方法已更正(将分隔符从加号更改为默认值并分成多个表达式,这样更便携):

    sed -e '/^# \(name thrashmetal\)/!b' -e 's//\1/' -e :a -e n -e 's/^# //' -e ta file
    

    我没有进行初始替换,而是让段落初始行的匹配来确定是否跳过编辑脚本的其余部分。b如果未遇到该行,则跳过该行。

    如果找到该行,我们将对其进行修改并创建标签a。然后,我们打印当前缓冲区并使用下一行替换其内容n。循环像以前一样继续,# 如果缓冲区的内容发生变化,则删除子字符串并循环回标签。

    您最初尝试的主要问题是,

    sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc
    

    ...是“ a-loop”是无条件的,因此适用于输入的每一行,无论初始替换是否成功或失败(您显示前两行不受命令影响,但我认为这是一个复制粘贴错误)。该循环也不会读取下一行,因此它只会在每行上运行一次# (除非在一行上找到多个子字符串)。

    我的修复方法是将初始替换分为测试和替换,然后确保“ a-loop”读取下一行输入,直到替换失败。我也不会替换# 任何一行上的多个或嵌入(内部)字符串,只会替换行开头的第一个字符串。

    • 4
  2. larsks
    2024-03-21T08:24:03+08:002024-03-21T08:24:03+08:00

    这个脚本似乎可以做你想做的事:

    H
    /^$/ T show
    $ T show
    d
    
    :show
    x
    s/\n//
    /^# name thrashmetal/ {
      s/# //
      s/\n# /\n/g
    }
    

    我们有效地将事物分割成空行分隔的块。当我们找到以 开头的块时# name thrashmetal,我们删除# 行开头的所有字符串。

    给定您的示例输入,这将产生输出:

    $ sed -f filter.sed < example.conf
    # name synthpop
    # screen -t script emacs -nw /home/$USER/bin/synthpop
    
    name thrashmetal
    screen -t script emacs -nw /home/$USER/bin/thrashmetal
    number 1
    split -v
    focus
    chdir "/home/$USER/thrashmetal/src"
    screen -t scr watch nl asdkjlek.html
    number 2
    focus
    split
    focus
    screen -t output watch thrashmetal asdkjlek.html
    number 3
    focus
    split
    focus
    chdir "/home/$USER/thrashmetal/plan"
    screen -t soll watch less soll
    number 4
    focus
    
    # name darkwave
    # screen -t script emacs -nw /home/$USER/bin/darkwave
    

    带注释的 sed 脚本:

    # Append current line to the hold space
    H
    
    # If we find a blank line or reach EOF, print out the
    # current chunk
    /^$/ T show
    $ T show
    
    # Delete the current line (we'll print it later in the
    # show routine)
    d
    
    :show
    # Swap the pattern space and the hold space
    x
    
    # Remove the initial "\n" that was added when we appended
    # the first line with the H command
    s/\n//
    
    # If this is our target chunk, remove the comments
    /^# name thrashmetal/ {
      s/# //
      s/\n# /\n/g
    }
    
    • 3
  3. user9101329
    2024-03-21T19:11:52+08:002024-03-21T19:11:52+08:00

    您还可以考虑使用 awk:

    $ awk -v RS= -v ORS='\n\n' '/thrashmetal/{sub(/^# /,"");gsub(/\n# /,"\n",$0)}1'  .screenrc
    # name synthpop
    # screen -t script emacs -nw /home/$USER/bin/synthpop 
    
    name thrashmetal
    screen -t script emacs -nw /home/$USER/bin/thrashmetal
    number 1
    split -v
    focus
    chdir "/home/$USER/thrashmetal/src"
    screen -t scr watch nl asdkjlek.html
    number 2
    focus
    split
    focus
    screen -t output watch thrashmetal asdkjlek.html
    number 3
    focus
    split
    focus
    chdir "/home/$USER/thrashmetal/plan"
    screen -t soll watch less soll
    number 4
    focus 
    
    # name darkwave
    # screen -t script emacs -nw /home/$USER/bin/darkwave 
    

    在这里,通过将 RS(输入记录分隔符)设置为空白,您可以将段落视为单行。

    • 3
  4. Ed Morton
    2024-03-22T01:15:52+08:002024-03-22T01:15:52+08:00

    使用任何 awk:

    $ awk '/^# name /{f=($3 == "thrashmetal")} f{sub(/^# /,"")} 1' file
    # name synthpop
    # screen -t script emacs -nw /home/$USER/bin/synthpop
    
    name thrashmetal
    screen -t script emacs -nw /home/$USER/bin/thrashmetal
    number 1
    split -v
    focus
    chdir "/home/$USER/thrashmetal/src"
    screen -t scr watch nl asdkjlek.html
    number 2
    focus
    split
    focus
    screen -t output watch thrashmetal asdkjlek.html
    number 3
    focus
    split
    focus
    chdir "/home/$USER/thrashmetal/plan"
    screen -t soll watch less soll
    number 4
    focus
    
    # name darkwave
    # screen -t script emacs -nw /home/$USER/bin/darkwave
    
    • 0

相关问题

  • grep 从 $START 到 $END 的一组行并且在 $MIDDLE 中包含匹配项

  • 重新排列字母并比较两个单词

  • 在awk中的两行之间减去相同的列

  • 多行文件洗牌

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve