質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.33%

batで「,」が削除されるのを防ぎたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,005

dasugar

score 5

前提・実現したいこと

言語:batファイル
環境:Windows10 64bit

以下のように変数にjsonを代入し、
jqによって抽出した数値を変数に格納するバッチを作りたいと考えています

例)
set JSONDATA={"status":200,"ids":[{"id":76}]}
filter.bat "%JSONDATA%" ".ids[].id"
echo %ANS%
=> 76と出力されてほしい

該当のソースコード

@echo on
for /f %%i in ('echo %~1 ^| jq.exe %2') do set ANS=%%i

発生している問題・エラーメッセージ

しかし、上のようなバッチを書いたところ、以下のように出力されました。

> filter.bat "%JSONDATA%" ".ids[].id"
for /F %i in ('echo {"status":200 "ids":[{"id":76}]} | jq.exe ".status"') do set ANS=%i
parse error: Expected separator between values at line 1, column 19

試したこと

出力から、上のエラーはcmdの仕様でJSON内の「,」が削除された為だろうと考えています。
しかし、「,」を削除されないようにしようと「%~1」を""で囲むと、
そのままjson全体が""で囲まれた状態になってしまうため、jqがフォーマットエラーを出してしまいます。

どのように書けば期待通りの挙動にすることができるのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

jqに環境変数を読む機能があるとは知りませんでしたが、一般論的に解決すると、,をエスケープします。

set JS=%~1
for /f %%i in ('echo %JS:,=^,% ^| jq.exe %2') do set ANS=%%i

'~~'でサブシェルを起動するときに','が落ちるようです。
for in ( )の括弧の中では、, ; =などが空白となってしまいます。
参考:for %%A in (a b,c;d=e) do echo %%A

最初、

echo %~1 | for /f %%i in ('jq.exe %2') do set ANS=%%i


でいいかと思ったのですが、パイプの為にサブシェルが起動され、ANSはサブシェル内の変数になってしまい、次の行で参照できません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/27 20:44

    バッチファイルのエスケープのやり方を知らなかったので、だいたいツールかスクリプトでどうにか迂回してやり過ごしてきたのですが、こうすればできるんですね!

    キャンセル

  • 2020/01/28 17:29

    こちらのやり方でも動作することが確認できました!
    %環境変数名:置換対象=置換先% の記法があるのですね。

    bsdfanさんのご回答で十分満足でしたが、
    このQ&Aのタイトルからはotnさんのご回答の方が適していると思われるため、
    他の方が見た時の為にこちらにベストアンサーを移させていただきます。

    ご回答いただきありがとうございます。

    キャンセル

  • 2020/01/28 18:12

    この問題に関しては、bsdfanさんのがB.A.かと思いますが、
    確かに、タイトルと合うのは私の方ですね。
    それよりPowerShellかWSL+Bashを使いましょうという方針がいい気もします。

    > バッチファイルのエスケープのやり方を知らなかったので、
    カンマならできますが、記号によってはどうしようもなくてお手上げです。
    = とかは多分無理です。

    キャンセル

+1

コンマを削除させない方法は分かりませんでしたが、文字列を環境変数にセットして、jqの中でその環境変数の文字列を展開するという風にすれば、データを取り出すことはできそうです。

@echo off
setlocal
set JSONTEXT=%~1
for /f "usebackq" %%i in (`jq.exe -n "env.JSONTEXT|fromjson|%~2"`) do set ANS=%%i
echo %ANS%


JSON文字列が長すぎると、問題があるかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/27 19:23

    ご教示頂いたやり方で動作することが確認できました!
    jqに環境変数を読む機能があったのですね。勉強不足でした。

    ご回答いただきありがとうございます。
    大変助かりました。

    キャンセル

0

for文の出力結果では確かにカンマは表示されていませんが、echoだけ見ればカンマは残っているようです。
バッチファイルはこうなるような気がします。
"usebackq"を追加、()内をバッククォートに変更。

@echo on
for /f "usebackq" %%i in (`echo %~1 ^| jq.exe %2`) do set ANS=%%i


バッチファイルに与えるパラメーターは以下でしょうか。
(第2パラメーターの先頭にピリオドを追加)

> filter.bat "%JSONDATA%" ".ids[].id"


動作未検証です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/27 14:33

    ご回答いただきありがとうございます。

    ご指摘の通りにバッククォートを使うようコードを変更しても出力は同じでした。
    そもそもjson内にはシングルクォートは含まれておらず、
    usebackqで区切り文字が変わっただけであるため、挙動は変わらない、と考えます。

    加えて、「echoだけ見ればカンマは残っている」と頂いておりますが、
    jsonの「200,"ids」がechoでは「200 "ids」になっているので、
    カンマはやはり消えているのではないでしょうか?

    > バッチファイルに与えるパラメーターは以下でしょうか。
    > (第2パラメーターの先頭にピリオドを追加)
    こちらコピペミスしておりましたので修正いたしました。
    大変失礼いたしました。

    キャンセル

  • 2020/01/27 15:02

    ごめんなさい。
    あまり関係ありませんでしたね。
    どうもfor文内でのみカンマが消えてしまうようで困りましたね。
    代替案として、一旦%JSONDATA%をファイルに出力して、それをjqに与えるのではどうでしょうか?
    当方jqの環境がないため確認できていませんが。。。
    echo %~1 > tmp.txt
    for /f %%i in ('type tmp.txt ^| jq.exe %2') do set ANS=%%i
    del tmp.txt

    キャンセル

  • 2020/01/27 15:53

    もしくはjqの結果をファイルに出力する方が素直な考え方かもしれません。
    echo %~1 | jq.exe %2 > tmp.txt
    for /f %%i in (tmp.txt) do set ANS=%%i
    del tmp.txt

    キャンセル

  • 2020/01/27 19:30

    説明不足ですみません。
    実は現在は提案頂いたようなコードでファイルに読み書きすることで代替していました。
    しかし、毎度ファイルに出すのも無駄なので質問させていただいておりました。

    今回はbsdfanさんのご回答で解決できましたが、
    カンマが消されること自体は防げていないのでまた勉強するように致します。

    ご回答いただきありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る