コマンド出力から値を抽出し、その値を後続のコマンドのパラメータとして使用する

コマンド出力から値を抽出し、その値を後続のコマンドのパラメータとして使用する

こんにちは、私は

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(ストリーム エディター) コマンドにパイプします。コマンド置換を使用して$()、出力をシェル変数に格納します。

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

token次に、 2 番目のコマンドのパラメーターとして変数を参照できますcurl

curl ... token="$token"

コマンドの説明sed:

sed -n '/ *"token" *: *"/ { s///; s/".*//; p; q; }'
  • -nオプションsedないすべての入力行を印刷する

  • / *"token" *: *"/値を含む行を指定します。このパターン (正規表現) は、トークン値を区切る最初の二重引用符まで、行の先頭全体に一致します。

  • {アドレス指定された行に適用されるコマンド ブロックを開始します。

  • s///;sed コマンドは、以前に一致したもの (アドレス部分) を削除します。行 (「パターン スペース」) は次のようになります。value_of_token"

  • s/".*//残っている二重引用符 ( ") とそれ以降のすべてを削除するには、sed コマンドを使用します。

  • p現在の(編集された)行(sed用語では「パターン スペース」)を印刷する sed コマンド。

  • qそれ以上の入力を処理せずにsedスクリプトを直ちに終了します。

  • '}' はコマンド ブロックを終了します。

例えば、

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

この方法は、同じ結果を得るために他の 4 つのコマンドをパイプするよりもはるかに効率的です。このsedコマンドは、JSON 入力にタブ文字がないことを前提としています。タブが存在する場合は、コマンドsedを変更する必要があります。

答え2

<URL>まず、 stackexchange が私がスパム行為をしていると判断して投稿を許可しなかったため、コマンド内の URL を に置き換える必要があったことに注意してください。

さて、ここでは 2 つの質問があります。

1) あるコマンドの出力を別のコマンドの引数にするにはどうすればよいですか?

$( <first command> )回答: 最も標準的な方法は、シェルのコマンド置換を使用して、2 番目のコマンドの引数を次のように置き換えることです。

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 コマンドを使用することもできます。

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 コマンドの出力の戻りコードを確認し、より広範な検証を行う必要があります。ただし、それにはより大きなスクリプトが必要になり、この質問の範囲を超えています。

関連情報