バッチファイルでパラメーターが空かどうかをテストする適切な方法は何ですか?


212

変数が設定されているかどうかをテストする必要があります。私はいくつかの技術を試してみたが、彼らはいつでも失敗するようで%1、このような場合のように引用符で囲まれて%1います"c:\some path with spaces"

IF NOT %1 GOTO MyLabel // This is invalid syntax
IF "%1" == "" GOTO MyLabel // Works unless %1 has double quotes which fatally kills bat execution
IF %1 == GOTO MyLabel // Gives an unexpected GOTO error.

このサイトによると、これらはサポートされているIF構文タイプです。だから、私はそれを行う方法がわかりません。

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command

1
私のシステム(Windows 2003およびWindows 7)では、二重引用符の数が偶数であるif "%1" == "" GOTO MyLabel限り、スクリプトの実行を致命的に強制終了しません%1。奇数の二重引用符が%1このエラーでスクリプトの実行を強制終了していることがわかります。The syntax of the command is incorrect.問題を解決するために角かっこを使用する以下の解決策は正解としてマークされていますが、それはそれ以上うまく行っていないようです。そのソリューションも%1奇数の二重引用符があると同じエラーで失敗します。
Susam Pal 2013

@SusamPal興味深い。その下の括弧バージョンを試して、それが機能するかどうかを確認してください。それは私がもっとテストしたものです。数日前に承認された回答を更新しました。
blak3r 2013年

ダン・ストーリーの答えは確かにうまくいくようです。角括弧を使用したバージョンを使用しました。
Susam Pal 2014

良い「すべてをキャッチする」例:stackoverflow.com/questions/830565/…引数でファイル/ディレクトリと一般的な文字列/数値の両方をカバーします。

とてもイライラIF DEFINEDします。スクリプト変数ではなく環境変数でのみ作業するのは、潜在的な無駄です。
kayleeFrye_onDeck

回答:


290

引用符の代わりに角括弧を使用します。

IF [%1] == [] GOTO MyLabel

括弧は安全ではありません。角括弧のみを使用してください。


11
括弧は安全ではありません!&inのようなコンテンツ%1は線を
引き

14
引数にスペースがない限り、if #%1#==##またはなどの他の文字を使用するif [%1]==[]ことをお勧めし…was unexpected at this timeます。そうしないと、エラーが発生します。
Synetech、2013

12
そして"%~1"、私の回答で述べたように、使用することは本当に良いアプローチです。
jamesdlin

8
みんな、@ jamesdlinは正しいです。このアプローチは、可変テキストにスペースが含まれている場合、またはである場合は機能しません==。代わりに彼の答えを使用してください。
James Ko

4
あなたはそれを明確にしませんit DOES NOT work with spaces。代わりに@jamesdlin回答を使用してください。
JB。モニカと。

153

以下を使用できます。

IF "%~1" == "" GOTO MyLabel

引用符の外側のセットを削除します。一般的に、変数にスペースが含まれている場合でも機能するため、角かっこを使用するよりも信頼性の高い方法です。


