我正在逐行读取文件。每行如下所示:
xxyu: JHYU_IOPI
每一行都传递给 awk,如下所示。我想打印匹配模式的上一行;我可以使用 grep 来实现这一点,并且想知道我在 awk 中犯了什么错误。
#!/bin/bash
while read i
do
awk '/$i/{print a}{a=$0}' ver_in.txt
done<in.txt
我也试过这个:
#!/bin/bash
while read i
do
awk -v var="$i" '/var/{print a}{a=$0}' jil.txt
done<in.txt
编辑:在得到不使用 sh read 的建议后使用 awk。我的输入和所需的输出如下所示:
编辑1:编辑@Ed Morton awk 脚本的输入,如下所示
输入文件:cat文件
/* ----------------- AIX_RUN_WATCH ----------------- */
insert_job: AIX_RUN_WATCH job_type: BOX
owner: root
permission:
date_conditions: 1
days_of_week: su
start_times: "22:00"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 0
notification_emailaddress:
/* ----------------- AIX_stop ----------------- */
insert_job: AIXstop job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 1
/* ----------------- AIX_start ----------------- */
insert_job: AIX_start job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
cat targets
box_name: AIX_RUN_WATCH
预期产出 -
box_name: AIX_RUN_WATCH
insert_job: AIX_stop
insert_job: AIX_start
对于第一次尝试,您需要使用双引号进行 shell 变量扩展,然后转义 awk
$
运算符以防止其被 shell 扩展,但请注意,如果变量$i
包含特殊字符(如\
, ),这样使用会破坏 awk/
。[我现在跳过修复您的命令的一个或多个其他问题]。对于第二次尝试,您需要对当前行使用正则表达式匹配或字符串匹配,例如使用正则表达式匹配(部分正则表达式匹配):
或字符串匹配(完整字符串匹配),例如:
现在,谈论您尝试使用它们打印匹配模式的前一行的命令,您可以使用 awk 完成所有操作并使用 shell 循环停止;这里我们进行全字符串匹配:
或进行部分正则表达式匹配:
或进行部分字符串匹配:
或进行完整的正则表达式匹配:
您不需要 while read 循环,并且在 sh 中进行文本处理是一个坏主意(请参阅为什么使用 shell 循环处理文本被认为是不好的做法?)。
而是让您的 awk 脚本来处理这两个文件。
在读取第一个文件 (
in.txt
) 时,它在一个变量中构建一个正则表达式,该变量re
通过附加每个输入行和正则表达式“交替”(即OR)运算符来调用。当它读完第一个文件后,它需要做的第一件事就是
|
从re
. 这是必要的,因为由于它的构造方式,它re
总是以字符结尾。|
如果我们不删除它,那么尾随|
将导致正则表达式匹配ver_in.txt
.之后,
a
如果当前输入行与变量中的正则表达式匹配,则打印变量re
(如果 ver_in.txt 的第一行匹配,这将打印一个空行re
- 因为 a 是空的。如果您不希望发生这种情况,请将该行从$0 ~ re {print a}
到$0 ~ re && a != "" {print a}
)。然后,无论是否匹配,设置
a=$0
.注意:这
NR==FNR {... ; next}
是一个非常常见的 awk 习惯用法,用于以与第二个和后续输入文件不同的方式处理第一个输入文件。NR
是正在读取的所有文件的全局行计数器,并且FNR
是当前文件的行计数器....所以如果NR==FNR
,这意味着我们正在读取第一个文件。该next
语句跳到下一个输入行,防止在第一个文件中执行 awk 脚本的其余部分。你没有提供完整的数据样本,所以我自己做了一个测试:
这个 in.txt 文件将导致 re 等于
bar|foo|xxyu: JHYU_IOPI
顺便说一句,因为 awk 脚本正在对 进行正则表达式匹配
re
,所以中的行in.txt
被视为正则表达式,而不是固定文本。这意味着,如果您希望将 in.txt 中的任何正则表达式特殊字符(如、.
或许多其他字符)视为文字字符,则需要使用反斜杠对其进行转义......您必须这样做这也与您原来的 sh+awk 循环一起使用。|
[
]
上面 awk 脚本的输出:
不要使用 shell 循环来操作文本,请参阅为什么使用 shell 循环来处理文本被认为是不好的做法?. 发明 shell 的人还发明了 awk 让 shell 调用来操作文本。
在每个 Unix 机器上的任何 shell 中使用任何 awk:
原答案:
请参阅https://www.gnu.org/software/gawk/manual/gawk.html#Multiple-Line了解如何将 RS 设置为 null 让我们处理多行记录,然后将 FS 设置为换行符意味着中的每个字段这样的记录是一整行,因此我们将您的数据视为以空行分隔的记录,每条记录包含 2 行数据。
You mentioned having some other file of ght lines that indicates which should be printed, implying there are other blocks that should not be printed. If you have such a file and it looks like this:
and your other input file contains some
ght:
lines that do not match the above, e.g. see theght: whatever
blocks in the modified input file below:then the above code would be updated to: