I am trying to use Windows built-in shell script to load this file:
hostname1,host_specific_file1
hostname2,host_specific_file2
hostname3,host_specific_file3
.
.
.
Like this:
for /f "tokens=1,2* delims=," %%i in (host-info.txt) do set clientName=%%i; set fileLoc=%%j
Which doesn't work but I want it to go like this:
:loop
For each line, Set the current_hostname=hostnamex and Set the current_file=host_specific_filex
And THEN
DO STUFF
Goto next line, Goto loop
Is there a method for doing this? I can't get my script wrapped around the "Goto next line" or "Handle one line at a time" concept.
Thanks,
Chris
You can;
echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2* delims=," %%i in (host-info.txt) do (
set clientName=%%i
set fileLoc=%%j
call:handler
)
goto:eof
:handler
echo client name is !clientName! location is !fileLoc!
goto:eof
Or Using %n notation;
echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2* delims=," %%i in (host-info.txt) do call:handler %%i %%j
goto:eof
:handler
echo client name is %1 location is %2 ...
Related
I am trying to extract the last word from the last line of a txt file.
The result I want is just Cup$2!.
This is what I tried:
#echo off
SetLocal EnableDelayedExpansion
set L=1
for /F "tokens=2 delims=" %%a in (corner.txt) do (
set line=%%a
if !L!==7 set Line7=%%a
set /a L=!L!+1
)
echo The word is %Line7%
pause
The result I'm getting is The word is.
What should I edit to get the above result?
Get line count.
for /f "tokens=3*" %%i in ('find /c /v /n /i"" corner.txt') do set /a v=%%i-1
Then get the last values from 7-th word of the last line:
for /f "tokens=7*" %%a in ('more corner.txt +%v%') do set "String="%%b""
Variable %String% keeps the values framed by double quotes: Cup&2!/Cup$2!
If you use / as delimiter you can get last value:
for /f "delims=/ tokens=2*" %%a in (%String%) do #echo %%a
Here's a quick example of how you could capture the substring you require, from reading your code, i.e. the last substring on the seventh line:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "var="
For /F UseBackQ^ Skip^=7^ Delims^=^ EOL^= %%G In ("corner.txt") Do Set "var=%%~nxG" & GoTo Next
If Not Defined var GoTo EndIt
:Next
SetLocal EnableDelayedExpansion
Echo The word is !var!
EndLocal
:EndIt
Echo Press any key to close . . .
Pause 1>NUL
EndLocal
Exit /B
If however, as your question title and body asks, you want the last substring of the last line, it's a little bit simpler:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "var="
For /F UseBackQ^ Delims^=^ EOL^= %%G In ("corner.txt") Do Set "var=%%~nxG"
If Not Defined var GoTo EndIt
SetLocal EnableDelayedExpansion
Echo The word is !var!
EndLocal
:EndIt
Echo Press any key to close . . .
Pause 1>NUL
EndLocal
Exit /B
I will not however be explaining any of it, please use the search facility at the top of the page, and the output from the built in help for each of the commands I have used.
Parsing strings in batch files is never ideal but this seems to work:
#echo off
setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
echo.line 1 > "%temp%\SO_Test.txt"
echo. >> "%temp%\SO_Test.txt"
echo.foo^&bar!baz hello/world Cup^&2!/Cup$2!>> "%temp%\SO_Test.txt"
goto start
:start
set "line="
for /F "usebackq delims=" %%a in ("%temp%\SO_Test.txt") do #set line=%%a
:word
set "b="
rem Delims is slash, tab, space and the order is important
for /F "tokens=1,* delims=/ " %%A in ("%line%") do (
set "line=%%A"
set "b=%%B"
)
if not "%b%" == "" (
set "line=%b%"
goto word
)
echo.Last word is "%line%"
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q70761955.txt"
SET "amper=&"
FOR /f "usebackq delims=" %%b IN ("%filename1%") DO SET "lastword=%%b"
:: Replace ampersands with spaces, then slashes with spaces
CALL SET "lastword=%%lastword:%amper%= %%"
SET "lastword=%lastword:/= %"
FOR %%b IN (%lastword%) DO SET "lastword=%%b"
ECHO last "word" is -^>%lastword%^<-
GOTO :EOF
Read each line of the file, retaining the last-read line in lastword.
Replace each "delimiter" character (& and / are implied in the question. Others - no information.)
Select the last "word" in the last line.
You would need to change the value assigned to sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that the spaces are processed correctly.
I used a file named q70761955.txt containing your data for my testing.
You could use this in a batch-file run by cmd on windows.
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"((Get-Content -Path 'corner.txt' -Last 1) -split '[\s*/]')[-1]"') DO (SET "LINE7=%%A")
ECHO %LINE7%
If the script were written in PowerShell instead of cmd language, it could be a one-liner.
$Line7 = ((Get-Content -Path 'corner.txt' -Last 1) -split '[\s*/]')[-1]
Apologies for my poorly worded question and my scatterbrain workings. Essentially I want to set an unknown number of variables that are parsed from each line of a text file.
I have written batch file to create symbolic links for network shares to a C:\Volumes folder.
#echo off
echo:
set /p dest=ENTER FOLDER PATH:
set dest="%dest%"
net use %dest%
if not exist "C:\Volumes" MD "C:\Volumes"
for %%i in (%dest%) do (set "fold=%%~ni")
mklink /d "c:\VOLUMES\%fold%" "%dest%"
pause
What I want to try is the same theory but have the script point at a text file mounts.txt with a list of folder paths and for a for loop to cycle through the list make a symbolic link for each path in the list. I have toyed with counters and cannot get it working correctly. I don't think I am going about it the right way at all.
Contents of mounts.txt
\\10.19.10.238\Masters\Removed bin\Work here
\\10.19.10.241\Scanning\WIP\to process
This does not work:
#echo off
setlocal enableDelayedExpansion
set i=1
:add
Set /a "i+=1"
for /F "tokens=*" %%A in (mounts.txt) do (set dest%i%=%%A)
if exist %dest%%i% goto:add
echo %dest%
echo %dest%%i%
echo !dest!
echo !dest!%i%
pause
Nor this:
#echo off
setlocal enableDelayedExpansion
set i=0
For /F "Tokens=1* Delims=] EOL=" %%A In ('Find /N /V ""^<"mounts.txt"') Do (
set /a i=i+1
set "dest!i!=%%B"
)
For /l %%a in (1,1,4) do echo _dest%%a is !dest%%a!
For /l %%a in (1,1,4) do set dest%%a=!dest%%a!
echo !dest!
pause
I did get something like this to work to an extent but cannot figure out how to use the dest[1], dest[2] as variables in other processes further down in the script.
#echo off
setlocal enabledelayedexpansion
set counter=0
for /f "tokens=*" %%a In (mounts.txt) do (
set /a counter+=1
set "dest[!counter!]=%%a"
)
set dest[
And the list could be added to with many more. If %dest%n variables can be set, the use the same theory to set different %fold% variables based on each %dest%n then maybe the links can be set using the same process as the original script.
Any help is appreciated. Thank you.
If your question actually describes what you want to do, you don't need to set variables. Just use the lines from the text file with a for /f loop:
for /f "delims=" %%i in (mount.txt) do mklink /d "C:\VOLUMES\%%~ni" "%%i"
It's safer to quote the filename, especially if you want/need to use the FQFN. Therefore you need the usebackq option, else a quoted string will be processed as a string, not a filename:
for /f "usebackq delims=" %%i in ("C:\full path\mount.txt") do mklink /d "C:\VOLUMES\%%~ni" "%%i"
You seemingly want to dynamically set the variables as dummy array's and return results based on the line numbers. If so, use the counter you created to become the max of the for /L loop, here is an example by just echoing the results:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,!cnt!) do echo !var[%%a]!
Edit
As highlighted by #Compo in the comments; after the initial code block where we increment the %cnt% variable, we no longer require using delayedexpansion on the %cnt% variable specifically and can therefore use %cnt% instead of !cnt!:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,%cnt%) do echo !var[%%a]!
This is a courtesy example, just to show you how you could have still used find.exe, as in one of your examples, and additionally includes a different method of iterating the variables with unknown increments:
#Echo Off
SetLocal EnableExtensions
Rem The next line ensures that there are no variables defined with names beginning _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Rem The next lines parse the directory paths content file and defines the incrementing variables
For /F "Tokens=1,* Delims=]" %%G In (
'"%SystemRoot%\System32\find.exe /N "\" 0< "C:\Users\roar\My Directory\mounts.txt" 2>NUL"'
) Do (
Set "_Path%%G]=%%H"
Set "_Name%%G]=%%~nxH"
)
Rem The next lines iterate the defined variables beginning _Path[ and runs commands against them
For /F "Tokens=2 Delims=[]" %%G In ('"(Set _Path[) 2>NUL"') Do (
SetLocal EnableDelayedExpansion
MkLink /D "C:\Volumes\!_Name[%%G]!" "!_Path[%%G]!"
EndLocal
)
Rem The next line undefines any previously defined variables named beginning with _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Please note that is likely you may need to run this script elevated, in order for the MkLink command to create the symbolic links.
So I'm trying to copy a local file to my network using batch scripting and would like to be able to get a result to know if the process completed properly.
My code is below:
#echo off
set locatie_folder=G:\Info\instructiuni.mht
for /f "tokens=1,2 delims= " %%a in (IP.txt) do (
copy %locatie_folder% "\\%%a\vsr">> temp.tmp
set /p VAR=<temp.tmp
echo %%b %VAR%
del temp.tmp
)
pause
exit
My IP.txt file looks like so:
10.117.14.10 100-01
10.117.14.11 100-02
10.117.14.12 100-03
First is the IP and second is a dedicated name for that IP in the network.
I need to output something like
100-01 1 file(s) copied.
100-02 0 file(s) copied.
100-03 1 file(s) copied.
Now my problem is that for some reason the variable VAR is not getting me the status "0 file(s) copied." or "1 file(s) copied." while reading even if it writes properly in the temp.tmp file.
What am I doing wrong here?
You need to enable delayed expansion for getting the new value of VAR, because you are setting and reading it within a block of code (the for loop). The immediate %VAR% expansion always returns the value when the entire block of code is parsed; with delayed !VAR! expansion, you will get the updated value.
Try this:
#echo off
setlocal EnableDelayedExpansion
set "locatie_folder=G:\Info\instructiuni.mht"
for /F "usebackq tokens=1,2 delims= " %%A in ("IP.txt") do (
> "temp.tmp" copy "%locatie_folder%" "\\%%~A\vsr"
< "temp.tmp" set /P VAR=
echo "%%~B" !VAR!
del "temp.tmp"
)
pause
endlocal
exit /B
You can make it all even simpler though, without using a temporary file, when you let another for /F loop capture the output of the copy command:
#echo off
set "locatie_folder=G:\Info\instructiuni.mht"
for /F "usebackq tokens=1,2 delims= " %%A in ("IP.txt") do (
for /F "delims=" %%X in ('copy "%locatie_folder%" "\\%%~A\vsr"') do (
echo "%%~B" %%X
)
)
pause
exit /B
Put your COPY command inside a FOR /F command to capture the verbose output to a variable.
Something like this.
for /F "tokens=* delims= " %%G in ('copy temp.txt C:\temp\') do echo %%b %%G
Edit: with your exact code.
#echo off
set locatie_folder=G:\Info\instructiuni.mht
for /f "tokens=1,2 delims= " %%a in (IP.txt) do (
for /F "tokens=* delims= " %%G in ('copy %locatie_folder% "\\%%a\vsr"') do echo %%b %%G
)
pause
exit
I'm having the below script to display some data on-screen, using one small CMD file:
#echo off
set description=%1
ver
date /t
time /t
echo %description%
This provides output, similar to:
Microsoft Windows [Version 6.1.7601]
ma 08/12/2014
17:00
sometext
But, I would like to have this output:
Microsoft Windows [Version 6.1.7601] [ma 08/12/2014 17:00] sometext
I can't think of easy coding (without including variables and/or temporary files) to have something like that achieved. Is it possible in an easy manner (like using backticks on Linux/Unix) ? How ?
As a bonus, it would be even more better if that one line does not end with a return character. That way, I can add additional text (also in 1 line format) to the file, just using ECHO. Knowing that ECHO itself will add a return eventually. I know I can do this, using Cygwin's PRINTF, but if possible I would like to avoid Cygwin, and use standard CMD.
EDIT: changed the question to include the "ver" command so that it matches the title : output of real commands, to be converted into 1 line
#echo off
set myVar=
set description=%1
for /F "delims=" %%I in ('ver') do (set myVar=%%I)
for /F "delims=" %%I in ('date /t') do (set myVar=%myVar% %%I)
for /F "delims=" %%I in ('time /t') do (set myVar=[%myVar% %%I])
set myVar=%myVar% %description%
echo %myVar%
How do I get the result of a command in a variable in windows?
No temporary file, no visible auxiliary variable (cf. no change to %xyz% variable formally used in the :echo subroutine). Simple to change echo anything to call :echo anything
#ECHO OFF >NUL
:: unrem next line to see no change
:: set "xyz=XYZ"
Call :echo %time%
Call :echo after 5 secs
ping 1.1.1.1 -n 1 -w 5000 > nul
Call :echo %time%
Call :echo another 5 secs
ping 1.1.1.1 -n 1 -w 5000 > nul
Call :echo %time%
:: add new line in next ECHO. command
echo.
:: ensure variable xyz is not defined / changed
set xyz
:: and STDOUT command output
for /F "tokens=* delims=" %%G in ('ver /?') do call :echo %%G
for /F "tokens=* delims=" %%G in ('ver') do call :echo %%G
goto :eof
:echo
<nul (set/p xyz=%* )
goto :eof
And to see your task solution:
#ECHO OFF >NUL
for /F "tokens=* delims=" %%G in ('ver') do call :echo %%G
for /F "tokens=* delims=" %%G in ('date /t') do call :echo %%G
for /F "tokens=* delims=" %%G in ('time /t') do call :echo %%G
call :echo sometext
call :echo
goto :eof
:echo
if "%*"=="" echo.&goto :eof
<nul (set/p xyz=%* ) 2>NUL
goto :eof
In last code snippet adhered to rule only one command for the same task: echo. replaced by call :echo to add new line to output. However, let echo ON and echo OFF apart...
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