9
これは確かにそれを行う良い方法です。を使用する~と、外側の引用符がある場合はそれを取り除きますが、手動で追加し直します(1つのセットのみを保証します)。さらに、引数にスペースが含まれている場合は、引用符を使用する必要あります(#引用符の代わりに使用するか、角かっこの以前のバージョンで、スペースを含む引数が…was unexpected at this timeエラーをスローする原因となったとき、私はこれを苦労して学びました。)
Synetech

4
これは、%1などの引数ではなく、%MYVAR%などの一般的な変数にも適用できますか?
simpleuser

4
@simpleuserおっと、そうです、一般的な環境変数では機能しません。
jamesdlin 2017

1
エスケープシーケンスとしてダブル '"'を使用する文字列に注意してください-比較しようとするとスクリプトがクラッシュします。たとえば、""this string will crash the comparison""ダブル '"'は適切なエスケープシーケンスであり、ダブル '"'の置換を行うと失敗します。文字列が空です
Tydaeus '26 / 10/26

1
@Amalgovinusおそらく、変数を引数としてサブルーチンに渡し、サブルーチンに使用させることができます"%~1"
jamesdlin

38

最良の半解決策の1つは、%1変数にコピーしてから、delayedExpとして遅延拡張を使用することです。コンテンツに対して常に安全です。

set "param1=%~1"
setlocal EnableDelayedExpansion
if "!param1!"=="" ( echo it is empty )
rem ... or use the DEFINED keyword now
if defined param1 echo There is something

これの利点は、param1の処理が絶対に安全であることです。

そして、param1の設定は多くの場合に機能します。

test.bat hello"this is"a"test
test.bat you^&me

しかし、それでも次のような奇妙な内容で失敗します

test.bat ^&"&

存在について100%正しい答えを得ることができる

%1空かどうかを検出しますが、一部のコンテンツではコンテンツをフェッチできません。
これは、空%1と空の区別にも役立ち""ます。コマンド
の機能を使用してCALL、バッチファイルを中止せずに失敗します。

@echo off
setlocal EnableDelayedExpansion
set "arg1="
call set "arg1=%%1"

if defined arg1 goto :arg_exists

set "arg1=#"
call set "arg1=%%1"
if "!arg1!" EQU "#" (
    echo arg1 exists, but can't assigned to a variable
    REM Try to fetch it a second time without quotes
    (call set arg1=%%1)
    goto :arg_exists
)

echo arg1 is missing
exit /b

:arg_exists
echo arg1 exists, perhaps the content is '!arg1!'

コンテンツを取得するために100%防弾になりたい場合は、最も奇妙なコマンドラインパラメーターを受け取る方法をお読みください。


18

IF /?から:

コマンド拡張が有効になっている場合、IFは次のように変更されます。

IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command

……

DEFINED条件は、環境変数名を受け取り、環境変数が定義されている場合にtrueを返すことを除いて、EXISTSと同じように機能します。


1
はい、私は実際にこのアプローチを試しましたが、これからわか​​るのは、これが環境変数でのみ機能することです。したがって、%1またはバッチファイル内で定義された変数では機能しませんでした。
blak3r 2010年

2
それは同類にのみ当てはまります%1。「バッチファイル内で定義される変数」は、実際にバッチファイルの実行中の環境変数であり、IF DEFINEDそれらを使用できます。
zb226 2013年

8

残念ながら、私は自分で書く必要があった現在の回答にコメントしたり投票したりするのに十分な評判がありません。

もともとOPの質問は「パラメータ」ではなく「変数」と言っていましたが、これは特に、空白の変数をテストする方法を検索するためのgoogleの一番のリンクだったため、非常に混乱しました。私の元の回答以来、Stephanは正しい用語を使用するように元の質問を編集しましたが、特にGoogleが変数のためにここでも人々を送信している場合は、私の回答を削除するのではなく、混乱を解消するためにそのままにしておくことにしました。

%1は変数ではありません!これはコマンドラインパラメータです。

非常に重要な区別。変数ではなくコマンドラインパラメータを参照する単一のパーセント記号とその後に番号を付けます。

変数は、setコマンドを使用して設定され、2つのパーセント記号を使用して呼び出されます(1つは前と1つ後)。たとえば、%myvar%

空の変数をテストするには、「if not defined」構文を使用します(変数を明示的に指定するコマンドにはパーセント記号は必要ありません)。次に例を示します。

set myvar1=foo  
if not defined myvar1 echo You won't see this because %myvar1% is defined.  
if not defined myvar2 echo You will see this because %myvar2% isn't defined.

(コマンドラインパラメーターをテストする場合は、jamesdlinの回答を参照することをお勧めします。)


1
あなたが正しいです。しかし、正しい方法は、タイトルをからif variable is emptyに修正することif parameter is emptyでした。やった。(パラメータの代わりに変数をチェックしたため、質問に答えなかったため、とにかく無効です)
Stephan

1
OKステファン、ありがとう。更新を反映するように回答を編集しました。
AutoMattTick 2018

6

「IF DEFINED変数コマンド」を使用して、バッチファイル内の変数をテストします。

ただし、バッチパラメータをテストする場合は、以下のコードを試して、トリッキーな入力(「1 2」やab ^> cdなど)を避けてください。

set tmp="%1"
if "%tmp:"=.%"==".." (
    echo empty
) else (
    echo not empty
)

5

以下のコードでテストしましたが、問題ありません。

@echo off

set varEmpty=
if not "%varEmpty%"=="" (
    echo varEmpty is not empty
) else (
    echo varEmpty is empty
)
set varNotEmpty=hasValue
if not "%varNotEmpty%"=="" (
    echo varNotEmpty is not empty
) else (
    echo varNotEmpty is empty
)

