如何使用 awk sed 或 cut 命令在匹配模式后打印一行

How to print one line after the matching pattern using awk sed or cut command

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

文件:

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

我尝试过的:

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

期望的输出:

2020-05-02 07:48

请帮助我。

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

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

2020-05-02 07:48
$ echo '2020-05-02 07:48:44+0000' | awk -F: -v OFS=: '{print , }'
2020-05-02 07:48
$ echo '2020-05-02 07:48:44+0000' | cut -d: -f1-2
2020-05-02 07:48

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

第一个解决方案:能否请您尝试以下。

awk 'match([=10=],/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}/){print substr([=10=],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}).*//' Input_file

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

awk 'match([=13=],/^.*:/){print substr([=13=],RSTART,RLENGTH-1)}' Input_file

第5种解决方法:只添加代入运算的awk解决方法

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

方案六:设置字段分隔符值,只打印需要的字段。

awk -F' |:' '{print ,":"}' Input_file

使用输入和输出字段分隔符 (:) 并使用 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

I want to print the content of text file till one character of pattern matching.

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

[^:]*:[^:]*

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

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

示例输出:

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

假设您已经对问题的性质进行了公正的表述,则不需要 awksedcut。以下是仅使用 bash 内置函数处理文本的四种方法:

1。 bash 正则表达式

[[ $(<./abc1.txt) =~ (^.+): ]] && printf %s "${BASH_REMATCH[1]}"
  • $(<./abc1.txt):读入文件内容abc1.txt,效率比catbash自己的man页面

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

  • (^.+)::捕获从行首到前面字符的每个字符最后的冒号

  • ${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" 重新格式化,在本例中表示类似于原始日期字符串,但没有时区且没有 seconds.

4。 printf

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

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

5。子串

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

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

除了 (3)¹ none 调用外部程序或命令,这提供了更多的可移植性,更好的 reliability/robustness,更有效的执行(一般来说,但这不会除非您正在处理数百个或更多的日期或文件)和更少的系统资源。

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

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