從命令輸出中提取值並將該值用作後續命令的參數

從命令輸出中提取值並將該值用作後續命令的參數

你好,我想擁有

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命令的返回代碼並對輸出進行更廣泛的驗證,這樣您就不會得到一些意外的結果;但這需要更大的腳本,並且超出了這個問題的範圍。

相關內容