将系统命令的输出分配给变量

问题描述 投票:0回答:7

我想在 awk 脚本中运行

system
命令并将其输出存储在变量中。我一直在尝试这样做,但命令的输出总是发送到 shell,而我无法捕获它。关于如何做到这一点有什么想法吗?

示例:

$ date | awk --field-separator=! {$1 = system("strip $1"); /*more processing*/}

应调用

strip
系统命令,而不是将输出发送到 shell,而应将输出分配回
$1
以进行更多处理。 现在,它正在将输出发送到 shell 并将命令的 retcode 分配给
$1

awk pipe
7个回答
79
投票

注意:协进程是 GNU awk 特定的。 无论如何,另一种选择是使用 getline

cmd = "strip "$1
while ( ( cmd | getline result ) > 0 ) {
  print  result
} 
close(cmd)

调用

close(cmd)
将阻止
awk
在多次调用后抛出此错误:

致命:无法打开管道“...”(打开的文件太多)


52
投票

要在

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

35
投票

想通了。

我们使用 awk 的 双向 I/O

{
  "strip $1" |& getline $1
}

将 $1 传递给 strip,getline 将 strip 的输出返回到 $1


6
投票
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}'

5
投票

当您需要处理 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
    

3
投票
我正在使用 macOS 的

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
 将包含命令的完整输出。

老实说这不是一个很好的方法,我自己也想知道是否有更好的方法。


0
投票
使用 GNU

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

,这就是我想看到的。

© www.soinside.com 2019 - 2024. All rights reserved.