13

いくつかのパラメーターを受け入れて EXE を実行する Windows CMD スクリプトがあります。最初にいくつかのハードコードされた引数を渡し、次にユーザーからのすべてのパラメーターを渡します。CMD スクリプトは次のようになります。

launcher.exe paramX paramY %*

ユーザーは、次のように Windows シェルから CMD スクリプトを実行します。

launcher.cmd param1 param2 param3 [...]

< >私が抱えている問題は、CMD スクリプトのパラメーターにや などのシェル特殊文字が含まれている場合^、ユーザーはそれぞれの前に 3 つのキャレット^シェル エスケープ文字を付けて、これらをエスケープする必要があることです。

2 つの例

1) 引数ten>oneを EXE に渡すには、ユーザーは次のように CMD を起動する必要があります。

launcher.cmd ten^^^>one

この理由は、シェルの特殊文字^>がコマンド シェルによって 2 つのレベルで解釈されるためです。最初はコマンド ラインで、2 番目は CMD スクリプト内です。そのため、キャレット^シェル エスケープ文字によるシェル エスケープを 2 回適用する必要があります。問題は、これがユーザーにとって自明ではなく、見た目が悪いことです。

この例では、より適切な解決策は、引数を二重引用符で囲むことです。ただし、これは、引数にリテラルの二重引用符を含む、より複雑な例ではうまくいきません。

2) 引数"^を EXE に渡すには、ユーザーは次のように CMD を起動する必要があります。

launcher.cmd "\"^^^^"

私の場合、制御文字、つまりコード ポイント 0x20 から 0x7E を除く、下位 ASCII 文字の任意のシーケンスを含む引数をサポートしたいと考えています。ユーザーが特定のシェル特殊文字をキャレットでエスケープする必要がある例があることを理解しています。ただし、ユーザーが EXE ではなく CMD スクリプトを呼び出しているという理由だけで、これらのケースで毎回3 つのキャレットを使用する必要はありません。

この問題は、CMD スクリプトを同じことを行う EXE に置き換えることで解決できます。ただし、シェルの特殊文字を解釈せずにパラメーターを EXE に渡すように CMD スクリプトを変更する方法はありますか?

4

2 に答える 2

8

1つの方法は、バッチ内で遅延拡張を処理することです。これは、特殊文字がそこで「特別な」意味を失うためです。

唯一の問題は、パラメーターを変数に入れることです。

このようなものが役立つ可能性があります

@echo off
setlocal DisableDelayedExpansion
rem ** At this point the delayedExpansion should be disabled
rem ** otherwise an exclamation mark in %1 can remove carets
set "param1=%~1"

setlocal EnableDelayedExpansion
rem ** Now you can use the param1, independent of the content, even with carets or quotes
rem ** but be careful with call's, because they start a second round of expansion
echo !param1!
set "tmp=!param1:~1,4!"

これで、パラメーターを引用符で囲むことができるため、キャレットは不要になります。例launcher.bat"abc>def&geh%ijk | lmn ^ opq!"

残っている唯一の問題のある特殊文字は引用符のようです。

[編集/改善]パラメータを取得する別の方法を作成します。2番目の例でも任意の文字列を受け入れることができると思います。
のような本当に硬い弦でさえ

ランチャー"^
ランチャー10^>1つの
ランチャー"& "^&

@echo off
setlocal DisableDelayedExpansion
set "prompt=X"
for %%a in (1 ) do (
    @echo on
    for %%b in (4) do (
        rem #%1#
    ) 
) > XY.txt
@echo off
for /F "delims=" %%a in (xy.txt) DO (
  set "param=%%a"
)
setlocal EnableDelayedExpansion
set param=!param:~7,-4!
echo param='!param!'

使い方?
"や^などの特殊文字を展開せずに%1を展開する唯一の方法は、REMステートメントにあります(完全に真実ではないが、それは別の話です)OK、唯一の問題は、REMが備考し、効果はありません:-)

ただし、echoを使用すると、rem行も実行される前にエコーされます(remの実行は良い言葉です)。次の問題は、それが表示され、このデバッグ出力を通常の>debug.txtで
リダイレクトできないことです。これは、forループを使用する場合にも当てはまります。

OK、次のような呼び出しで出力 のエコーをリダイレクトできます

echo on
call :myFunc > debug.txt

ただし、関数を呼び出すと、バッチファイルの%1にアクセスできなくなります。

ただし、二重のforループを使用すると、デバッグ出力のリダイレクトをアクティブにすることができ、%1にアクセスすることもできます。
プロンプトを「X」に変更したので、常に1文字の長さであることがわかります。

残っているのは、%1に#を追加する理由を説明することだけです。
これは、REM行でも、状況によっては特殊文字が認識されるためです;-)

rem This is a remark^
rem This_is_a_multiline^
rem "This is also a multiline"^

したがって、#は複数行の状況の可能性を抑制します。

于 2010-10-06T18:47:39.653 に答える
0

これは役に立ちますか:

EscapPipes.Cmd :

@echo off 

:Start
    If [%1]==[] goto :eof
    @Echo %1
    shift
goto :Start

このように開始すると:

EscapPipes.Cmd Andy Pandy "Pudding | > < and pie"  

与える

Andy
Pandy
"Pudding | > < and pie"

引用符を取り除くとすぐに、パイプ記号が有効になります。

于 2010-09-29T09:51:51.970 に答える