Windowsの変数でコマンドの結果を取得するにはどうすればよいですか?


132

コマンドの結果をWindowsバッチスクリプトの変数として取得しようとしています(bashスクリプトで同等の機能を実現するために、bashでコマンドの結果を取得する方法を参照してください)。.batファイルで機能するソリューションが推奨されますが、他の一般的なWindowsスクリプトソリューションも歓迎します。


9
ジョン、この非常に役立つ質問を見つけるのは途方もなく困難です。プログラム出力Windowsバッチファイルの変数にキャプチャする方法の
Piotr Dobrogost、2011年

3
Googleはこのページを3位に表示しました。
ルネNyffenegger


@MichaelFreidgeimこの質問は実際にはその重複の2年前に尋ねられました-しかし、この質問には複数の重複があります。stackoverflow.com/questions/6359820/…
icc97

1
@ icc97、「可能性のある重複」は、クリーンアップする方法です。同様の質問を閉じて、最良の回答を持つ質問を保持します。日付は必須ではありません。meta.stackexchange.com/questions/147643/を参照してください。明確化が必要であることに同意する場合は、meta.stackexchange.com / questions / 281980 /に投票し てください。複数の重複がある場合は、1つを正規として選択し、投票して他のユーザーを閉じる必要があります。
Michael Freidgeim

回答:


34

すべてのコマンド出力をキャプチャする必要がある場合は、次のようなバッチを使用できます。

@ECHO OFF
IF NOT "%1"=="" GOTO ADDV
SET VAR=
FOR /F %%I IN ('DIR *.TXT /B /O:D') DO CALL %0 %%I
SET VAR
GOTO END

:ADDV
SET VAR=%VAR%!%1

:END

すべての出力行は、「!」で区切られたVARに格納されます。

@ジョン:これの実用的な用途はありますか?PowerShellや、スクリプトタスクを簡単に実行できるその他のプログラミング言語(Python、Perl、PHP、Ruby)を見る必要があると思います


1行の回答で、私が抱えている特定のケースが解決されます。私は、複数行のオプション(またはより簡単な単一行のオプション)があると考えました。私はバットファイルの能力がそれ程素晴らしいとは思わない。Javaアプリをラップするbatスクリプトが必要です。主にクラスパスを構築します。
John Meagher、

十分に注意してください。GWTはまた、特定のクラスパスでJavaを起動するためにバッチファイルを使用しようとしましたが、ASCII以外の文字を含むディレクトリに到達するとすぐに恐ろしく失敗しました(その場合は、私の家でした:))。彼らはそれをVBSで書き直した。
ジョーイ

25
これの実用的な用途はありますか?冗談ですか?これは他のシェル(私が推測するすべてのGNU / Linuxシェル)で常に使用されており、非常に便利です。
Piotr Dobrogost、2011年

1
@PiotrDobrogost彼が言っていたのは、bashスクリプトは過去の恐ろしい遺物であるということだと思います(プログラムの出力をキャプチャするためにforループを使用する必要がありますか?真剣に?)。変数を使用する必要がある場合は、PowerShellなどのよりモダンなものを使用する必要があります。
Ajedi32 2015

3
実用的な使い方があります。PowerShellスクリプトを使用して特定のVisual Studioパスを検索したいのですが、そのパスから必要なのは、一連の環境変数を設定してeditbinを呼び出すことができるバッチファイルです...パスを見つける必要があります呼び出し元のインスタンスに戻して、cmdそこで実行できるようにします。...はい、これは音と同じくらいひどいです。Visual Studioを使用すると、ときどき泣きたくなります。@ Ajedi32 バッチスクリプトは過去の恐ろしい遺物であると言うつもりだったと思います。;)
jpmc26

85

謙虚ためのコマンドは、長年にわたって、いくつかの興味深い機能を蓄積してきました。

D:\> FOR /F "delims=" %i IN ('date /t') DO set today=%i
D:\> echo %today%
Sat 20/09/2008

"delims="は、デフォルトのスペースとタブ区切り文字を上書きするため、dateコマンドの出力が一度に乱れることに注意してください。

複数行の出力をキャプチャする場合でも、基本的には1行にすることができます(変数lfを結果の変数の区切り文字として使用します)。

REM NB:in a batch file, need to use %%i not %i
setlocal EnableDelayedExpansion
SET lf=-
FOR /F "delims=" %%i IN ('dir \ /b') DO if ("!out!"=="") (set out=%%i) else (set out=!out!%lf%%%i)
ECHO %out%

パイプ式をキャプチャするには、次を使用します^|

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"

1
@PabloGの回答と同様に、これはコマンドからの出力の最後の行(この場合は "date / t")を取得するためにのみ機能します。
John Meagher、

11
私はつまり、私は二重のパーセント記号を使用する場合にのみ、仕事にあなたの答えを見つけたFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski

18
@Rabarberski:forコマンドラインでコマンドを直接入力する場合は、単一のを使用します%。バッチファイルで使用する場合は、を使用します%%
個人

@tardate:コマンドニーズがで引数を渡すことがあれば、スクリプトは、次のようになりますどのように教えてもらえ%例えば、:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k

1
@degenerate date使用されるコマンドがCygwinからのものである場合、コマンドは有効です。私はそれについて言及すべきだったのに同意します。
dma_k

24

現在のディレクトリを取得するには、これを使用できます:

CD > tmpFile
SET /p myvar= < tmpFile
DEL tmpFile
echo test: %myvar%

ただし、一時ファイルを使用しているため、それほどきれいではありませんが、確実に機能します。「CD」は現在のディレクトリを「tmpFile」に置き、「SET」はtmpFileのコンテンツをロードします。

「配列」を持つ複数行の解決策は次のとおりです。

@echo off

rem ---------
rem Obtain line numbers from the file
rem ---------

rem This is the file that is being read: You can replace this with %1 for dynamic behaviour or replace it with some command like the first example i gave with the 'CD' command.
set _readfile=test.txt

for /f "usebackq tokens=2 delims=:" %%a in (`find /c /v "" %_readfile%`) do set _max=%%a
set /a _max+=1
set _i=0
set _filename=temp.dat

rem ---------
rem Make the list
rem ---------

:makeList
find /n /v "" %_readfile% >%_filename%

rem ---------
rem Read the list
rem ---------

:readList
if %_i%==%_max% goto printList

rem ---------
rem Read the lines into the array
rem ---------
for /f "usebackq delims=] tokens=2" %%a in (`findstr /r "\[%_i%]" %_filename%`) do set _data%_i%=%%a
set /a _i+=1
goto readList

:printList
del %_filename%
set _i=1
:printMore
if %_i%==%_max% goto finished
set _data%_i%
set /a _i+=1
goto printMore

:finished

しかし、より強力な別のシェルに移動することを検討したり、このようなアプリケーションを作成したりすることをお勧めします。バッチファイルの可能性をかなり広げています。


コマンドから複数の行をキャプチャするために機能するバリエーションはありますか?
John Meagher、

6
現在のディレクトリを取得するには、echo%CD%
Joe

9

SETパラメータ付きのコマンドを使用して/P、出力をそれに送る必要があります。たとえば、http://www.ss64.com/nt/set.htmlを参照してください。CMDで動作しますが、.BATファイルについては不明です

コメントからこの投稿へ:

そのリンクには、「Set /P _MyVar=<MyFilename.txt_MyVarの最初の行に設定することを示すコマンド「」がありますMyFilename.txt。これは「myCmd > tmp.txt」とともに「set /P myVar=<tmp.txt」として使用できます。ただし、すべての出力ではなく、出力の最初の行のみを取得します


2
そのリンクには、コマンド「Set / P _MyVar = <MyFilename.txt」があり、これは、_MyVarをMyFilename.txtの最初の行に設定することを示しています。これは、「set / P myVar = <tmp.txt」で「myCmd> tmp.txt」として使用できます。ただし、すべての出力ではなく、出力の最初の行のみを取得します。
John Meagher

この回答は私のような初心者向けです

5

「V」環境変数に最新のファイルを設定する例

FOR /F %I IN ('DIR *.* /O:D /B') DO SET V=%I

バッチファイルでは、ループ変数でダブルプレフィックスを使用する必要があります。

FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I

2
私は以前このアプローチを見たことがありますが、それは本当にハッキーなようです。また、コマンドの出力の最後の行のみを変数に取り込むという問題もあります。
John Meagher、

3

FORコマンドの結果を使用するだけです。例(バッチファイル内):

for /F "delims=" %%I in ('dir /b /a-d /od FILESA*') do (echo %%I)

%%I必要な値として使用できます。このように:%%I

そして、事前に%%IスペースやCR文字がなく、比較に使用できます!!


2

コマンドの結果をbashの引数として使用するで提供されているソリューションをお探しですか?

次に、コードは次のとおりです。

@echo off
if not "%1"=="" goto get_basename_pwd
for /f "delims=X" %%i in ('cd') do call %0 %%i
for /f "delims=X" %%i in ('dir /o:d /b') do echo %%i>>%filename%.txt
goto end

:get_basename_pwd
set filename=%~n1

:end
  • これは、pwdと同じように、CDコマンドの結果で自分自身を呼び出します。
  • パラメータの文字列抽出は、ファイル名/フォルダを返します。
  • このフォルダーの内容を取得し、filename.txtに追加します

