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

发布于 2024-08-15 13:49:00 字数 362 浏览 2 评论 0原文

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

示例:

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

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

I want to run the system command in an awk script and get its output stored in a variable. I've been trying to do this, but the command's output always goes to the shell and I'm not able to capture it. Any ideas on how this can be done?

Example:

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

Should call the strip system command and instead of sending the output to the shell, should assign the output back to $1 for more processing. Rignt now, it's sending output to shell and assigning the command's retcode to $1.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

枉心 2024-08-22 13:49:00

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

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

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

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

Note: Coprocess is GNU awk specific.
Anyway another alternative is using getline

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

Calling close(cmd) will prevent awk to throw this error after a number of calls :

fatal: cannot open pipe `…' (Too many open files)

童话里做英雄 2024-08-22 13:49:00

要在 awk 中运行系统命令,您可以使用 system()cmd |获取行

我更喜欢 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

To run a system command in awk you can either use system() or cmd | getline.

I prefer cmd | getline because it allows you to catch the value into a variable:

$ awk 'BEGIN {"date" |  getline mydate; close("date"); print "returns", mydate}'
returns Thu Jul 28 10:16:55 CEST 2016

More generally, you can set the command into a variable:

awk 'BEGIN {
       cmd = "date -j -f %s"
       cmd | getline mydate
       close(cmd)
     }'

Note it is important to use close() to prevent getting a "makes too many open files" error if you have multiple results (thanks mateuscb for pointing this out in comments).


Using system(), the command output is printed automatically and the value you can catch is its return code:

$ 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
写下不归期 2024-08-22 13:49:00

想通了。

我们使用awk的双向I/O

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

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

Figured out.

We use awk's Two-way I/O

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

passes $1 to strip and the getline takes output from strip back to $1

画尸师 2024-08-22 13:49:00
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}'
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}'
命比纸薄 2024-08-22 13:49:00

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

You can use this when you need to process a grep output:

echo "some/path/exex.c:some text" | awk -F: '{ "basename "$1"" |& getline $1; print $1 " ==> " $2}'

option -F: tell awk to use : as field separator

"basename "$1"" execute shell command basename on first field

|& getline $1 reads output of previous shell command in substream

output:
exex.c ==> some text
花期渐远 2024-08-22 13:49:00

我正在使用 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 将包含命令的完整输出。

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

I am using macOS's awk and I also needed exit status of the command. So I extended @ghostdog74's solution to get the exit status too:

Exit if non-zero exit status:

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
}

So basically I just changed cmd to print exit status of the command on a new line. After the execution of the above while loop, res would contain the exit status of the command and
value would contain the complete output of the command.

Honestly not a very neat way and I myself would like to know if there is some better way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文