What does "set _" in a for loop? - batch-file

I had a problem that Win7 hangs on shutdown screen for over 30 mins.....
then I found this batch file was the cause, but i dont understand what's the purpose of this.
The shutdown only hangs on after join to domain.
This batch file was in c:\ntfs\bin
After I removed this batch file, no more hangs
Issue fixed but i want to know what does this script mean. I dont know much about batch file
please give me a hint
#echo off
for /f "usebackq tokens=1-2 delims==" %%a in (`set _`) do set %%a=

use better:
for /f "delims==" %%a in ('set "_"') do set "%%a="
This code deletes all environment variables starting with _ (underscore) in the current setlocal-endlocal block. If you use this in a batch file without the setlocal command, the varialbles are removed from the current command prompt session.
The use of usebackq and tokens is not needed in this case, see help for for more help on the command prompt.

It deletes all variables that start with an underscore (for example _test or _whatever)

Related

Batch commands for rds

I have a project for my Radio Station where I copy the text within a .wsx file of what is on air and parse it to a Audio Processor in my private network for RDS Display using a wget command like
set /p TEXTO= 0<R:\40.wsx
wget -q "http://x.x.x.x:7380/parameter/fm/rds/rds_rt=%TEXTO%" -O NUL
It works great but it won't filter if it's music or promotions.
My challenge is to be able to filter and only parse music names.
For the process I marked the Files that i don't want to show up like commercial, or promotions to start with a "#-" without the quotes.
So the text will show like #-Promo1
My Code:
for /F "delims=" %%a in ('FINDSTR "\<#-.*" C:\RDS\PRUEBAS\txt1.wsx') do set
"VAR=%%a"
echo %VAR%
if "%VAR%" == "true" (
set /p VAR=0<C:\FILEPATH\LOS40.wsx & wget -q
"http://x.x.x.x:7380/parameter/fm/rds/rds_rt=%VAR%" -O NUL
) else (
set /p TEXTO=0<C:\FILEPATH\ENVIVO.wsx & wget -q
"http://x.x.x.x:7380/parameter/fm/rds/rds_rt=%TEXTO%" -O NUL
)
I can't seem to find a correct way to filter it.
pls Heelpp..
for /F "delims=" %%a in ('FINDSTR "\<#-.*" C:\RDS\PRUEBAS\txt1.wsx') do set
should be
for /F "delims=" %%a in ('FINDSTR /b "#-" C:\RDS\PRUEBAS\txt1.wsx') do set
to find those lines in the .wsx file that do /b begin with "#-"
If you want to find those lines that do not begin with "#-" then add /v to the /b.
The result will be a line from the file which does [not] begin with "#-" which will be placed in %%a.
If you simply assign %%a to a variable as you are doing, that variable will contain after the for the last value that was assigned to it.
If you want to execute your wget on each name, then use
for /F "delims=" %%a in ('FINDSTR /B "#-" C:\RDS\PRUEBAS\txt1.wsx') do (
echo %%a
)
and between the parentheses you can execute commands using %%a as a filename.
Quite what you propose to do is obscure. I've no idea what the set/p from an unexplained file is meant to do, but be aware that any code between parentheses is subject to the delayedexpansion trap - please explain what processing you intend to apply to the filenames that do[not] match a leading #-.
You should read SO items on delayed expansion (it's documented with and without the space) to understand the problems with and solutions to processing values that are altered within a loop.
First of all thanks for your help.. I don't have experience in coding.
Let me explain a little bit more..
As I said before its a radio station which will provide text to the Car o home stereos using the RDS Protocol which allow me to send text like song name, title, etc.
Im My case the Audio Processor that let me send the text will receive the info as a URL where I add at the end the text I want to send.
For Example:
http://x.x.x.x:7380/parameter/fm/rds/rds_rt=%TEXTO%
%TEXTO% will be the text Im sending.
C:\RDS\PRUEBAS\txt1.wsx Contains the text of what it being played at the moment and which is being read to see if the #- for the script to avoid sending those titles.
I have a Pc running a Directory Monitor Program that will monitor events on file C:\RDS\PRUEBAS\txt1.wsx and that as soon as being modified, it will execute the batch file CHECKRDS.cmd.
After testing I decided to run a code in CHECKRDS.cmd like:
for /F "delims=" %%a in ('FINDSTR /v "#-" R:\40PPALES.wsx') do (
START "" RDS.bat
)
EXIT
RDS.bat contains code and it works fine:
set /p TEXTO= 0<C:\RDS\PRUEBAS\txt1.wsx
wget -q "http://x.x.x.x:7380/parameter/fm/rds/rds_rt=%TEXTO%" -O NUL
EXIT
As far as the set /p I test it from What does /p mean in set /p?
AS I said before Im new at coding and I just googled everything and started to assable the pieces of the puzzle.
Pls, If you think I should be doing these process diferently, pls let me know..
And sorry for my bad english..
regards

How to set a variable in a FOR loop that is involved in a pipe?

I know this question has been ask many times, but I've read the answers for hours and tried everything, nothing seems to work. Basically I can't succeed to (Re-)SET a variable in a for /F loop.
I would like to do the following : check the connection between two computers and do an action (basically start a program) if the connection doesn't exist anymore.
#ECHO OFF
SET _A=0
PING localhost | (for /F "tokens=*" %%a in ('FINDSTR Reply') DO #ECHO %%a & SET _A=1)
if %_A%==0 ECHO %_A% FAIL
if %_A%==1 ECHO %_A% SUCCESS
PAUSE
Here I assume that if the PING command doesn't return at least once the word "Reply", then the connection was lost.
The first "DO #ECHO %%a" works, but then it doesn't reset the variable "_A". And I need this variable to be external to the FOR loop because after that the "if %_A%==1" will have to execute the program only once.
Anyone knows what I'm doing wrong ? Thanks a lot for your help. I really tried everything, included setlocal enabledelayedexpansion and putting variable between !!, but nothing works, it always ends up printing "FAIL" and never "SUCCESS".
This is a great question! The problem is the pipe | as this initialises separate termporary cmd instances for both sides. The variable _A is set in the right instance but is lost afterwards.
If you do:
for /F "tokens=*" %%a in ('PING localhost ^| FINDSTR Reply') do #ECHO %%a & SET _A=1
it will work as the set command is in the main cmd instance the batch script is running in.
Note the escaped pipe ^|, which is necessary to transfer its execution to the cmd instance created by for /F for the command line it parses.

Save specific line from text via batch

So I'm trying to save the contents from the second line of a text file as a variable using Batch. I know there are way better scripting languages to do this with, but batch has command line simplicity that I need. I found this webpage: http://www.netikka.net/tsneti/info/tscmd023.htm But it seems that this method requires an auxiliary program called SED be installed. Are there any methods that do not require SED?
A for loop could work ..
#echo off
Setlocal enabledelayedexpansion
For /f "skip=1 tokens=*" %%a in (myfile.txt) do (
Set secondline=%%a
goto finish
)
: finish
Echo this is my variable !secondline!
Pause

This Supybot for windows batch install script needs to create another batch file

This Supybot for windows batch install script needs to create another batch file...
The Problem:
(1) I have a directory that has a file that ends with .conf
(2) There is only one file in this directory that ends with .conf
(3) But I don't know what this file starts with.. all I know is ????????.conf
(4) How do I set the filename.conf and remove the .conf part of the file name?
(5) As it is just the beginning of the filename that I need.
Example:
C:\runbot>find "supybot.ident: " | type *.conf > temp.txt
robotbot.conf
Outputs : robotbot.conf
The quest, is how do I set a variable=robotbot
=========================================================================
The Input was this file named "RootCode.conf" among many others
within the directory searched:
RootCode.conf
The Solution is:
FOR /F "tokens=1,2 delims=." %%a in ('FINDSTR /M "supybot.ident:" *.conf') DO SET USER=%%a&set dontneed=%%b
echo %USER%
pause
The Output is:
C:\runbot>FOR /F "tokens=1,2 delims=." %a in ('FINDSTR /M "supybot.ident:" *.con
f') DO SET USER=%a & set dontneed=%b
C:\runbot>SET USER=RootCode & set dontneed=conf
C:\runbot>echo RootCode
RootCode
C:\runbot>pause
Press any key to continue . . .
Winner... Special thanks Everyone
Your example of piping the output to typecommand is either wrong or useless. So I am assuming you mistyped and the real line was piping the other way around, and thus I am assuming that you are trying to find the filename of the file that contains the string "supybot.ident: ". In that case I would suggest to use findstr command instead.
FOR /F "tokens=*" %%a in ('FINDSTR /M "supybot.ident:" *.conf') DO SET USER=%%a
See HELP FINDSTR, HELP SET and HELP FOR for more information.
It's a bit unclear (to me, at least) what exactly you ask here. But if you need the output of a command, then use for /f:
for /f "delims=" %%x in ('some command ^| line') do set somevar=%%x
Note that you need to escape shell metacharacters in the command line (as they need to survive one parsing pass). Also note that you cannot set a variable to contain more than one line of text.

Windows Batch help in setting a variable from command output [duplicate]

This question already has answers here:
Set output of a command as a variable (with pipes) [duplicate]
(6 answers)
Closed 7 years ago.
I need to run a simple find command and redirect the output to a variable in a Windows Batch File.
I have tried this:
set file=ls|find ".txt"
echo %file%
But it does not work.
If I run this command it works without problems:
set file=test.txt
echo %file%
So obviously my command output is not being set to my variable. Can anyone help? Thanks
I just find out how to use commands with pipes in it, here's my command (that extracts the head revision of an svn repo) :
SET SVN_INFO_CMD=svn info http://mySvnRepo/MyProjects
FOR /f "tokens=1 delims=" %%i IN ('%SVN_INFO_CMD% ^| find "Revision"') DO echo %%i
First of all, what you seem to expect from your question isn't even possible in UNIX shells. How should the shell know that ls|find foo is a command and test.txt is not? What to execute here? That's why UNIX shells have the backtick for such things. Anyway, I digress.
You can't set environment variables to multi-line strings from the shell. So we now have a problem because the output of ls wouldn't quite fit.
What you really want here, though, is a list of all text files, right? Depending on what you need it's very easy to do. The main part in all of these examples is the for loop, iterating over a set of files.
If you just need to do an action for every text file:
for %%i in (*.txt) do echo Doing something with "%%i"
This even works for file names with spaces and it won't erroneously catch files that just have a .txt in the middle of their name, such as foo.txt.bar. Just to point out that your approach isn't as pretty as you'd like it to be.
Anyway, if you want a list of files you can use a little trick to create arrays, or something like that:
setlocal enabledelayedexpansion
set N=0
for %%i in (*.txt) do (
set Files[!N!]=%%i
set /a N+=1
)
After this you will have a number of environment variables, named Files[0], Files[1], etc. each one containing a single file name. You can loop over that with
for /l %%x in (1,1,%N%) do echo.!Files[%%x]!
(Note that we output a superfluous new line here, we could remove that but takes one more line of code :-))
Then you can build a really long line of file names, if you wish. You might recognize the pattern:
setlocal enabledelayedexpansion
set Files=
for %%i in (*.txt) do set Files=!Files! "%%i"
Now we have a really long line with file names. Use it for whatever you wish. This is sometimes handy for passing a bunch of files to another program.
Keep in mind though, that the maximum line length for batch files is around 8190 characters. So that puts a limit on the number of things you can have in a single line. And yes, enumerating a whole bunch of files in a single line might overflow here.
Back to the original point, that batch files have no way of capturing a command output. Others have noted it before. You can use for /f for this purpose:
for /f %%i in ('dir /b') do ...
This will iterate over the lines returned by the command, tokenizing them along the way. Not quite as handy maybe as backticks but close enough and sufficient for most puposes.
By default the tokens are broken up at whitespace, so if you got a file name "Foo bar" then suddenly you would have only "Foo" in %%i and "bar" in %%j. It can be confusing and such things are the main reason why you don't ever want to use for /f just to get a file listing.
You can also use backticks instead of apostrophes if that clashes with some program arguments:
for /f "usebackq" %%i in (`echo I can write 'apostrophes'`) do ...
Note that this also tokenizes. There are some more options you can give. They are detailed in the help for command.
set command has /p option that tells it to read a value from standard input. Unfortunately, it does not support piping into it, but it supports reading a value from a first line of existing file.
So, to set your variable to the name of a first *.txt file, you could do the following:
dir /b *.txt > filename.tmp
set /p file=< filename.tmp
del /q filename.tmp
It is important not to add a space before or even after =.
P. S. No fors, no tokens.
Here's a batch file which will return the last item output by find:
#echo off
ls | find ".txt" > %temp%\temp.txt
for /f %%i in (%temp%\temp.txt) do set file=%%i
del %temp%\temp.txt
echo %file%
for has a syntax for parsing command output, for /f "usebackq", but it cannot handle pipes in the command, so I've redirected output to a temporary location.
I strongly recommend, given that you have access to ls, that you consider using a better batch language, such as bash or even an scripting language like python or ruby. Even bash would be a 20x improvement over cmd scripting.
The short answer is: Don't!
A windows shell env var can hold a max of 32 Kb and it isn't safe to save output from programs in them.
That's why you can't. In batch script you must adopt another programming style. If you need all of the output
from the program then save it to file. If you only need to check for certain properties then pipe the output into
a program that does the checking and use the errorlevel mechanism:
#echo off
type somefile.txt | find "somestring" >nul
if %errorlevel% EQU 1 echo Sorry, not found!
REM Alternatively:
if errorlevel 1 echo Sorry, not found!
However, it's more elegant to use the logical operators Perl style:
#echo off
(type somefile.txt | find "somestring" >nul) || echo Sorry, not found!
It's not available in DOS, but in the Windows console, there is the for command. Just type 'help for' at a command prompt to see all of the options. To set a single variable you can use this:
for /f %%i in ('find .txt') do set file=%%i
Note this will only work for the first line returned from 'find .txt' because windows only expands variable once by default. You'll have to enable delayed expansion as shown here.
what you are essentially doing is listing out .txt files. With that, you can use a for loop to over dir cmd
eg
for /f "tokens=*" %%i in ('dir /b *.txt') do set file=%%i
or if you prefer using your ls, there's no need to pipe to find.
for /f "tokens=*" %%i in ('ls *.txt') do set file=%%i
Example of setting a variable from command output:
FOR /F "usebackq" %%Z IN ( `C:\cygwin\bin\cygpath "C:\scripts\sample.sh"` ) DO SET BASH_SCRIPT=%%Z
c:\cygwin\bin\bash -c '. ~/.bashrc ; %BASH_SCRIPT%'
Also, note that if you want to test out the FOR command in a DOS shell, then you need only use %Z instead of %%Z, otherwise it will complain with the following error:
%%Z was unexpected at this time.

Resources