【问题标题】:How to print one line after the matching pattern using awk sed or cut command如何使用 awk sed 或 cut 命令在匹配模式后打印一行
【发布时间】:2020-08-16 18:04:29
【问题描述】:

我想打印文本文件的内容直到一个字符的模式匹配。我使用了awk 命令,但未能获得所需的输出。

文件:

>cat abc1.txt
2020-05-02 07:48:44+0000

我尝试过的:

>cat abc1.txt | awk '{print $1}'
2020-05-02

期望的输出:

2020-05-02 07:48

请帮帮我。

【问题讨论】:

  • 请修正问题的标题
  • 后一行还是后一个字符?你想匹配什么“模式”?

标签: shell unix awk sed sh


【解决方案1】:

你可以在 awk 中使用 sub 函数来删除最后一次出现 : 之后的所有内容:

awk '{sub(/:[^:]*$/, "")} 1' abc1.txt

2020-05-02 07:48

【讨论】:

    【解决方案2】:
    $ echo '2020-05-02 07:48:44+0000' | awk -F: -v OFS=: '{print $1, $2}'
    2020-05-02 07:48
    $ echo '2020-05-02 07:48:44+0000' | cut -d: -f1-2
    2020-05-02 07:48
    

    您可以将默认字段分隔符更改为: 字符并打印前两个字段

    【讨论】:

      【解决方案3】:

      第一种解决方案:请您尝试以下方法。

      awk 'match($0,/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}/){print substr($0,RSTART,RLENGTH)}'  Input_file
      

      第二个解决方案:使用rev + awk,这让我们的替换更容易。

      rev Input_file | awk '{sub(/[^:]*:/,"")} 1' | rev
      

      第三种解决方案:使用sed 的临时缓冲能力。

      sed -E 's/([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}).*/\1/' Input_file
      

      第 4 种解决方案:如果您的 Input_file 始终具有相同的输入格式,并且您不需要验证日期的语法,请尝试。

      awk 'match($0,/^.*:/){print substr($0,RSTART,RLENGTH-1)}' Input_file
      

      第 5 种解决方案: 只添加替代操作 awk 解决方案。

      awk '{sub(/:[0-9]{2}\+.*/,"")} 1'  Input_file
      

      第 6 种解决方案: 设置字段分隔符值并仅打印需要的字段。

      awk -F' |:' '{print $1,$2":"$3}' Input_file
      

      【讨论】:

        【解决方案4】:

        使用输入和输出字段分隔符 (:) 并使用 GNU awk 删除最后一列:

        awk 'BEGIN{FS=OFS=":"} {NF--; print}' abc1.txt
        

        或更短:

        awk 'BEGIN{FS=OFS=":"} {NF--}1' abc1.txt
        

        输出:

        2020-05-02 07:48

        见:8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

        【讨论】:

          【解决方案5】:

          我想打印文本文件的内容直到模式匹配的一个字符。

          匹配你想要保留的正则表达式:

          [^:]*:[^:]*
          

          两个等效的 sed 命令仅保留与之匹配的内容:

          sed 's|\([^:]*:[^:]*\).*|\1|'
          sed -E 's|([^:]*:[^:]*).*|\1|'
          

          示例输出:

          $ echo '2020 07:48:40:40+0000'|sed 's|\([^:]*:[^:]*\).*|\1|'
          2020 07:48
          

          【讨论】:

            【解决方案6】:

            假设您已经公平地说明了问题的性质,则不需要awksedcut。以下是仅使用 bash 内置函数处理文本的四种方法:

            1。 bash 正则表达式

            [[ $(<./abc1.txt) =~ (^.+): ]] && printf %s "${BASH_REMATCH[1]}"
            
            • $(&lt;./abc1.txt):根据bash自己的man页面读取文件abc1.txt的内容,比cat效率更高

            • =~:正则表达式运算符

            • (^.+)::捕获从行首到紧接在最后一个冒号之前的每个字符

            • ${BASH_REMATCH[1]}:存储正则表达式模式匹配的子串列表;第一个捕获组(在模式的括号内)存储在索引 1

            2。 bash参数替换

            : "$(<./abc1.txt)"
            printf %s "${_%:*}"
            
            • ${_%:*}: 下划线引用上一条命令的参数,即文件内容;并且替换会删除从最后一个冒号到字符串末尾的所有内容

            3。 date

            由于很明显您正在使用日期,并且以明确定义的格式 (ISO-8601) 表示,date 命令可以执行设计的操作:

            # -j flag available on macOS:
            date -jf '%F %T%z' "$(<./abc1.txt)" +'%F %R'
            # -d option on other systems:
            # [credit: @WalterA (see comments below)]
            date -d "$(<./abc1.txt)" +"%F %R"
            

            这使用输入格式字符串 "%F %T%z" 解析日期,该字符串描述日期字符串的每个组件代表的内容(请参阅Linux Programmer's Manual - STRFTIME(3)),并使用输出字符串 "%F %R" 重新格式化,在这种情况下表示日期字符串与原始字符串类似,但没有时区和

            4。 printf

            printf 用于格式化文本。所以这里它只是格式化文本以显示前 16 个字符(它实际上将第一个字段的列宽限制为 16 个字符的宽度,但那是废话):

            printf '%16.16s\n' "$(<./abc1.txt)"
            

            5。子串

            与 (4) 类似,但使用参数替换:

            : "$(<./abc1.txt)"
            printf "${_:0:16}"
            

            除了(3)¹ 之外,没有人调用外部程序或命令,这提供了更多的可移植性、更高的可靠性/稳健性、更高效的执行(一般来说,但这将无法衡量,除非您正在处理数百个或更多日期或文件),以及更少的系统资源。

            awksed 是强大的大炮,而不是特别轻量级的工具(它们都是成熟的、图灵完备的脚本语言)。不要仅仅因为其他人都这样做,或者因为它是你所知道的就去接触它们:了解 bash 作为 shell 可以做什么,你会从中受益匪浅。

            ¹ 某些系统包含printf 的一个版本,它可以使用strftime 识别的任何标志来格式化日期,如果可用,它是date 的一个很好的替代品。 printf --helpman bash(在关于内置的部分下)将显示此选项是否存在。

            【讨论】:

            • 我的date 不知道-j,我需要date -d "$(&lt;./abc1.txt)" +'%F %R'。您的前 2 个解决方案给我留下了最深刻的印象,我无法理解为什么没有其他人支持您的答案。
            • @WalterA 非常感谢您的支持和date 上的注释。我希望您不要反对我在我的回答中包含您的解决方案,我已将其添加到我的答案中。如果您希望我删除它,例如如果您更喜欢添加自己的答案,请告诉我,我会回滚我的编辑。我猜-j 选项是 macOS 特有的。
            最近更新 更多