9

この質問に答えている間、私は説明のない奇妙な行動を見つけました

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)') do @echo %a0

番号10..100が表示されます。ここで、パイプを追加するだけです。たとえば、sortまたはなどmore、次のようになります。

for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0

%aとの間にスペースが追加されます0!パイプを通して何かをエコーするように見えます-末尾のスペースを追加します、それは簡単に見ることができます:

>_tempfile echo no space here
>_tempfile echo and here's a space|more

そしてさえ

>_tempfile <nul set /p =also a space|sort

(おそらくechoを使用してプロンプトを出力します)

これは、出力リダイレクトがない場合(ファイル内であろうとコマンド用であろうと)は発生しません。それはバグですか、それとも何かが足りませんか?どうすればスペースを取り除くことができますか?(最後の文字を削除するという汚いハックを除いてvar:~0,-1

4

2 に答える 2

8

素晴らしい興味深い質問(+1)

このスペースは、SORTではなく、CMDパーサーのパイプメカニズムによって導入されます。

FOR / Fを使用してコマンドを実行すると、コマンドは独自のCMDシェルで実行されます。また、パイプの各側は、独自のCMDシェルで実行されます。パイプされたコードブロック内で遅延拡張が失敗するのはなぜですか?を参照してください。詳細については。

したがって、コマンドは実際に3つのCMDシェルをインスタンス化します。1つはFOR / Fコマンド用であり、パイプの各側に2つ作成されます。

%CMDCMDLINE%動的変数を使用して、コマンドがどのように解析され、CMDシェルに送られるかを確認できます。コマンドラインからコマンドを実行しているため、変数名の少なくとも1つの文字を2回エスケープして、最も内側のCMDシェルに到達するまで展開されないようにする必要があります。

結果を含むコマンドは次のとおりです(先頭>は私のコマンドプロンプトです):

>for /f "delims=" %a in ('(echo %^^^cmdcmdline%^&for /l %z in (1,1,10^) do @echo %z^)^|sort') do @echo %a0
1 0
10 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
C:\Windows\system32\cmd.exe  /S /D /c" ( echo %cmdcmdline% & FOR /L %z in (1 1 10) do @ echo %z )" 0

出力の最後の行は、パイプの左側に使用されるコマンドラインです。パーサーが多くの場所にスペースを追加した方法を確認できます。

ECHOコマンドの代わりに、単純なバッチスクリプトを使用して値をエコーすることにより、問題を回避できます。

echoArgs.bat

@echo(%*

このコマンドを実行すると、目的の結果が得られます。

>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do @echoArgs %z^)^|sort') do @echo %a0
10
100
20
30
40
50
60
70
80
90

この問題を回避するもう1つの方法は、ECHOコマンドを使用して変数を作成し、変数の展開を適切にエスケープすることです。

>set cmd=@(echo %z)

>for /f "delims=" %a in ('(for /l %z in (1,1,10^) do %^^^cmd%^)^|sort') do @echo %a0
10
100
20
30
40
50
60
70
80
90

編集

>_tempfile echo and here's a space|more例も面白いです。出力ファイルの最後に余分なスペースがあります。しかし、Chad Nouisは、左側のリダイレクトのために何もソートされていないというのは正しいです。右側で任意のコマンドを使用でき、結果は同じになります。

問題の原因は依然としてパーサーですが、パーサーがコマンドを再構築する方法は興味深いものです。

>>_tempfile echo %^cmdcmdline%|rem

>type _tempfile
C:\Windows\system32\cmd.exe  /S /D /c" echo %cmdcmdline% 1>_tempfile"

コマンドの最初から最後にリダイレクトがどのように移動され、のファイルハンドル1が明示的に追加されているかに注目してください。あなたは確かに余分なスペースがどこから来ているかを見ることができます。

于 2012-06-08T14:36:44.387 に答える
0

リダイレクト演算子は、行全体ではなく、最も近いコマンドに適用されます。

echo3つのテストケースでは、 andsetコマンドのstdoutをファイルにリダイレクトしています。stdoutをリダイレクトすることにより、moreまたはにパイプするものがなくなりsortます。

ネストされたforループの例では、頭痛の種となる不要な括弧がいくつかあると思います。代わりにこれを試してください:

for /f "delims=" %a in ('for /l %z in (1,1,10^) do @echo %z^|sort') do @echo %a0
于 2012-06-08T15:23:26.063 に答える