[クレジット]:他のすべての回答、およびWindows XPコマンドページのいくつかの掘り下げに感謝します。


2
@echo off

ver | find "6.1." > nul
if %ERRORLEVEL% == 0 (
echo Win7
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)

ver | find "5.1." > nul
if %ERRORLEVEL% == 0 (
echo WinXP
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)
echo Outlook dir:  %findoutlook%
"%findoutlook%"

回答を投稿していただきありがとうございます。コードスニペットは、質問に答えることもできますが、それは、など。説明のように、周りにいくつかの追加情報を追加するために、まだ素晴らしいことだ
j0k

2

上記の解決策にコメントを追加します:

これらの構文はすべて、コマンドがパス内にある場合、またはコマンドがスペースや特殊文字なしのコマンドパスである場合に、完全に機能します。

ただし、パスに特殊文字が含まれているフォルダーにある実行可能コマンドを使用しようとすると、コマンドパスを二重引用符( ")で囲む必要があり、FOR / F構文は機能しません。

例:

$ for /f "tokens=* USEBACKQ" %f in (
    `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" Hello '"F:\GLW7\Distrib\System\Shells and scripting"'`
) do echo %f
The filename, directory name, or volume label syntax is incorrect.

または

$ for /f "tokens=* USEBACKQ" %f in (
      `"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'F:\GLW7\Distrib\System\Shells' is not recognized as an internal or external command, operable program or batch file.

または

`$ for /f "tokens=* USEBACKQ" %f in (
     `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello' is not recognized as an internal or external command, operable program or batch file.

その場合、コマンドを使用してその結果を変数に格納することがわかった唯一の解決策は、デフォルトのディレクトリをコマンド自体の1つに(一時的に)設定することです。

pushd "%~d0%~p0"
FOR /F "tokens=* USEBACKQ" %%F IN (
    `FOLDERBROWSE "Hello world!" "F:\GLW7\Distrib\System\Layouts (print,display...)"`
) DO (SET MyFolder=%%F)
popd
echo My selected folder: %MyFolder%

結果は正しいです:

My selected folder: F:\GLW7\Distrib\System\OS install, recovery, VM\
Press any key to continue . . .

もちろん、上記の例では、「%〜d0%〜p0」構文を使用できるように、バッチスクリプトが実行可能コマンドと同じフォルダーにあると想定しています。これが当てはまらない場合は、コマンドパスを見つけてデフォルトのディレクトリをそのパスに変更する方法を見つける必要があります。

注意:不思議に思う人のために、ここで(フォルダを選択するために)使用されるサンプルコマンドはFOLDERBROWSE.EXEです。Webサイトf2ko.de(http://f2ko.de/en/cmd.php)で見つけました。

誰かが複雑なパスを介してアクセスできるそのようなコマンドのより良い解決策を持っているなら、私はそれを聞いてとても嬉しいでしょう。

ジル


コマンドの前にを付けることができますCALLパスにスペースがある場合、FOR / Fは機能しません
jeb

@jeb:どうもありがとう!これで私のコード< CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters">は完全に機能します。
Gilles Maisonneuve

1

すべての出力を1つの変数でキャプチャできますが、実際のCR-LFではなく、行は選択した文字(下の例では#)で区切られます。

@echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
)
echo directory contains:
echo %DIR%

2番目のバージョン、内容を行ごとに印刷する必要がある場合。これは、「dir / b」からの出力の重複行がないため、一般的なケースでは機能しない可能性があるという事実を利用しています。

@echo off
setlocal EnableDelayedExpansion
set count=0
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
    set /a count = !count! + 1
)

echo directory contains:
echo %DIR%

for /l %%c in (1,1,%count%) do (
    for /f "delims=#" %%i in ("!DIR!") do (
        echo %%i
        set DIR=!DIR:%%i=!
    )
)

0
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

結果は「TXT:hola」です


0

forコマンドを使用する必要があります。次に例を示します。

@echo off
rem Commands go here
exit /b
:output
for /f "tokens=* useback" %%a in (`%~1`) do set "output=%%a"

そして、あなたはcall :output "Command goes here"それから出力を%output%変数に入れることができます。

注:複数行のコマンド出力がある場合、このツールはset複数行コマンドの最後の行に出力します。


-1

コマンド出力で何ができるかを説明しているhttp://technet.microsoft.com/en-us/library/bb490982.aspxを参照してください。


1
その記事では、リダイレクトと関連トピックのみを扱います。1つのコマンドの出力を取得して変数に入れる方法についての質問には答えません。
John Meagher、

3
彼の答えを使用して私はこれを思い付きました: git pull>0 set /P RESULTVAR=<0 編集:おそらく、ここでは改行の使用方法がわかりません...各コマンドはそれ自体の行にあります。
RibeiroBreno 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.