Shell-Script

將stderr輸出儲存在變數中而不修改stdout,並重複這樣做

  • January 13, 2019

考慮一個簡單的伺服器 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... }

將數據輸出到標準輸出,並且標頭(連同其他詳細資訊)轉到標準錯誤。其中一個標題是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}'`

但它似乎也不起作用。

參數中的*“故障”*字元$POS為 EOL。HTTP 使用 CRLF 作為行尾。例如:

< X-POSITION: xxxxxxxx\r\n

這使欄位 3awk成為xxxxxxxx\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"

這樣做的另一個優點是您只解析標題數據。

引用自:https://unix.stackexchange.com/questions/286929