将 stderr 输出存储在变量中而不修改 stdout,并重复执行此操作

将 stderr 输出存储在变量中而不修改 stdout,并重复执行此操作

考虑一个简单的服务器 API,您可以在其中使用“无状态令牌”迭代使用数据,它可能如下所示:rQAAMTQ2MzU4MDA1MjgxM3x8fC9wZXJtaWQub3JnfHx8,因此:

curl -v "http://ws.foo.bar/_consume?position=rQAAMTQ2MzU4MDA1MjgxM3x8fC9wZXJtaWQub3JnfHx8"
* Connected to ws.foo.bar (12.34.56.78) port 80 (#0)
> GET /_consume?position=rQAAMTQ2MzU4MDA1MjgxM3x8fC9wZXJtaWQub3JnfHx8 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: ws.foo.bar
> Accept: */*
> 
< HTTP/1.1 200 OK
... many irrelevant headers
< X-POSITION: qwAAMTQ2MzU4MDA1MTIxOHx8fC9wZXJtaWQub3JnfHx8
< Connection: close
< Date: Wed, 01 Jun 2016 15:02:42 GMT
{ datadatadatadatadatadatadata... }

将数据输出到 stdout,标头(以及其他详细信息)转到 stderr。其中一个标头是X-POSITION,存储我应该提供的下一个位置作为下一个数据块的查询参数。我试图想出一个简单的方法,我只需点击按钮并再次执行即可检索下一个数据块

我尝试了以下操作(假设初始位置1foo2BAR3baz4QUUX5blah:):

$ POS=1foo2BAR3baz4QUUX5blah
$ POS=$( curl -v "http://ws.foo.bar/_consume?position=$POS" 2>&1 | grep X-POSITION | awk '{print $3}' )

显然,它不会打印到屏幕数据,因为它被 吞没了grep,而且,POS只改变一次,并且不能再次使用。第二次调用时,curl 抱怨:

* Illegal characters found in URL
* Closing connection -1
curl: (3) Illegal characters found in URL

尽管 POS 似乎获得了新的价值:

$ echo $POS
rQAAMTQ2MzU4MDA1MjgxM3x8fC9wZXJtaWQub3JnfHx8

我怀疑也许是EOF?

无论如何,即使我解决了这个问题,我仍然不想忽略标准输出。尝试过这个解决方案:

$ POS=`( curl -v "http://ws.foo.bar/_consume?position=$POS" 3>&1 1>&2- 2>&3- ) | grep X-POSITION | awk '{print $3}'`

但它似乎也不起作用。

答案1

“有缺陷”参数中的字符$POS为 EOL。 HTTP 使用 CRLF 作为行结束符。例如:

< X-POSITION: xxxxxxxx\r\n

这使得 中的字段 3awkxxxxxxxx\r

通过使用printinawk您还可以重新引入最后一个换行符 ,\n但是由于您的表达式没有被引用,因此它会丢失。

您可以通过执行以下操作来看到这一点:

curl -v "http://ws.foo.bar/_consume?position=$POS" 2>&1 | cat -v

^M行尾的 s表示\r

或者:

printf "%s" "$pos" | xxd
00000000: 7251 4141 4d54 5132 4d7a 5534 4d44 4131  rQAAMTQ2MzU4MDA1
00000010: 4d6a 6778 4d33 7838 6643 3977 5a58 4a74  MjgxM3x8fC9wZXJt
00000020: 6157 5175 6233 4a6e 6648 7838 0d         aWQub3JnfHx8.

最后一个0d是 CR。 (可以选择ascii在命令提示符下执行。)

也不需要混合grepawk因为awk数学本身就很好。

为了走上正确的轨道,这可能是一个开始:

pos=$(curl -v "http://foo.x/pos=$pos" 2>&1 | awk -vRS="\r\n" '/^< X-POSITION:/{printf "%s", $3}')

这里将RS或记录分隔符设置awk为 CRLF,

...但这只会给你令牌,而不是内容。

假设您不需要实际将内容打印到屏幕上,但将其保存到文件中的一种方法可能是:

pos=$(curl -sD - -o "$pos.out" "http://foo.x/?position=$pos" | awk -vRS="\r\n" '/^X-POSITION:/{printf "%s", $2}')

在这里,我们将标头数据重定向到stdoutby-D -并将内容保存到文件 by -o "$pos.out"

这样做的另一个优点是您只需解析标头数据。

相关内容