首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >包含一对()括号的sed删除行

包含一对()括号的sed删除行
EN

Stack Overflow用户
提问于 2020-06-28 05:30:53
回答 2查看 85关注 0票数 0

嗨,我创建了一个大型的命令集来操作文本文件。最后一件我似乎无法解决的事情是,一行只是由一对()组成

代码语言:javascript
复制
some text
()
more text
(leave this line as is)

我想删除整个()行

代码语言:javascript
复制
some text
more text
(leave this line as is)

在我的脚本中,sed命令-e '/ () / s/()//'可以找到并删除(),但留下一行

代码语言:javascript
复制
some text

more text
(leave this line as is)

下面是大图的剪短版

代码语言:javascript
复制
FILEPATH=*.chordpro
for fn in $FILEPATH; do
    echo $fn
    fnbak=$fn.bak
    mv "$fn" "$fnbak" #Create an untouched backup

    sed `: # these are comments` \
`: # Insert after subtitle; author,book,keywords,tempo,time` \
    -e '/^{subtitle.*/a {author:mds}\n{book:CatStevens}\n{keywords:70s,Tillerman}\n{tempo:120}\n{time:4/4}' \
    -e 's/{subtitle:/{artist:/'     `: # swap subtitle for artist` \
    -e 's/{time:/{duration:/'   `: # modifiy original meta "time" for "duration"` \
....lots of other commands
    `: # Tidy up` \
        -e '/()/ s/()//'            `: # Remove any () pairs created by script`  \
         "$fnbak" >"$fn"

下面是输入测试用例的片段。

代码语言:javascript
复制
{c:Verse2}
{c: Verse 2: Bass single}
{c: Verse 2 Rock it}
{c: verse 1}
{c: verse     1}
{c: Verse 1:}
{c:Verse}

在这里,它被转换了。Out#1

代码语言:javascript
复制
Verse 2:
()
Verse 2:
( Bass single)
Verse 2:
( Rock it)
Verse 1:
()
Verse 1:
()
Verse 1:
()
Verse :
()

这是使用-e '/()/ s/()//' Out#2进行整理的结果

代码语言:javascript
复制
Verse 2:

Verse 2:
( Bass single)
Verse 2:
( Rock it)
Verse 1:

Verse 1:

Verse 1:

Verse :

这是使用-e '/()/d'的结果。

代码语言:javascript
复制
Verse 2:
( Bass single)
Verse 2:
( Rock it)

,在Rock之后,所有东西都在哪里?注意:好的,这与它在循环中/与其他sed命令的交互有关。如果我将Out#1单独放入文件中,并仅在文件上运行sed -e '/()/d'命令,它就能工作。

这就是我希望达到的目标。

代码语言:javascript
复制
Verse 2:
Verse 2:
( Bass single)
Verse 2:
( Rock it)
Verse 1:
Verse 1:
Verse 1:
Verse :
EN

回答 2

Stack Overflow用户

发布于 2020-06-28 12:14:25

不要编写冗长的sed脚本,而要使用awk来提高清晰度、效率、健壮性、可移植性等。

代码语言:javascript
复制
    sed `: # these are comments` \
`: # Insert after subtitle; author,book,keywords,tempo,time` \
    -e '/^{subtitle.*/a {author:mds}\n{book:CatStevens}\n{keywords:70s,Tillerman}\n{tempo:120}\n{time:4/4}' \
    -e 's/{subtitle:/{artist:/'     `: # swap subtitle for artist` \
    -e 's/{time:/{duration:/'   `: # modifiy original meta "time" for "duration"` \
....lots of other commands
    `: # Tidy up` \
        -e '/()/ s/()//'            `: # Remove any () pairs created by script`  \
         "$fnbak" >"$fn"

尝试一下,我认为相当于上面所做的,但也修正了您的代码以删除()对:

