This question already has an answer here:
Variables are not behaving as expected
(1 answer)
Closed 3 years ago.
I have a list of host names separated by new lines in a text file. I want to run netstat on each of those lines and write the output of all these commands to a text file. I know the netstat command will work on each line so thats not an issue.
Here is what I have so far in my .bat:
FOR /F "tokens=*" %%A in (fqdn.txt) do (
FOR /F "tokens=* USEBACKQ" %%F IN (`netstat %%A`) DO (
SET var=%%F
)
echo %var% >> test.txt
echo delim >> test.txt
)
All that happens is the netstat help is posted to the command line over and over and the text file fills up with:
ECHO is on.
delim
ECHO is on.
delim
ECHO is on.
delim
Thanks in advance for the help :)
You need delayedexpansion because you are setting and using a variable inside of a code block:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%A in (fqdn.txt) do (
for /f "tokens=* USEBACKQ" %%F IN (`netstat %%A`) DO (
SET var=%%F
)
echo !var! >> test.txt
echo delim >> test.txt
)
To get more detail on delayedexpansion run from cmd set /? and setlocal /?
That being said, you also do not need delayedexpansion:
#echo off
for /f "tokens=*" %%A in (fqdn.txt) do (
for /f "tokens=* USEBACKQ" %%F IN (`netstat %%A`) DO (
echo %%F >> test.txt
)
echo delim >> test.txt
)
As I did not see the actual input file, it is also possible to eliminate the second for loop should you want the entire output from the netstat command.
#echo off
(for /f "tokens=*" %%i in (fqdn.txt) do (
netstat %%i
echo delim
)
)>>test.txt
ok, I give up. Why doesn't this work?
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
FOR /F %%I in (myfile.txt) do (
echo I: %%i
set LINE=%%i
echo LINE: %LINE%
)
"echo I:" displays the lines correctly, but "echo LINE:" is empty
I have tried different variations with the same results, such as
set LINE=%i
set LINE=%i%
set LINE=!i!
Obviously there is something simple I am not understanding.
you enabled delayed expansion, so the only thing you have to do is: use it.
replace echo LINE: %LINE% with echo LINE: !LINE!
EDIT: solution without delayed extension
FOR /F %%I in (myfile.txt) do ( call DoIt %%I )
exit /b
:DoIt
echo I: %1
set LINE=%1
echo LINE: %LINE%
goto :eof
I'm trying to make a code which will get first words from all lines of HELP's output to a variable and echo this variable. Here is my code:
#echo off
set a=
for /F "tokens=1,*" %%i in ('help') do (
set a=%a% %%i
)
echo %a%
But it returns first word from only last line. Why?
Bali C solved your problem as stated, but it looks to me like you are trying to get a list of commands found in HELP.
Some of the commands appear on multiple lines, so you get some extraneous words. Also there is a leading and trailing line beginning with "For" on an English machine that is not wanted.
Here is a short script for an English machine that will build a list of commands. The FINDSTR command will have to change for different languages.
#echo off
setlocal enableDelayedExpansion
set "cmds="
for /f "eol= delims=." %%A in ('help^|findstr /bv "For"') do (
for /f %%B in ("%%A") do set "cmds=!cmds! %%B"
)
set "cmds=%cmds:~1%"
echo %cmds%
EDIT
Ansgar Wiechers came up with a more efficient algorithm to extract just the command names at https://stackoverflow.com/a/12733642/1012053 that I believe should work with all languages. I've used his idea to simplify the code below.
#echo off
setlocal enableDelayedExpansion
set "cmds="
for /f %%A in ('help^|findstr /brc:"[A-Z][A-Z]* "') do set "cmds=!cmds! %%A"
set "cmds=%cmds:~1%"
echo %cmds%
You need to use delayed expansion in your for loop
#echo off
setlocal enabledelayedexpansion
set a=
for /F "tokens=1,*" %%i in ('help') do (
set a=!a! %%i
)
echo %a%
Instead of using %'s around the a variable, you use !'s to use delayed expansion.
Because the echo is outside the do ( ...... )
#echo off
for /F "tokens=1,*" %%i in ('help') do (
echo %%i
)
and no need to print a, you can use directly %%i.
Another very simple example could be a batch like this saved as help1.cmd
#echo off
for /F "tokens=1,*" %%i in ('help') do (
if /I "%%i" EQU "%1" echo %%j
)
and you call this batch like
help1 MKDIR
to get the short help text for the MKDIR command
Is it possible to set the output of TYPE or ECHO as a variable in a batch file?
Convoluted, and it only works for a single line, but general:
for /f "delims=" %%x in ('some command with output') do set "Var=%%x"
For echo you don't need to do anything special, just change
echo Foo
into
set Var=Foo
And for files there is also the option of either
set /p Var=<file.txt
or
for /f "delims=" %%x in (file.txt) do set "Var=%%x"
This question already has answers here:
Assign output of a program to a variable using a MS batch file
(12 answers)
How to set commands output as a variable in a batch file [duplicate]
(9 answers)
Closed 9 months ago.
I'm looking to get the result of a command as a variable in a Windows batch script (see how to get the result of a command in bash for the bash scripting equivalent). A solution that will work in a .bat file is preferred, but other common windows scripting solutions are also welcome.
The humble for command has accumulated some interesting capabilities over the years:
D:\> FOR /F "delims=" %i IN ('date /t') DO set today=%i
D:\> echo %today%
Sat 20/09/2008
Note that "delims=" overwrites the default space and tab delimiters so that the output of the date command gets gobbled all at once.
To capture multi-line output, it can still essentially be a one-liner (using the variable lf as the delimiter in the resulting variable):
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%
To capture a piped expression, use ^|:
FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
If you have to capture all the command output you can use a batch like this:
#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
All output lines are stored in VAR separated with "!".
But if only a single-line console-output is expected, try:
#ECHO off
#SET MY_VAR=
FOR /F %%I IN ('npm prefix') DO #SET "MY_VAR=%%I"
#REM Do something with MY_VAR variable...
#John: is there any practical use for this? I think you should watch PowerShell or any other programming language capable to perform scripting tasks easily (Python, Perl, PHP, Ruby)
To get the current directory, you can use this:
CD > tmpFile
SET /p myvar= < tmpFile
DEL tmpFile
echo test: %myvar%
It's using a temp-file though, so it's not the most pretty, but it certainly works! 'CD' puts the current directory in 'tmpFile', 'SET' loads the content of tmpFile.
Here is a solution for multiple lines with "array's":
#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
But you might want to consider moving to another more powerful shell or create an application for this stuff. It's stretching the possibilities of the batch files quite a bit.
you need to use the SET command with parameter /P and direct your output to it.
For example see http://www.ss64.com/nt/set.html. Will work for CMD, not sure about .BAT files
From a comment to this post:
That link has the command "Set /P
_MyVar=<MyFilename.txt" which says it will set _MyVar to the first line
from MyFilename.txt. This could be
used as "myCmd > tmp.txt" with "set
/P myVar=<tmp.txt". But it will only
get the first line of the output, not
all the output
Example to set in the "V" environment variable the most recent file
FOR /F %I IN ('DIR *.* /O:D /B') DO SET V=%I
in a batch file you have to use double prefix in the loop variable:
FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I
I would like to add a remark to the above solutions:
All these syntaxes work perfectly well IF YOUR COMMAND IS FOUND WITHIN THE PATH or IF THE COMMAND IS A cmdpath WITHOUT SPACES OR SPECIAL CHARACTERS.
But if you try to use an executable command located in a folder which path contains special characters then you would need to enclose your command path into double quotes (") and then the FOR /F syntax does not work.
Examples:
$ 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.
or
$ 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.
or
`$ 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.
In that case, the only solution I found to use a command and store its result in a variable is to set (temporarily) the default directory to the one of command itself :
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%
The result is then correct:
My selected folder: F:\GLW7\Distrib\System\OS install, recovery, VM\
Press any key to continue . . .
Of course in the above example, I assume that my batch script is located in the same folder as the one of my executable command so that I can use the "%~d0%~p0" syntax. If this is not your case, then you have to find a way to locate your command path and change the default directory to its path.
NB: For those who wonder, the sample command used here (to select a folder) is FOLDERBROWSE.EXE. I found it on the web site f2ko.de (http://f2ko.de/en/cmd.php).
If anyone has a better solution for that kind of commands accessible through a complex path, I will be very glad to hear of it.
Gilles
Just use the result from the FOR command. For example (inside a batch file):
for /F "delims=" %%I in ('dir /b /a-d /od FILESA*') do (echo %%I)
You can use the %%I as the value you want. Just like this: %%I.
And in advance the %%I does not have any spaces or CR characters and can be used for comparisons!!
If you're looking for the solution provided in Using the result of a command as an argument in bash?
then here is the code:
#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
This will call itself with the result of the CD command, same as pwd.
String extraction on parameters will return the filename/folder.
Get the contents of this folder and append to the filename.txt
[Credits]: Thanks to all the other answers and some digging on the Windows XP commands page.
#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%"
You can capture all output in one variable, but the lines will be separated by a character of your choice (# in the example below) instead of an actual 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%
Second version, if you need to print the contents out line-by-line. This takes advanted of the fact that there won't be duplicate lines of output from "dir /b", so it may not work in the general case.
#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=!
)
)
#echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
set TXT=%%i
)
echo 'TXT: %TXT%'
the result is 'TXT: hola'
You should use the for command, here is an example:
#echo off
rem Commands go here
exit /b
:output
for /f "tokens=* useback" %%a in (`%~1`) do set "output=%%a"
and you can use call :output "Command goes here" then the output will be in the %output% variable.
Note: If you have a command output that is multiline, this tool will set the output to the last line of your multiline command.
Please refer to this http://technet.microsoft.com/en-us/library/bb490982.aspx which explains what you can do with command output.