変数に引用符が含まれている場合、ソリューションは失敗します。ところでIF DEFINED var、理由のある構文があります
jeb

4

私は通常これを使用します:

IF "%1."=="." GOTO MyLabel

%1が空の場合、IFは "。"を比較します。「。」に これはtrueと評価されます。


4
これは誤りです。これは同じことです。もしIF "%1" == ""この投稿の理由は、%1自体が引用符を持っている場合に失敗しました。
blak3r 2010年

%1が空かどうか、または引用符があるかどうかをテストしようとしていますか?質問は不明確です。%1のコマンドラインで何も指定されていない場合、私の答えは機能します。
失神

>%1が空かどうか、または引用符があるかどうかをテストしようとしていますか? @aphoria、両方を処理できる必要があります。
Synetech 2012年

%1%が設定されているかどうかを確認するためにこれを使用して、うまくいきました。よろしくお願いいたします。
チャーリーA

4

有効なスクリプトが多数あるため、ここでの回答に基づいてこの小さなバッチスクリプトを作成しました。同じ形式に従っている限り、これに追加してかまいません。

REM Parameter-testing

Setlocal EnableDelayedExpansion EnableExtensions

IF NOT "%~1"=="" (echo Percent Tilde 1 failed with quotes) ELSE (echo SUCCESS)
IF NOT [%~1]==[] (echo Percent Tilde 1 failed with brackets) ELSE (echo SUCCESS)
IF NOT  "%1"=="" (echo Quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1]==[] (echo Brackets one failed) ELSE (echo SUCCESS)
IF NOT "%1."=="." (echo Appended dot quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1.]==[.] (echo Appended dot brackets one failed) ELSE (echo SUCCESS)

pause

4

空の文字列はdouble-quotes/のペアです。""長さをテストするだけです。

set ARG=%1
if not defined ARG goto nomore

set CHAR=%ARG:~2,1%
if defined CHAR goto goon

次に、それが2文字であることをテストしdouble-quotesます。

if ^%ARG:~1,1% == ^" if ^%ARG:~0,1% == ^" goto blank
::else
goto goon

これがあなたが遊ぶことができるバッチスクリプトです。空の文字列を正しくキャッチすると思います。

これは単なる例であり、スクリプトに従って上記の2(または3?)ステップをカスタマイズする必要があるだけです。

@echo off
if not "%OS%"=="Windows_NT" goto EOF
:: I guess we need enableExtensions, CMIIW
setLocal enableExtensions
set i=0
set script=%0

:LOOP
set /a i=%i%+1

set A1=%1
if not defined A1 goto nomore

:: Assumption:
:: Empty string is (exactly) a pair of double-quotes ("")

:: Step out if str length is more than 2
set C3=%A1:~2,1%
if defined C3 goto goon

:: Check the first and second char for double-quotes
:: Any characters will do fine since we test it *literally*
if ^%A1:~1,1% == ^" if ^%A1:~0,1% == ^" goto blank
goto goon

:goon
echo.args[%i%]: [%1]
shift
goto LOOP

:blank
echo.args[%i%]: [%1] is empty string
shift
goto LOOP

:nomore
echo.
echo.command line:
echo.%script% %*

:EOF

この拷問のテスト結果:

.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""
args[1]: [::]
args[2]: [""] is empty string
args[3]: [">"""bl" "]
args[4]: ["< "">"]
args[5]: [(")(")]
args[6]: [""] is empty string
args[7]: [::]
args[8]: [""-"  "]
args[9]: ["( )"">\>"]
args[10]: [""] is empty string

command line:
.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""

空の文字列は二重引用符が2つ付いた文字列ではなく""、空の文字列は空の文字列 ``であり、バッチでは空の変数は未定義の変数です。引数の外側の引用符が削除されるように定義できますが、その後、文字列は長さが0の空のままです
jeb

このコンテキスト(win cmd引数)では、他の方法で空の文字列を表すことはできません。Unixシェルでは同じように空の二重引用符を1つ使用することもできません。
user6801759 2016年

はい、""空の文字列にも使用されますが%~1、外側の引用符を削除するのは非常に簡単です。このような複雑なソリューションを使用する必要はありません
ジェブ

空の文字列だけでなく、引数を列挙する安全な方法です。などのその他の方法は、有効な引数であるの"%~1"==""ような引数で失敗し"Long File Name".txtます。編集:あなたが言ったように、それは間違いなく複雑ではありません。上記の2つの手順はテスト用で、残りは詳細な例です。
user6801759 2016年