代码语言:javascript
复制
awk '
    # Insert after subtitle; author,book,keywords,tempo,time
    /^{subtitle/ {
        $0 = $0 \
            "\n{author:mds}"              \
            "\n{book:CatStevens}"         \
            "\n{keywords:70s,Tillerman}"  \
            "\n{tempo:120}"               \
            "\n{time:4/4}"
    }

    {
        sub(/{subtitle:/,"{artist:")      # swap subtitle for artist
        sub/{time:/,"{duration:")         # modify original meta "time" for "duration"
        ....lots of other commands

        # Tidy up
        # Remove any () pairs created by script
        gsub(/\n\()\n/,"\n")              # Convert every \n()\n to \n ..
        gsub(/\n\()\n/,"\n")              # .. done twice to handle \n()\n()\n
        gsub(/^\()\n|\n\()$/,"")          # Remove ()\n at the start and \n() at the end
        gsub(/\()/,"")                    # Remove every remaining ()

        print
    }

' "$fnbak" > "$fn"

您的评论说是Remove any () pairs created by script,但是您发布的脚本不能创建任何()对,所以我假设您的lots of other commands可以这样做,我只是在我的awk脚本中猜测您真正想要在"Tidy“部分做什么,因为您没有提供任何我们可以测试的示例输入/输出。

顺便说一句,修改输入文件的更常见的方法是:

代码语言:javascript
复制
fnbak=$(mktemp) || exit 1
cmd 'script' "$fn" > "$fnbak" &&
mv -- "$fnbak" "$fn"

而不是

代码语言:javascript
复制
fnbak=$fn.bak
mv "$fn" "$fnback"
cmd 'script' "$fnbak" > "$fn"

前者只保留备份文件足够长的时间来修改原始文件,只对所有文件使用一个备份,而不是对每个文件使用一个备份,如果没有足够的磁盘空间或没有创建备份的写权限,则不会删除原始输入文件。

在进入循环之前,只需创建一次备份文件:

代码语言:javascript
复制
FILEPATH=*.chordpro
fnbak=$(mktemp) || exit 1
for fn in $FILEPATH; do
    echo "$fn"
    cmd 'script' "$fn" > "$fnbak" &&
    mv -- "$fnbak" "$fn"
done

当然,如果使用GNU awk,则根本不需要循环或临时文件,只需:

代码语言:javascript
复制
gawk -i inplace 'script' *.chordpro

(将FNR==1{print FILENAME | "cat>&2"}添加到awk脚本中,以查看在处理输入文件名时打印的输入文件名)。

票数 0
EN

Stack Overflow用户

发布于 2020-06-28 14:06:19

这里有一个GNU脚本-它允许内联注释,所以不需要复杂的引用

将其保存在tmp.sh中

代码语言:javascript
复制
#!/bin/bash
# tmp.sh

sed -E '
# strip initial piece
s/\{c: *//

# strip terminal piece
s/ *} *$//

# munge verse with number
s/verse *([0-9]+):? */Verse \1:/i

# munge verse without number
s/verse *$/Verse :/i

# put description on new line
s/: *(.+)$/:\n(\1)/
'

用本文档进行测试:

代码语言:javascript
复制
$ ./tmp.sh <<EOF
{c:Verse2}
{c: Verse 2: Bass single}
{c: Verse 2 Rock it}
{c: verse 1}
{c: verse     1}
{c: Verse 1:}
{c:Verse}
EOF
代码语言:javascript
复制
Verse 2:
Verse 2:
(Bass single)
Verse 2:
(Rock it)
Verse 1:
Verse 1:
Verse 1:
Verse :

很难说为什么您的单个delete命令在未看到整个脚本的情况下意外地运行

您可以尝试sed 4.6中提供的相对较新的--debug选项,或者我发现非常有用的是l=命令来在多个转换中的任意一点显示行的状态。

我的脚本更像是对脚本进行比较和故障排除以及修改其他测试用例的起点。

希望它能帮上忙

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62618625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档