將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... }
將數據輸出到標準輸出,並且標頭(連同其他詳細資訊)轉到標準錯誤。其中一個標題是
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
這使欄位 3
awk
成為xxxxxxxx\r
。通過使用
awk
您還可以重新引入最後一個換行符\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
在命令提示符下執行。)也沒有必要混合
grep
,awk
因為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}')
在這裡,我們將標頭數據重定向到
stdout
by-D -
並將內容保存到文件 by-o "$pos.out"
。這樣做的另一個優點是您只解析標題數據。