「if not defined ARG」は完全に機能しているようです(変数がコマンドラインから
取得さ


3

スクリプト1:

入力( "Remove Quotes.cmd" "This is a Test")

@ECHO OFF

REM Set "string" variable to "first" command line parameter
SET STRING=%1

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

REM IF %1 [or String] is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel


REM   OR   IF "." equals "." GOTO MyLabel
IF "%STRING%." == "." GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

PAUSE

出力(なし、%1は空白、空、またはNULLではありませんでした):


上記のスクリプトを使用して、パラメーターなしで( "Remove Quotes.cmd")を実行します1

出力(%1は空白、空、またはNULL):

Welcome!

Press any key to continue . . .

注:変数を IF ( ) ELSE ( )ステートメント、「IF」ステートメントを終了するまでを定義できません(「遅延変数拡張」が有効になっていない限り、有効になったら、代わりに感嘆符「!」を使用してください。パーセント「%」記号}。

例えば:

スクリプト2:

入力( "Remove Quotes.cmd" "This is a Test")

@ECHO OFF

SETLOCAL EnableDelayedExpansion

SET STRING=%0
IF 1==1 (
  SET STRING=%1
  ECHO String in IF Statement='%STRING%'
  ECHO String in IF Statement [delayed expansion]='!STRING!'
) 

ECHO String out of IF Statement='%STRING%'

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

ECHO String without Quotes=%STRING% 

REM IF %1 is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

ENDLOCAL
PAUSE

出力:

C:\Users\Test>"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd" "This is a Test"  
String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is a Test"'  
String out of IF Statement='"This is a Test"'  
String without Quotes=This is a Test  

C:\Users\Test>  

注:文字列内の引用符も削除されます。

例(スクリプト1または2を使用):C:\ Users \ Test \ Documents \ Batch Files> "Remove Quotes.cmd" "This is" a "Test"

出力(スクリプト2):

String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is "a" Test"'  
String out of IF Statement='"This is "a" Test"'  
String without Quotes=This is a Test  

スクリプト2でパラメーターなしで実行( "Remove Quotes.cmd")します。

出力:

Welcome!

Press any key to continue . . .

3

まとめると:

set str=%~1
if not defined str ( echo Empty string )

%1が ""または "または空の場合、このコードは"空の文字列 "を出力します。現在正しくない受け入れられた回答に追加しました。


0

私はネットで多くの答えを出して多くの問題を抱えてきました。ほとんどはほとんどのことで機能しますが、常にそれぞれを壊すコーナーケースがあります。
引用符がある場合は機能しない可能性があります。引用符がない場合は破損する可能性があります。varにスペースがある場合は構文エラー、一部は環境変数ではなくパラメータでのみ機能し、他の手法では空を許可します「定義済み」として渡す引用符のセット。一部のトリッキーな引用符では、チェーンを作成できません。else後から。

これが私が満足している解決策です、それがうまくいかないコーナーケースを見つけたら私に知らせてください。

:ifSet
if "%~1"=="" (Exit /B 1) else (Exit /B 0)

あなたのスクリプトまたはそれ自身のの中にそのサブルーチンが.batあればうまくいくはずです。
したがって、(疑似で)書き込みたい場合:

if (var)
then something
else somethingElse

あなたは書ける:

(Call :ifSet %var% && (
    Echo something
)) || (
    Echo something else
)

それは私のすべてのテストでうまくいきました:

(Call :ifSet && ECHO y) || ECHO n
(Call :ifSet a && ECHO y) || ECHO n
(Call :ifSet "" && ECHO y) || ECHO n
(Call :ifSet "a" && ECHO y) || ECHO n
(Call :ifSet "a a" && ECHO y) || ECHO n

Echo'd nynyy


その他の例:

  • 確認したいだけifですか?Call :ifSet %var% && Echo set
  • そうでない場合でも(他の人だけ)? Call :ifSet %var% || Echo set
  • 渡された引数を確認します。正常に動作します。Call :ifSet %1 && Echo set
  • スクリプト/重複コードを詰まらせたくなかったので、それを独自のものに入れifSet.batますか?問題ない:((Call ifSet.bat %var%) && Echo set) || (Echo not set)

ケースを見つけました。if with else構文を試し、thenブロックの最後のコマンドが失敗した場合、elseは次のように実行されます:(Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echotrue false
echos

実際、これが問題であり、追加の回線を処理できる場合はifSet、独自に呼び出してからIf %errorlevel% EQU 0 (x) Else (y)
Hashbrown

受け入れられた回答(角括弧を使用)が機能しないのはどのような場合ですか?そして、出口/ Bが何をするかを説明できますか
blak3r

何らかの理由で、私がテストしたとき、set変数を使用すると(のように[%bob%]、のような引数に対してのみ機能するように[%2])壊れましたが、今では再チェックが機能します。私の[]今の唯一の不満は、空の引用符が渡されることですが、これは(実際にはユースケース
次第です

/Bフラグは、サブルーチンまたは出る、出るからバッチ全体を停止callD」バッチ。コマンド全体が何をしているのか質問していない限り; 呼び出し元のスクリプトは(サブルーチンの結果を知らせるためにエラーコードを返します0、パスを1、または経由での回答では、使用可能な経由ブール論理を不合格)%errorlevel%上記のコメントで
Hashbrown

0

を使用して 空の文字列をチェックする場合は "の代わりに

@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty

1
先端は本当に悪いです。引用符は少なくともスペースと特殊文字を処理できますが、感嘆符は処理できません。そして、遅延拡張が有効になっている場合、感嘆符はここで非常に厄介です
jeb

0

私は1か月足らずで入ってきました(8年前に尋ねられた場合でも)...彼/彼女がバッチファイルを超えて移動したことを願っています。;-)私はいつもこれをやっていました。しかし、最終的な目標が何かはわかりません。私のように怠け者の場合、私のgo.batはそのようなもので機能します。(下記参照)しかし、1は、入力を直接コマンドとして使用している場合、OPのコマンドが無効になる可能性があります。つまり、

"C:/Users/Me"

は無効なコマンドです(または、別のドライブにいた場合に使用されていました)。2つの部分に分割する必要があります。

C:
cd /Users/Me

そして、2、「定義済み」または「未定義」はどういう意味ですか?ギゴ。デフォルトを使用してエラーをキャッチします。入力がキャッチされない場合は、ヘルプ(またはデフォルトのコマンド)にドロップされます。したがって、入力がないことはエラーではありません。入力にcdして、エラーがある場合はエラーをキャッチできます。(さて、go "downloads(1つの括弧のみ)を使用すると、DOSによってキャッチされます。(厳しい!))

cd "%1"
if %errorlevel% neq 0 goto :error

そして、3、引用符は、パスではなく、コマンドではなく必要です。つまり、

"cd C:\Users" 

別のドライブを使用しているのでない限り、それは悪かった(または昔は慣れていた)。

cd "\Users" 

機能しています。

cd "\Users\Dr Whos infinite storage space"

パスにスペースがある場合に機能します。

@REM go.bat
@REM The @ sigh prevents echo on the current command
@REM The echo on/off turns on/off the echo command. Turn on for debugging
@REM You can't see this.
@echo off
if "help" == "%1" goto :help

if "c" == "%1" C:
if "c" == "%1" goto :done

if "d" == "%1" D:
if "d" == "%1" goto :done

if "home"=="%1" %homedrive%
if "home"=="%1" cd %homepath%
if "home"=="%1" if %errorlevel% neq 0 goto :error
if "home"=="%1" goto :done

if "docs" == "%1" goto :docs

@REM goto :help
echo Default command
cd %1
if %errorlevel% neq 0 goto :error
goto :done

:help
echo "Type go and a code for a location/directory
echo For example
echo go D
echo will change disks (D:)
echo go home
echo will change directories to the users home directory (%homepath%)
echo go pictures
echo will change directories to %homepath%\pictures
echo Notes
echo @ sigh prevents echo on the current command
echo The echo on/off turns on/off the echo command. Turn on for debugging
echo Paths (only) with folder names with spaces need to be inclosed in         quotes (not the ommand)
goto :done

:docs
echo executing "%homedrive%%homepath%\Documents"
%homedrive%
cd "%homepath%\Documents"\test error\
if %errorlevel% neq 0 goto :error
goto :done

:error
echo Error: Input (%1 %2 %3 %4 %5 %6 %7 %8 %9) or command is invalid
echo go help for help
goto :done

:done

cd/d切り替えには理由があります:cd /d "C:\Users\Me" (and the proper path delimeter for Windows is `ではなく` /)。
ステファン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.