我试图找到一种方法来 grep 位于不同行的文件中的信息,其中一个模式是包含日期和时间的模式。
下面是输入
unwantedtext unwantedtext unwantedtext unwantedtext 8/1/2022 6:15 (1st required pattern using date and time format and the date and time can be changed)
unwantedtext unwantedtext unwantedtext unwantedtext
unwantedtext unwantedtext INC-220721-00007628 (2nd required pattern)
同样在第二个文件中,某些第二模式并不总是位于第三行,但肯定位于与日期和时间信息不同的行中。
第二个模式始终以 INC 开头,然后是年月和日期信息
INC
始终将此 INC 放在前 3 位数字中
INC-YYMMDD
INC 之后是日期和时间
INC-YYMMDD-00000000
YYMMDD 之后是随机 8 位数字。
-
连字符始终作为第二个模式的分隔符
我期待以下输出
INC-220721-00007628,8/1/2022 6:15
对于测试,我使用 Windows CYGWYN,对于大量文件,我使用 CENTOS 7
预先感谢您的所有建议
答案1
假设值为总是成对地,您可以用来grep
查找它们并将paste
它们组合起来:
$ grep -oP '\b\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{2}|INC-\d{6}-\d{8}\b' file |
paste -d "," - -
8/1/2022 6:15,INC-220721-00007628
答案2
你无法grep
独自完成这件事。您也许可以sed
使用 PITA 来完成此操作,并且需要比您可能拥有的更多有关模式和保持空间的知识(并且这些知识通常不值得学习,因为用其他语言更容易做到)。
$ perl -lne 'BEGIN { $, = "," };
if (m=(\b\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{1,2}\b)=) {
$dt = $1
} elsif (m/(INC-\d+-\d+)/) {
print $1, $dt;
#$dt = ""; # uncomment to clear $dt before next input line
}' input.txt
INC-220721-00007628,8/1/2022 6:15
这个perl单行脚本使用perl的-l
选项来启用自动处理行结束,同时读取输入和打印输出(例如\n
在unix或\r\n
windows上),该-n
选项使perl像sed -n
.该-e
选项指示下一个参数是要由 perl 运行的脚本。
首先,此脚本将输出字段分隔符 ( $,
) 设置为逗号。该变量记录在曼·珀尔瓦尔。它在一个BEGIN {...}
块中执行此操作,以便在脚本启动时仅运行一次,而不是为每个读取的输入行运行一次。
顺便说一句,您可以选择使用 perl英语如果您不喜欢或无法记住神秘的单字符变量名称(在use English;
脚本内部或-MEnglish
单行代码中),这可以让您访问长描述性英文别名和类似 awk 的等效项(如果适用)短变量。例如,use English
您可以使用$,
、$OUTPUT_FIELD_SEPARATOR
或类似 awk 的命令$OFS
- 它们都表示相同的含义并引用相同的变量。
该脚本使用 Perl 的正则表达式匹配运算符m
来匹配(并捕获,由于正则表达式中的括号)所需的模式。看曼·珀洛普并搜索“米/图案“。第一次使用 时m
,我将=
其用作正则表达式分隔符,这样我就不必转义/
日期模式中的 s。第二次,我使用更熟悉的/
.
对于读取的每个输入行,它尝试匹配所需的日期和时间模式,如果成功,则存储捕获的日期和时间(来自 Perl 的$1
子模式匹配变量,这类似于\1
in sed
- 查看man perlvar
并搜索标题为“的部分”与正则表达式相关的变量") 到一个名为 的变量中$dt
。
如果之前的匹配不成功,它会尝试匹配该INC-\d+-\d+
模式。如果成功,它将打印捕获的模式和$dt
变量。
所有其他输入都将被忽略。
或使用 awk:
$ awk -v OFS=, '
match($0,/\<[[:digit:]]{1,2}\/[[:digit:]]{1,2}\/[[:digit:]]{4} [[:digit:]]{1,2}:[[:digit:]]{1,2}\>/,a) {
dt = a[0]; next
};
match($0,/INC-[[:digit:]]+-[[:digit:]]+/,a) {
print a[0], dt
}' input.txt
INC-220721-00007628,8/1/2022 6:15
awk 有一个方便的-v
选项来设置 awk 变量,因此我们不需要BEGIN
块来设置 OFS。
这个 awk 单行语句几乎是 Perl 版本的直接翻译,但使用 awk 的match()
函数来进行匹配和捕获测试。它将所有匹配捕获到 array 中a
。
它还使用[[:digit:]]
与 perl 等效的\d
.在许多语言环境中,您可以使用 using 来[0-9]
代替,但是两者[[:digit:]]
和 perl都\d
可以在任何语言环境中工作。
答案3
grep -Eo 'INC-[[:digit:]]{6}-[[:digit:]]+|[[:digit:]]{1,2}/[[:digit:]]{1,2}/[[:digit:]]{4} [[:digit:]]{1,2}:[[:digit:]]{1,2}' inputfile.txt |
tr '\n' ',' |
sed 's/,$//'
笔记:
grep
:-o
: 只获取匹配的表达式-E
:接受扩展 RE- 模式由管道 (
|
)、布尔运算符“或”分隔
- 模式由管道 (
结果是:
8/1/2022
INC-220721-00007628
该顺序与输入文件中的顺序相同。
tr ...
: 将换行符 (\n
) 转换为逗号 (,
)
结果是:
8/1/2022 6:15,INC-220721-00007628,
sed ...
:搜索并替换/删除命令添加的最后一个tr
逗号
结果是:
8/1/2022 6:15,INC-220721-00007628
答案4
Withpcregrep
的多行模式:
$ pcregrep -M -o2 -o1 --om-separator=, '(?s) (\d+/\d+/\d+ \d+:\d+) .*?(INC-\d{6}-\d{8})' your-file
INC-220721-00007628,8/1/2022 6:15