web-dev-qa-db-ja.com

batファイル内の文字列をコマンドラインパラメータ文字列に置き換える方法

私はcmdバッチファイルで以下を持っています:

for /f %%l in (%2) do (for %%f in (%%l) do copy "%%f" %1))

注:このスクリプトは基本的に、パスが%2で指定されているセミコロン区切りのtxtファイルを含むテキストファイルを読み取り(たとえば、c:\ test1\file1.cs; d:\ file2.jsを含む)、ファイルを宛先にコピーします%1で指定されたフォルダ。

%1パラメータのxの文字列値(バッチファイルにも渡される%3など)を、パラメータとしてバッチに渡される%4値に置き換える必要があります。ファイル。

例えば。:

if %1 = 'test replace x with y'
%3=x
%4=y

したがって、出力は「yをyに置き換えるテスト」になるはずです。

Windows CMDバッチインタープリターを使用してこれを実現するにはどうすればよいですか?

14
DSharper

まず、%1を変数に格納する必要があります。そうすると、置換を実行できるようになります。

基本的に、置換の構文は次のとおりです。

%variable:str1=str2%

つまり、 'variableのすべてのstr1str2'に置き換えます。

あなたの場合、str1str2はどちらもパラメータであり、リテラル文字列ではありません。上記のテンプレートを直接使用すると、次の式になる可能性があります。

%variable:%3=%4%

ただし、%3および%4を最初に評価する必要があることがわからないため、パーサーを混乱させることになります。実際、最初に%variable:%を評価しようとします(そして失敗します)。

この場合の解決策の1つは、 'lazy'遅延評価と呼ばれるメソッドを使用することです。基本的に、変数を評価する場所のコマンドをCALLコマンドに渡します。元のコマンドの「CALLバージョン」への変換は次のようになります。

ECHO %var% ==> CALL ECHO %%var%%

二重%sに注意してください。解析時に、それらは単一の%sに評価されます。結果のコマンドはCALLによって再度解析され、最終的な効果は元のコマンドECHO %var%の場合と同じになります。

したがって、元のコマンドと同じように機能し(これは優れています)、ここで得られるのは評価の後半です。つまり、変数が実際にその値に置き換えられました。その影響を知っているので、%3%4が最初に評価され、次に結果の式全体が評価されるように、式を作成できます。具体的には、このように:

%%variable:%3=%4%%

最初の解析後、この式は次のようになります。

%variable:x=y%

それは再び解析され、出力はvariableの変更された内容になります。

よりわかりやすくするために、ここに簡単な作業例を示します。

SET "output=%1"
CALL SET output=%%output:%3=%4%%
ECHO %output%

[〜#〜]更新[〜#〜]

同じことをする別の方法があります。おそらく最初に述べたはずです。

Windowsコマンドシェルは、proper遅延展開をサポートしています。使用方法は簡単ですが、いくつかの注意点があります。

最初に、それを使用する方法。遅延拡張の構文は、即時拡張の!var!ではなく%var%です(これは有効なままであり、遅延拡張構文と一緒に使用できます)。

コマンドで構文を有効にするまで、おそらく!var!はスクリプトで機能しません。

SETLOCAL EnableDelayedExpansion

ENDLOCALコマンドは、遅延拡張構文が有効であり、コマンドシェルによって解釈されるブロックを閉じます。

上記のサンプルスクリプトは、次のように書き直すことができます。

SET "output=%1"
SETLOCAL EnableDelayedExpansion
SET output=!output:%3=%4!
ECHO !output!
ENDLOCAL

SET output=!output:%3=%4!コマンドの場合にこれがどのように機能するか:

  • %3%4はすぐに、つまり解析時に評価されます。これらはそれぞれxyに置き換えられます。

  • コマンドは次のようになります:SET output=!output:x=y!;

  • コマンドが実行されようとしています– !式が評価されます(xsはysに置き換えられます);

  • コマンドが実行されます-output変数が変更されます。

今警告について。最初に覚えておくべきことは、!が構文の一部になり、遭遇するたびに消費および解釈されることです。そのため、リテラルとして使用する場所でエスケープする必要があります(^!など)。

もう1つの警告は、SETLOCAL/ENDLOCALブロックの主な影響です。問題は、そのようなブロック内の環境変数へのすべての変更がローカルなことです。ブロックを終了すると(ENDLOCALを実行すると)、変数は変数に入る前の値(SETLOCALを実行する前)に設定されます。つまり、変更されたoutputの値は、最初に遅延拡張を使用するために開始しなければならなかったSETLOCALブロック内でのみ有効になります。値を変更してすぐに使用する必要がある場合、これは特定のケースでは問題にならない可能性がありますが、将来のために覚えておく必要があります。

注:jebのコメントに従って、次のトリックを使用して、変更した値を保存し、SETLOCALブロックを離れることができます。

ENDLOCAL & SET "output=%output%"

&演算子は、コマンドが同じ行に配置されている場合にコマンドを区切るだけです。これらは、指定された順序で次々に実行されます。問題は、行を解析する時点では、SETLOCALブロックがまだ残っていないため、%output%は変更された値に評価され、それはまだ有効です。しかし、割り当ては実際に実行されますENDLOCAL、つまり、ブロックを離れた後。したがって、ブロックを終了した後、変更された値を効果的に保存し、変更を保存します。 (ありがとう、jeb!)


詳しくは:

  1. 遅延拡張について:

  2. 部分文字列の置換について:

50
Andriy M

私はWindows 7のバッチファイルで以下のコードを試しました:

SET output=%1
CALL SET output=%output:unsigned=signed%
CALL SET output=%output:.apk=-aligned.apk%

できます !

1
Eddie Cheung

1つの文字列で複数のパラメータを置き換える必要がある場合は、「for/f」を使用して、次のように以前の置換で変数を設定します。

SET "output1=%1"
CALL SET output1=%%output1:%3=%4%%
for /f "tokens=1" %%a in ('echo %output1%') do set output2=%%a
CALL SET output2=%%output2:%5%6%
for /f "tokens=1" %%a in ('echo %output2') do set output3=%%a
0
michael