0

シェル スクリプトを Windows バッチに変換しています。私がする必要があるのは、コマンドライン引数から 1,2 と last を除くすべてを取ることです。それらを結合し、argv として別のプログラムに送信します。

@echo off

SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
  ECHO %%A
  set /a i+=1
  IF %i% geq 2 (
    set /a c+=1;
    set candidates[!c!]=%%A
  )
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%

候補配列をargv[3..n-1]

たとえば、私が書いた場合、別のプログラムにbatch x 2 a b p渡す必要がありますa b

問題は、ループ カウンターが += 演算子によってインクリメントされていないことです。echo %1%内部に書き込むFORと、常に 0 が表示されます

4

4 に答える 4

1

あなたの質問には2つの答えがあります:

1-最初の問題は、IF %i% ...コマンドでi変数の値が変更されないことです(set /a i+=1コマンドは変数正しくインクリメントしますが)。これを解決する方法はsetlocal EnableDelayedExpansion、最初にコマンドを含め、次のようにパーセント記号でiを囲むことですIF !i! ...:(以前の回答)。ただし、Batch の配列変数は同じ名前の単純な変数とは異なることに注意する必要があります(両方が同時に存在する可能性があります)。そのため、配列要素は常に添字で記述する必要があり、配列全体を処理する方法はありません。単一の操作。詳細については、このトピックを参照してください。

プログラムでは、配列の要素を単純な変数に転送する必要があります。candidates以下の例では、同じ名前になっています (要点を述べるだけです)。

@echo off
setlocal EnableDelayedExpansion
SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
  ECHO %%A
  set /a i+=1
  IF !i! geq 2 (
    set /a c+=1
    set candidates[!c!]=%%A
  )
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
REM Transfer "candidates" array elements into "candidates" simple variable:
set candidates=
FOR /L %%i IN (1,1,%c%) do (
   set candidates=!candidates! !candidates[%%i]!
)
REM Show "candidates" simple variable:
echo %candidates%

バッチ ファイルでは、ほとんどのコマンドでスペースの代わりにコンマ、セミコロン、および等号をセパレータとして挿入できることに注意してください。ただし、SET /Aこの点に関してコマンドには別の規則があるため、セミコロンは省略しなければなりません。

2-上記で説明した配列管理とは別に、配列の代わりにリストを使用して問題を解決する方法は次のとおりです。

@echo off
SET subject=%1
shift
set count=%1
set candidates=
set lastArg=
set i=0
:nextArg
   shift
   if "%1" equ "" goto endArgv
   set /a i+=1
   set candidates=!candidates! !lastArg!
   set lastArg=%1
   goto nextArg
:endArgv
SET /a count_actual=i-3, count_expected=count
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%

アントニオ

于 2013-01-05T18:05:29.007 に答える
1

ファイル名セットとしてfor %%A in (%*)扱うため、使用しないでください。これは、特にパラメーターにor (cmd のワイルドカード一致文字)%*を渡すことができる場合に問題を引き起こす可能性があります。パターンを満たすすべてのファイルに展開されるためです。第二に、バッチは実際には配列について何も知りません - a[1] と a[2] は人間のための簡略表記にすぎません - これらは 2 つの別個の変数です。 *?

問題のParse コマンドラインを考えると、変数に連結するパラメーターの数として2番目のパラメーターを使用します。ここに私の見解があります:

@echo off
setlocal

set subject=%1

shift
set exp_count=%1

if not defined exp_count (
  echo Count not specified
  exit /b 1
)
set /a "verify=%exp_count%"
if %verify% leq 0 (
  echo Count not valid /not a positive integer/
  exit /b 2
)

set real_count=0
:loop
    shift
    if "%~1"=="" goto end_params
    set /a real_count+=1
    if %real_count% leq %exp_count% set "candidates=%candidates%%~1"
    goto loop
  )

:end_params
if %real_count% lss %exp_count% (
  echo Less parameters passed than specified!
  exit /b 3
)

echo %subject%
echo %candidates%

「ぶら下がっている」パラメーター (連結されていない最後のパラメーター) があるかどうかをチェックしていないことに注意してください。ただし、そのチェックを追加するのは簡単なはずです。コードをより柔軟にするために、意図的に省略しました。

于 2013-01-05T09:58:44.223 に答える
0

はい、あなたのコードは増加しませんi。バッチ変数置換は、ブロックの実行時ではなく、ブロックの解析時に発生します。ブロック全体forが 1 回解析されるため、ブロックが実行される%i%前にゼロに置き換えられます。for

これを無効にするには、遅延展開を有効にし、変数エスケープ文字を から に変更%!て、実行時に置換を行う必要があります。次に、ループiでインクリメントされます。for

@echo off
Setlocal EnableDelayedExpansion

SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
  ECHO %%A
  set /a i+=1
  IF !i! geq 2 (
    set /a c+=1
    set candidates[!c!]=%%A
  )
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%

;また、行末の を取り除く必要があります。括弧はバッチでは何も意味しないため、set /a c+=1;オンラインで何をしようとしているのかわかりません。set candidates[!c!]=%%A

于 2013-01-05T07:45:50.820 に答える
0

すでに多くの回答がリストされていますが、もう 1 つ追加することにしました。私のアプローチは、特定のニーズに合わせて答えをできるだけシンプルにすることです。ご不明な点がございましたら、お気軽にお問い合わせください。

これにより、遅延展開や派手なロジックを必要とせずに、必要な [3,...,n-1] 配列が作成されます。

@echo off

:: Get the First Two Parameters    
set "subject=%1"
shift
set "count=%1"
shift

:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates[%index%]=%param%"
set /a "index+=1"
goto NextParam
:EndParam

set "count_actual=%index%"
set "count_expected=%count%"

:: Show the Results
echo %count_actual%
echo %count_expected%
echo %subject%
set candidates

これは、候補が個別の変数ではなく、スペースで区切られた文字列に格納されている別の方法です。%candidates% %param%の間のスペースを任意の区切り文字に置き換えます。

@echo off

:: Get the First Two Parameters  
set "subject=%1"
shift
set "count=%1"
shift

:: Loop through the rest
set "index=0"
:NextParam
set "param=%1"
shift
set "next=%1"
:: Skip the last parameter
if not defined next goto EndParam
set "candidates=%candidates% %param%"
set /a "index+=1"
goto NextParam
:EndParam

set "count_actual=%index%"
set "count_expected=%count%"

:: Show Results
echo %count_actual%
echo %count_expected%
echo %subject%
echo %candidates%
于 2013-01-05T19:05:07.030 に答える