【问题标题】:How to delete a part of the file with awk如何使用 awk 删除文件的一部分
【发布时间】:2010-11-06 12:04:31
【问题描述】:

我正在编写一个 shell 脚本,它在某些时候必须获取一个文件,在其中搜索一个特定的单词并删除该单词之后的整个文本(包括单词本身) - awk 是正确的工具我想,但我对其中的编程了解不多。

谁能帮帮我?

【问题讨论】:

    标签: shell text scripting awk


    【解决方案1】:

    我认为 'awk' 是这项工作的一种工具,尽管我认为 'sed' 对于这个特定的操作来说更简单。规范有点模糊。简单的版本是:

    • 查找包含给定单词的第一行。
    • 删除该行和所有后续行。

    为此,我会使用“sed”:

    sed '/word/,$d' file
    

    更复杂的版本是:

    • 查找包含给定单词的第一行。
    • 从单词开始删除该行上的文本。
    • 删除所有后续文本行。

    我可能仍然会使用“sed”:

    sed -n '1,/word/{s/word.*//;p}' file
    

    这颠倒了逻辑。默认情况下它不打印任何内容,但是对于第 1 行,直到包含单词的第一行它会执行替换(直到包含单词的行之前什么都不做),然后打印。

    可以在'awk'中完成吗?并非完全不重要,因为 'awk' 将输入行自动拆分为单词,并且您必须使用函数来进行替换。

    awk '/word/ { if (found == 0) {
                    # First line with word
                    sub("word.*", "")
                    print $0;
                    found = 1
                  }
                }
                { if (found == 0) print $0; }' file
    

    已编辑:将 'delete' 更改为 'found',因为 'delete' 是 'awk' 中的保留字。)

    在所有这些示例中,输入文件的截断版本被写入标准输出。要就地修改文件,您要么需要使用 Perl 或 Python 或类似语言,要么在命令完成后将输出捕获到临时文件中,然后将其复制到原始文件中。 (如果你尝试“脚本文件”,你会处理一个空文件。)

    有多种早期退出优化可以应用于 sed 和 awk 脚本,例如:

    sed '/word/q' file
    

    而且,如果您假设使用 GNU 版本的 awk 或 sed,则有各种非标准扩展可以帮助对文件进行原位修改。

    【讨论】:

    • 同意,我可能也会在 sed 中这样做。
    • sed -e ' /\.*/{s///; q}' 做同样的事情,并且只指定单词一次。 (我之前的评论声称要做同样的事情,但匹配错误......)另外,您可能希望指定 \ 以避免被某人的剑抓住。
    • @Stobor:当然,我们正在进入有趣的领域,包括单词的定义,以及“sed”版本支持的正则表达式语法的定义。 '\' 表示法在支持时非常出色;传统上不支持它,但我发现它在 Solaris 上受支持(有点令我惊讶)。
    • @Stobor:避免重复这个词是有利的。此外,关于“awk”中“word”定义的类似 cmets 可能适用。所有这些都是对基本技术的改进——如果你愿意的话,可以为读者练习(或原始海报)。
    【解决方案2】:

    我假设您的输入是这样的:

    Lorem ipsum dolor sit amet,
    consectetur adipiscing velit。
    Nullam neque sapien, molestie vel congue non,
    feugiat quistellus。犹他
    努拉米Maecenas 舌叶。

    并且您希望在单词 'vel' 处截断输出,如下所示:

    Lorem ipsum dolor sit amet,
    consectetur adipiscing velit。
    Nullam neque sapien, molestie

    在这种情况下,您的 awk 脚本将是:

    cat lorem.txt | awk ' 
      /\<vel\>/ 
      {
         print substr($0, 0, match($0, /\<vel\>/) - 1); 
         exit; 
      } 
    
      { print }
    '
    

    您要截断的单词需要替换脚本中单词vel 的两个实例。

    您也可以安全地将整个脚本放在一行中。

    【讨论】:

    • @Erik:我不打算就“从不”这个词展开争论......我只想说我同意它在这里没有用。
    【解决方案3】:
    awk '/word/{exit}1' file
    

    【讨论】:

    • 不,不打印包含单词的行的第一部分
    【解决方案4】:

    我不知道如何用 awk 来做,但你可以用 sed 来做:

    sed -i~ -e 's/the-word-to-find.*$//' the-file
    

    这将删除从the-word-to-find 到行尾的所有内容,在包含the-word-to-find 的每一行上。如果您想在第一次出现 the-word-to-find 时删除文件的其余部分,您可以这样做:

    sed -i~ -e 's/\(the-word-to-find\).*$/\1/;/the-word-to-find/,$d'
    

    【讨论】:

      【解决方案5】:

      这个 awk 单行代码应该可以解决问题: { sub(/ word.*/, "");打印 } 对于每一行,如果该行包含以 word 开头(以空格开头)并到达行尾的模式 - 用空字符串替换该模式 - 然后打印更新的行。

      [ 认为问题可以读取任何一种方式(该行上的整个文本或文件中的整个文本)。如果想跳过文件的其余部分,可以: { skip = gsub(/ word.*/, "");打印 ;如果(跳过)退出}]

      【讨论】:

      • 我认为这不能解决问题 - 它不会在第一次出现搜索词后忽略文件的其余部分。
      【解决方案6】:

      用sed删除部分行,例如:

      $ echo '12345 John Smith / red black or blue it is a test' | sed -e 's/\/.*//'
      
      $ 12345 John Smith 
      

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 1970-01-01
        • 2022-01-23
        • 2012-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-11
        • 1970-01-01
        相关资源
        最近更新 更多