- ベストアンサー
バッチスクリプトでの%n展開 | エラーメッセージ解説と解決方法
- バッチスクリプトにおいて%n展開を行う際にエラーメッセージが発生しました。本記事では、エラーメッセージの内容を解説し、解決方法を提案します。
- バッチスクリプトの%n展開によるエラーメッセージについて、解説と解決方法を紹介します。コマンドの構文に誤りがある可能性がありますが、本記事ではより具体的な解決策を提供します。
- バッチスクリプトでの%n展開によるエラーメッセージを解説し、解決方法を提案します。エラーメッセージの内容から、コマンドの構文に問題がある可能性があります。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>(callは普通、バッチスクリプトやサブルーチンを呼ぶときに使うと説明されているので、少し混乱しています。) call を前置するとそのうしろの部分の構文解析が二度行われます。前回書いたように、引数の展開の方がFOR変数の展開より先なので、質問文にある、"%~%%n" は、%~ が引数みたいだけどその後ろに数字がないのでエラーになります。この時点では、%%n は %が1つになった %n です。 call を書くことで、構文解析が二回されるので、%の展開(1回目)→FOR変数の展開(1回目)→%の展開(2回目)→FOR変数の展開(2回目) となります。 call set "X=%%~%%n" ↓%の展開&%%が%に call set "X=%~%n" ↓FOR変数の展開 set "X=%~1" ↓%の展開 set "X=「引用符をはずした引数1」" >今回のように、forループの中でsetコマンドによって、変数の値を変化させる場合は、遅延展開を使わなくてはいけないのでしょうか? そうですね。for /? の遅延展開の部分にFORの中での使用について記述があります。 >、「| の使い方が誤っています。」のようなエラーが出ました。 < > & | などはCMDの特殊文字です。処理順序は、 %の展開 → 特殊文字の解釈 → FOR変数の展開 → 遅延展開 なので、環境変数AAAの中に特殊文字が含まれる場合は、%AAA% をそのまま書くとだめです。 遅延展開を使うか、二重引用符で囲むか。今回は二重引用符で囲みたくないと言うことだと思うので、遅延展開を使う必要があります。
その他の回答 (2)
- notnot
- ベストアンサー率47% (4900/10359)
>for /? の遅延展開の部分に、FORの中での遅延展開の使用について記述があります。 すいません。set /? の書き誤りです。 >notnotさんは、どうやってコマンドラインのの処理順序を理解したのですか? 実際にやってみてです。最初に行われる % の処理の時に同時に行われるほかの処理が多いのがややこしい元かもしれません。
お礼
notnotさん、御回答ありがとうございます。 setのヘルプを参照させていただきました。 僕も色々と試した結果、遅延展開は、主に2つの目的で使える事が分かりました。 まず1つ目は、forループやif文の中で、setコマンドによって 環境変数の値を変更する場合です。 2つ目は、環境変数に特殊文字が含まれており、 それをコマンドプロンプトによって展開させてくない場合です。 %・・・%で展開させた場合は、特殊文字が展開されるのですが、 !・・・!で遅延展開させた場合は、されないようです。 色々とありがとうございました。
- notnot
- ベストアンサー率47% (4900/10359)
FORの変数の展開は、構文解析のかなり後で行われますので、%%n が 1 であっても、%~%%n は %~1 のようには解釈されません。また、引数 %1 などの展開はforの繰り返しの前に行われます。 案1.繰り返しにせず素直に並べる(これが簡単) 案2. setlocal enabledelayedexpansion for /L %%n in (1,1,9) do ( call set "X=%%~%%n" if not "!X!" == "" echo 「!X!」 )
お礼
御回答ありがとうございます。 案2で御提案頂いたスクリプトを実行すると、確かに上手く行きました。 前々から思っていたのですが、callをコマンドの前につけると、 環境変数やforの制御変数およびコマンドライン引数の、展開のされ方が変化するようです。 今回の場合だと、 call set "X=%%~%%n" を set "X=%%~%%n" と書き換えると Xには、%~n が代入されます。(n=1~9) なぜこういった事が起こるのかについて知りたいと思っています。 (callは普通、バッチスクリプトやサブルーチンを呼ぶときに使うと説明されているので、少し混乱しています。) あと、案2のif notの所で、遅延展開!X!を使わずに%X%を使うと、 上手く行きませんでした。 遅延展開の意味は何となく知っているのですが、 今回のように、forループの中でsetコマンドによって、 変数の値を変化させる場合は、遅延展開を使わなくてはいけないのでしょうか?
補足
案2で提供して下さったコードブロックを参考にし、以下のようなプログラムを作成しましたところ、上手く行きました。 _________________________ @echo off setlocal set /a num=1 :loop call set "str=%%~!num!" if not "!str!" == "" ( echo %%~!num!の値:「!str!」 set /a num+=1 goto :loop ) _________________________ ところが、if notの所にある!str!を%str%とすると、"abc |de"のように特殊文字が含まれた文字列を渡した時に、「| の使い方が誤っています。」のようなエラーが出ました。 なぜ遅延展開の使わなくてはならなかったのかが分からないので、 もしお分かりあれば教えていただきたいです。
お礼
度々の御回答、ありがとうございます。 御説明を読んで、callについては理解致しました。 >for /? の遅延展開の部分に、FORの中での遅延展開の使用について記述があります。 僕はVistaを使っているのですが、Forのヘルプのどこを探しても、遅延展開についての説明は見当たりませんでした。 if not の部分で遅延展開を使うのは、%・・・%の展開の後の特殊文字の処理を回避するためだったのですね。 よーく分かりました。 色々調べてみたんですけど、コマンドプロンプトのコマンドライン処理の順序って、すごくややこしいですね。 サイトによって処理の順序が異なっている事がほとんどでした。 本当に正しい処理順序を理解するには、自分で色々と試してみなければ分からないようです。(実際に今、その事で悪戦苦闘しています。) notnotさんは、どうやってコマンドラインのの処理順序を理解したのですか?
補足
そういえばnotnotさんには、以前もOKWaveで御世話になりました。 毎度助けて頂いて、本当に感謝しています。