从命令输出中提取值并将该值用作后续命令的参数

从命令输出中提取值并将该值用作后续命令的参数

你好,我想拥有

curl -v --request POST https://example.com --data-urlencode "username=usr]” --data-urlencode "password=[pass]”

将输出传递到[TOKEN]此处的字段:

curl -D - --request POST https://example.com --data-urlencode token=[TOKEN]

但是,我不熟悉 JSON,因为第一个命令的输出是

{
    "token": "value_of_token"
}

我该如何接受"value_of_token"并让它成为现实[TOKEN]

答案1

为了最有效地value_of_token从命令的输出中获取curl,请将输出通过管道传输到单个sed(流编辑器)命令。使用命令替换$()将输出存储在 shell 变量中:

token=$(curl ... | sed -n '/ *"token": *"/ { s///; s/".*//; p; }')

然后您可以将该变量token作为参数引用到第二个curl命令:

curl ... token="$token"

命令解释sed

sed -n '/ *"token" *: *"/ { s///; s/".*//; p; q; }'
  • -n选项sed告诉不是打印每个输入行

  • / *"token" *: *"/寻址包含该值的行。此模式(正则表达式)匹配行的整个开头,直到并包括分隔标记值的第一个双引号。

  • {开始一个命令块,该命令块将应用于指定的行。

  • s///;sed 命令删除先前匹配的内容(在地址部分)。该线(“模式空间”)现在看起来像:value_of_token"

  • s/".*//sed 命令删除剩余的双引号 ( ") 及其后的所有内容。

  • psed 命令打印当前(编辑的)行(sed术语“模式空间”)。

  • q立即退出 sed 脚本,不再处理任何输入

  • '}' 结束命令块。

例如,

$ echo '
{                          
    "token": "value_of_token"
}
' | sed -n '/ *"token" *: *"/ { s///; s/".*//; p; }'
value_of_token
$

此方法比通过管道传输其他 4 个命令来获得相同结果要高效得多。此sed命令假设 JSON 输入中没有制表符。如果选项卡存在,则sed命令将需要修改。

答案2

首先,请注意,我必须替换命令中的 URL,<URL>因为 stackexchange 认为我在发送垃圾邮件,不允许我发帖。

好的,您这里有两个问题:

1)如何获取一个命令的输出并将其作为另一命令的参数?

答案:最规范的方法是使用 shell 的命令替换,将第二个命令中的参数替换为$( <first command> )

curl -D - --request POST <URL> --data-urlencode token=$( curl -v --request POST <URL> --data-urlencode "username=usr]” --data-urlencode "password=[pass]” )

但是,出于可读性目的,您确实应该通过保存第一个命令的输出并重新使用它来在单独的行中执行此操作,如下所示:

token=$( curl -v --request POST <URL> --data-urlencode "username=usr]” --data-urlencode "password=[pass]” )
curl -D - --request POST <URL> --data-urlencode token="$token"

另外,为了完整起见,并且因为您具体询问了如何“管道”,您可以使用 xargs 命令而不是 shell 的命令替换:

curl -v --request POST <URL> --data-urlencode "username=usr]” --data-urlencode "password=[pass]” | xargs "curl -D - --request POST <URL> --data-urlencode token="{}

但是,正如您所指出的,第一个命令的输出并不完全是您正在寻找的令牌;因此,上述解决方案不会按您的预期工作,这给我们带来了下一个问题:

2)我们如何从整个 JSON 输出中分离出“value_of_token”?

无需进入某些 JSON API,一个简单的 grep、head 和 cut 管道就可以完成这项工作:

token=$( curl -v --request POST <URL> --data-urlencode "username=usr]” --data-urlencode "password=[pass]” ) | grep '"token":' | head -1 | cut -d ':' -f 2 | cut -d '"' -f 2
curl -D - --request POST <URL> --data-urlencode token="$token"

请注意,这head -1是为了防止输出中碰巧有多个标记行,在这种情况下,仅使用第一个标记行。

您应该知道,如果此应用程序很重要,那么这不是一个非常强大的解决方案。如果是,您确实应该检查第一个curl命令的返回代码并对输出进行更广泛的验证,这样您就不会得到一些意外的结果;但这需要更大的脚本,并且超出了这个问题的范围。

相关内容