使用 AWK 并将结果设置为 bash variables/arrays?

Using AWK and setting results to bash variables/arrays?

我有一个文件可以复制 mySQL 的 show processlist 命令的结果。 该文件如下所示:

*************************** 1. row ***************************
Id: 1
User: system user
Host:
db: NULL
Command: Connect
Time: 1030455
State: Waiting for master to send event
Info: NULL
*************************** 2. row ***************************
Id: 2
User: system user
Host:
db: NULL
Command: Connect
Time: 1004
State: Has read all relay log; waiting for the slave
       I/O thread to update it
Info: NULL

并且它在相同的结构中继续进行了几次。

我想使用 AWK 只获取这些参数:时间、ID、命令和状态,并将这些参数中的每一个存储到不同的变量或数组中,以便我以后可以在我的 bash shell.

问题是,我的 AWK 很糟糕,我不知道如何将我想要的参数从文件中分离出来,并将它们设置为 bash 变量或数组。

非常感谢您的帮助!

编辑:到目前为止,这是我的代码

echo "Enter age"
read age
cat data | awk 'BEGIN{ RS="row"
FS="\n"
OFS="\n"}
{ print ,}
' | awk 'BEGIN{ RS="Id"}
{if ( > $age){print }}'

文件 'data' 包含我在上面粘贴的块。如果输入的 'age' 小于数据文件中的时间参数(在我的 awk 代码中是 $4),代码应该 return ID 参数,但它 return 什么都没有.

如果我删除 if 语句并打印 $4 而不是 $2,这就是我的输出

Enter age
1

1030455
1004
2144
2086
0

所以我在想,也许空白行以某种方式弄乱了我的 AWK 打印?有没有一种简单的方法可以在保留我的其他数据的同时忽略该空白行?

在第一级,您有 shell 用于 运行 任何其他 child 进程。从 child 进程中修改 parent 的环境是不可能的。当您 运行 您的 bash 脚本文件(+x 正确)时,它会作为新进程生成 (child)。它可以设置自己的环境,但当它结束直播时,您将回到原来的状态 (parent)。

您可以在 bash 和 export 上设置一些变量到它的环境。它会被它的 children 继承。但是它不能在相反的方向上完成(parent 不能从它的 child 继承)。

如果您希望在当前 bash 的上下文中从脚本文件执行一些命令,您可以 source 脚本文件。 source ./your_script.sh. ./your_script.sh 会为您完成。

如果您需要 运行 awk 为您过滤一些数据并将结果保存在 bash 中,您可以这样做:

awk ... | read foo

这是因为 read 是 shell 内置函数而不是外部进程(检查 type readhelphelp readman bash自己查一下)。

或:

foo=`awk ....`

您可以使用许多其他结构。无论您使用什么 bash 脚本,请将您的代码与 bash pitfalls webpage.

进行比较

这就是您如何使用 awk 在输入的每个 "row" 块的每一行上生成您想要的值作为一组制表符分隔的字段:

$ cat tst.awk
BEGIN {
    RS="[*]+ [[:digit:]]+[]. row [*]+\n"
    FS="\n"
    OFS="\t"
}
NR>1 {
    sub(/\n$/,"")     # remove the trailing newline
    gsub(/\n\s+/," ") # compress all multi-line fields into single lines
    gsub(OFS," ")     # ensure the only OFS in the output IS between fields

    delete n2v
    for (i=1; i<=NF; i++) {
        name = gensub(/:.*/,"","",$i)
        value = gensub(/^[^:]+:\s+/,"","",$i)
        n2v[name] = value
    }

    if (n2v["Time"]+0 > age) {  # force a numeric comparison
        print n2v["Time"], n2v["Id"], n2v["Command"], n2v["State"]
    }
}

$ awk -v age=2000 -f tst.awk file
1030455 1       Connect Waiting for master to send event

如果目标年龄已经存储在 shell 变量中,只需从同名的 shell 变量初始化 awk 变量:

$ age="2000"
$ awk -v age="$age" -f tst.awk file

以上使用 GNU awk 进行多字符 RS(您已经拥有)、gensub()\sdelete array.

当你说 "and store every one of these parameters into a different variable or array" 时,它可能意味着几件事之一,所以我会把那部分留给你,但你可能正在寻找类似的东西:

arr=( $(awk '...') )

awk '...' |
while IFS="\t" read -r Time Id Command State
do
    <do something with those 4 vars>
done

但到目前为止,最有可能的情况是您根本不想使用 shell,而是留在 awk 中。

记住 - 每次你在 shell 中写一个循环只是为了操纵文本时,你就采用了错误的方法。 UNIX shell 是调用 UNIX 工具的环境,用于一般文本操作的 UNIX 工具是 awk.

除非您编辑您的问题以告诉我们更多关于您的问题的信息,否则我们无法从现在开始猜测正确的解决方案是什么。