我想在 awk 脚本中运行
system
命令并将其输出存储在变量中。我一直在尝试这样做,但命令的输出总是发送到 shell,而我无法捕获它。关于如何做到这一点有什么想法吗?
示例:
$ date | awk --field-separator=! {$1 = system("strip $1"); /*more processing*/}
应调用
strip
系统命令,而不是将输出发送到 shell,而应将输出分配回 $1
以进行更多处理。 现在,它正在将输出发送到 shell 并将命令的 retcode 分配给 $1
。
注意:协进程是 GNU awk 特定的。 无论如何,另一种选择是使用 getline
cmd = "strip "$1
while ( ( cmd | getline result ) > 0 ) {
print result
}
close(cmd)
调用
close(cmd)
将阻止 awk
在多次调用后抛出此错误:
致命:无法打开管道“...”(打开的文件太多)
要在
awk
中运行系统命令,您可以使用 system()
或 cmd | getline
。
我更喜欢
cmd | getline
,因为它允许您将值捕获到变量中:
$ awk 'BEGIN {"date" | getline mydate; close("date"); print "returns", mydate}'
returns Thu Jul 28 10:16:55 CEST 2016
更一般地,您可以将命令设置为变量:
awk 'BEGIN {
cmd = "date -j -f %s"
cmd | getline mydate
close(cmd)
}'
请注意,如果您有多个结果,请务必使用
close()
来防止出现“打开太多文件”错误(感谢 mateuscb 在评论中指出这一点)。
使用
system()
,会自动打印命令输出,你可以捕获到的值就是它的返回码:
$ awk 'BEGIN {d=system("date"); print "returns", d}'
Thu Jul 28 10:16:12 CEST 2016
returns 0
$ awk 'BEGIN {d=system("ls -l asdfasdfasd"); print "returns", d}'
ls: cannot access asdfasdfasd: No such file or directory
returns 2
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}'
当您需要处理 grep 输出时,可以使用它:
echo "some/path/exex.c:some text" | awk -F: '{ "basename "$1"" |& getline $1; print $1 " ==> " $2}'
选项
-F:
告诉 awk 使用 :
作为字段分隔符
"basename "$1""
在第一个字段上执行 shell 命令 basename
|& getline $1
读取子流中先前 shell 命令的输出
output:
exex.c ==> some text
awk
,我还需要命令的退出状态。所以我扩展了@ghostdog74的解决方案来获取退出状态:如果退出状态非零则退出:
cmd = <your command goes here>
cmd = cmd" ; printf \"\n$?\""
last_res = ""
value = ""
while ( ( cmd | getline res ) > 0 ) {
if (value == "") {
value = last_res
} else {
value = value"\n"last_res
}
last_res = res
}
close(cmd)
# Now `res` has the exit status of the command
# and `value` has the complete output of command
if (res != 0) {
exit 1
} else {
print value
}
所以基本上我只是更改了
cmd
以在新行上打印命令的退出状态。执行上述
while
循环后,
res
将包含命令的退出状态和
value
将包含命令的完整输出。老实说这不是一个很好的方法,我自己也想知道是否有更好的方法。
awk
,我想获取函数调用的输出并将其存储,以便我可以使用
printf
格式化所有内容。你不能用
system()
做到这一点,但你可以用
myCmd | getline myVar
:
#!/usr/bin/env bash
hrbytes() { # human readable bytes. numfmt is cool.
local num;
if [[ $# -lt 1 ]]; then
read num;
else
num="$1"
fi
local from
if [[ "$num" =~ [KMGTPEZY]i$ ]]; then
from="--from=iec-i"
elif [[ "$num" =~ [KMGTPEZY]$ ]]; then
from="--from=si"
fi
# purposefully not quoting from to avoid empty string issues
numfmt --to=iec-i --suffix=B --format="%.1f" $from "${num//,}"
}
export -f hrbytes
command time -l helm ls 2>&1 |
awk '/peak memory/ {"hrbytes " $1 | getline mem}; /[0-9.] real / {time=$1} END {printf "%ss; %s\n", time, mem}'
这会使用与正则表达式匹配的行上第一个字段的参数调用 hrbytes
,并将输出存储在
mem
中,我可以认为在读取文件结束时参考我的
printf
命令。这打印了
1.49s; 152.1MiB
,这就是我想看到的。