Pass arguments with special characters in BATCH - windows

I have batch file (for example: test.bat) which takes up some arguments, one is login, and second one is a password. Password contains special characters ( password!?> ) so to prevent from executing special characters i pass it in double quotes ( "password!?>" ), but I need to pass it to next batch which dumb mysql database so password must be without " ", how can I pass my password like a normal string without double quotes without executing this special characters?

The following is a method for safely capturing arguments to a script and using them.
#Echo off
Rem # input capture method is a modified version of Dave Benhams method:
Rem # https://www.dostips.com/forum/viewtopic.php?t=4288#p23980
SETLOCAL EnableDelayedExpansion
1>"%~f0:Params.dat" <"%~f0:Params.dat" (
SETLOCAL DisableExtensions
Set prompt=#
Echo on
For %%a in (%%a) do rem . %*.
Echo off
ENDLOCAL
Set /p "Args="
Set /p "Args="
Set "Args=!Args:~7,-2!"
) || (
1>&2 Echo(%~nx0 requires an NTFS drive system to function as intended.
CMD /C Exit -1073741510
) || Goto:Eof
Echo(some command !Args:"=!
Pause

Related

Reading lines from a txt file into variables in batch

I am trying to figure out how to read IP addresses from a file named "IPList.txt) into individual variables in a batch script. Here's what I have so far.
:DEFINITIONS
set LOGFILE=IPScript.log
set IPLIST=C:\IPLIST.txt
echo Script Started >> %LOGFILE%
goto SetIP
:SetIP
for /f "tokens=*" %%a in (%IPLIST%) do (
set FirstIP=%%a
)
echo The first IP is %FirstIP% >> %LOGFILE%
exit
The output I'm getting in "IPscript.log" is "The First IP is: " with no IP listed, just a space. Also, is there a way for me to set multiple IPs like this, in just one for loop?
Here's a quick example to assist you:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
:DEFINE_LOCAL_VARIABLES
Set "IPLIST=C:\IPLIST.txt"
Set "LOGFILE=IPScript.log"
:CHECK_SOURCE_EXISTS
For %%G In ("%IPLIST%") Do If "%%~aG" Lss "-" (
Echo The file %IPLIST% does not exist.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
) Else If "%%~aG" GEq "d" (
Echo Expected a file, but %IPLIST% is a directory.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
)
:UNDEFINE_LOCAL_VARIABLES
For /F "Delims==" %%G In ('"(Set IP[) 2> NUL"') Do Set "%%G="
:START_MAIN
Set "i=1000"
(
Echo Script Started
For /F UseBackQ^ Delims^=^ EOL^= %%G In ("%IPLIST%") Do (
Set /A i += 1
SetLocal EnableDelayedExpansion
For %%H In ("!i:~-3!") Do (
EndLocal
Set "IP[%%~H]=%%G"
Echo IP[%%~H] is %%G
)
)
) 1> "%LOGFILE%"
:CHECK_IP_VARIABLES_EXIST
If Not Defined IP[001] (
Echo %IPLIST% had no readable file content.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
)
:VIEW_IP_VARIABLES
Set IP[
Pause & GoTo :EOF
If you have an existing %LOGFILE%, and you intend to append to it, (as opposed to overwrite/create one), change 1> "%LOGFILE%" to 1>> "%LOGFILE%".
If you didn't really need %LOGFILE%, e.g. it was used by you just for testing, it would look a little more like this:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
:DEFINE_LOCAL_VARIABLES
Set "IPLIST=C:\IPLIST.txt"
:CHECK_SOURCE_EXISTS
For %%G In ("%IPLIST%") Do If "%%~aG" Lss "-" (
Echo The file %IPLIST% does not exist.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
) Else If "%%~aG" GEq "d" (
Echo Expected a file, but %IPLIST% is a directory.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
)
:UNDEFINE_LOCAL_VARIABLES
For /F "Delims==" %%G In ('"(Set IP[) 2> NUL"') Do Set "%%G="
:START_MAIN
Set "i=1000"
Echo Script Started
For /F UseBackQ^ Delims^=^ EOL^= %%G In ("%IPLIST%") Do (
Set /A i += 1
SetLocal EnableDelayedExpansion
For %%H In ("!i:~-3!") Do (
EndLocal
Set "IP[%%~H]=%%G"
)
)
:CHECK_IP_VARIABLES_EXIST
If Not Defined IP[001] (
Echo %IPLIST% had no readable file content.
Echo Press any key to end this script.
Pause 1> NUL
GoTo :EOF
)
:VIEW_IP_VARIABLES
Set IP[
Pause & GoTo :EOF
The last line in both examples is for display purposes. If you're testing/running this script from within cmd.exe, you may omit it.
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" "%filename1%"') DO set "IP%%a=%%b"
)
set IP
findstr reads the file in filename1 and produces a list of the format n:content of line n.
The for /f reads this list, and partitions it using 2 tokens - %%a gets the first token (1) and %%b the remainder of the line (*) using : as a delimiter.
So simply set the IP variables from there.
set ip displays all variables that start ip
Probability is that your file contains empty line(s) after the last IP. Your original code would have reported the LAST IP, not the FIRST as the value in firstip is overwritten on each iteration, so it would be cleared by being set to nothing when the empty lines are read.
The solution above would simply execute (eg) set "IP6=" under these circumstances, clearing the variable.
You could have obtained the first IP by using
if not defined firstip set "FirstIP=%%a"
I'm assuming a clean environment here - that is, that each batch you run includes a setlocal after the #echo off (which restores the initial environment when the batch finishes) and the variables used are known-empty.
Bonus:
changing the set command to
set "IP%%a=%%b"&if "%%b" neq "" set "ipmax=%%a"
would set ipmax to the number of the last non-empty line, as %%b is empty for an empty line.
The batch file could have following command lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LOGFILE=%~dp0IPScript.log"
set "IPLIST=%~dp0IPLIST.txt"
set "AddressCount=0"
echo Script started>"%LOGFILE%"
for /F "delims==" %%I in ('set IP_Address_ 2^>nul') do set "%%I="
if exist "%IPLIST%" for /F "useback delims=" %%I in ("%IPLIST%") do (
set /A AddressCount+=1
call set "IP_Address_%%AddressCount%%=%%I"
)
if not %AddressCount% == 0 (
if %AddressCount% == 1 (
echo The IP address is:
) else echo The IP addresses are:
echo/
set IP_Address_
) >>"%LOGFILE%"
endlocal
The batch file first two command line define the execution environment which means:
Disable command echo mode.
Push current command extension state on stack and enable command extensions.
Push current delayed expansion state on stack and disable delayed environment variable expansion.
Push path of current directory on stack.
Push pointer to current list of environment variables on stack and create a copy of the entire current environment variables list to use next.
The third and fourth line define two environment variables with the name of the log file and the name of the IP address list file with full qualified file name. The file path of both files is defined as path of the directory containing the batch file referenced with %~dp0. This path always ends with \ and for that reason no additional backslash is needed on concatenating this path with the two file names.
The fifth line define the environment variable AddressCount with value 0.
The sixth line creates the log file in current directory with overwriting an already existing log file. There is no space left to redirection operator > as this space would be output by command ECHO and therefore written as trailing space also into the log file.
The first FOR command with option /F starts in background with %ComSpec% /c one more command process with the command line between ' appended as additional arguments. So executed is in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c set IP_Address_ 2>nul
Windows creates a copy of current list of environment variables for the command process started in background. The background command process runs command SET to output all environment variables with name, an equal sign and the string value assigned to the variable line by line of which name starts with IP_Address_. This output to handle STDOUT of background command process is captured by FOR respectively the command process which is processing the batch file. The error message output by SET on no environment variable define with a name starting with IP_Address_ is redirected from handle STDERR to device NUL to suppress this error message.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR processes the captured output line by line after started background command process closed itself after execution of command SET. Empty lines are always ignored by FOR which can be ignored as there are no empty lines output by SET.
FOR would split up by default the current line into substrings using normal space and horizontal tab as delimiters. This default line splitting behavior is not wanted here. The option delims== defines the equal sign as string delimiter to split the line on = which is the character between variable name and variable value.
FOR would next ignore the line if the first substring would start with a semicolon which is the default end of line character. The command SET outputs only lines starting with IP_Address_ and for that reason the default eol=; can be kept in this case.
FOR assigns just the first substring to the specified loop variable I as tokens=1 is the default. That is exactly the wanted behavior in this case.
So FOR assigns one environment variable name starting with IP_Address_ to loop variable I and runs next the command SET to delete this environment variable in current list of environment variables of command process processing the batch file.
In other words the first FOR is for deletion of all environment variables of which name starts with IP_Address_ defined by chance outside the batch file.
The next line first checks if the file with the list of environment variables exists at all in directory of the batch file. In this case once again FOR is used to process lines, but this time read line by line from the specified list file instead of captured output of a background command process. The usage of " instead of ' with the option usebackq makes the difference.
There is used the option delims= to define an empty list of delimiters resulting in getting each non-empty line not starting with ; assigned completely to the specified loop variable I.
For each string assigned to loop variable I the current value of environment variable AddressCount is incremented by one using an arithmetic expression evaluated by command SET.
This value is used on next command line to define an environment variable of which name starts with IP_Address_ and has appended the current address count value with line read from file assigned to the environment variable.
There is usually used delayed expansion for such tasks on which the second command line in command block of second FOR loop would be:
set "IP_Address_!AddressCount!=%%I"
But the code above uses the alternative method with command call to parse set "IP_Address_%%AddressCount%%=%%I" a second time which was already modified to set "IP_Address_%AddressCount%=%I" before the IF condition left to FOR was executed at all.
The next IF condition checks if any line was read from the list file with the IP addresses. In this case first an information line is output depending on having read exactly one line from the file or more than one line. Then an empty line is output and last all environment variables of which name starts with IP_Address_ with = and the line (IP address) assigned to the environment variable. All this output is appended to the log file.
The last command restores previous execution environment which means:
Discard the current list of environment variables and pop from stack the pointer to initial list of environment variables resulting in restoring the initial list of environment variables. In other words all environment variables defined or modified by the batch file after command SETLOCAL in second command line are lost forever.
Pop path of current directory from stack and make this directory again the current directory. The current directory between setlocal and endlocal was not changed by the code between and so this does not matter here.
Pop delayed expansion state from stack and enable or disable delayed environment variable expansion accordingly to restore initial delayed expansion behavior.
Pop current command extension state from stack and enable or disable command extensions accordingly to restore initial command extension behavior.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
if /?
set /?
setlocal /?
See also:
Variables are not behaving as expected
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Microsoft's documentation for the Windows Commands
SS64.com - A-Z index of Windows CMD commands

Create new string from 1st character of each word of a multi word string

I have a need for a Windows NT command script to do the following:
- Read variable string from command line
- Take that variable and create new string based off 1st byte of each word
The incoming string in the Windows NT command script is %1.
The string may vary in length and number of words, but always ends with (something here) [something there].
Example - Incoming value from command line including quotes:
"This is my string for a new name (comment) [comment 2]"
The string I need to create is:
Timsfann
These characters are from the 1st letter in each of the words in the above string and stopping when it gets to the parenthesis in (comment).
The above string will be concatenated with a date/time string to create a unique filename. The finished string should be set to a system variable so that programs can find the finished value.
Any help would be appreciated.
I've been attempting using a FOR loop, but can't seem to get it to work as desired.
#Crimsyn, if it's easier for you to understand, here's another one of the few ways, which doesn't use delayed expansion or the FOR statement:
#Echo Off
Call :Loop %~1
Echo(%oStr%&Pause
Exit/B
:Loop
If "%~1"=="" GoTo :EOF
Set "iStr=%~1"
If "%iStr:~,1%"=="(" GoTo :EOF
Set "oStr=%oStr%%iStr:~,1%"
Shift&GoTo Loop
Another one! Although simpler and shorter, this method could be harder to understand... ;)
#echo off
setlocal EnableDelayedExpansion
set "str=%~1 "
set "str=%str:(= " & rem %
set "result="
set "word=%str: =" & set "result=!result!!word:~0,1!" & set "word=%"
echo %result%
Hint: execute it with echo on
Just one of a few ways you could do this.
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1 delims=(" %%G IN ("%~1") do set "line=%%G"
FOR %%G IN (%line%) DO (
set tline=%%G
set code=!code!!tline:~0,1!
)
echo %code%
pause

echo variable is not working in batch file

My batch file execution throws error at echo echo %outfvar%. The following is the batch file I wrote:
setlocal ENABLEDELAYEDEXPANSION
set /a incvar = 1
set outfvar = "outfile"_!incvar!".res"
echo !outfvar!
echo *.txt > !outfvar!
set /a incvar = incvar+1
FOR %%pat in (%*) do(
FOR /F %%k in (!outfvar!) DO( grep -l !pat! !k! >>outfile_!incvar!.res)
set /a incvar = incvar+1
set outfvar = "outfile"_!incvar!.res
)
Error is "%pat was unexpected at this time.."
Can anybody help me to execute this batch file successfully?
Remove the spaces around = in all set commands.
There must be a space in between do and ( in the line of for.
The line
set outfvar = "outfile"_%incvar%".res"
should read
set "outfvar=outfile_%incvar%.res"
(The quotes as you stated them were part of the string value.)
for variables must consist of one letter only and need to be expanded by preceding with %%. You are trying to use %%pat in your code, which will not work. State %%p instead (also inner for).
Finally, you need delayed expansion to be able to read variables you modify within the same (compound) command, the for in your code. See this post to learn how it works.

Writing a script that can be both piped to and given direct input

This is a follow-on question from here, posted at the suggestion of the person who originally answered it.
I'm trying to create a script that will both take piped input and also direct input from the command line. I wrote two scripts; the first is called create and the other is called edit. I give the code below.
#echo off
REM create
if -%1-==-- (
REM Piped
set /p name=
copy nul %name% > nul
echo %name%
) else (
REM Not piped
copy nul %1 > nul
)
#echo off
REM edit
if -%1-==-- (
REM Piped
set /p file=
start notepad++.exe %file%
) else (
REM Not piped
start notepad++.exe %1
)
I have added remarks to clarify which is which, and what my intent was. Now, the normal input (for example, if I just type create foo.txt into the command prompt) works fine, but the moment I try piping (for example, create foo.txt | edit) I get strange behaviour, namely, the edit script tries to open a completely different file to foo.txt in this example! What am I missing or doing wrong?
In batch files, when execution reaches a line, it is parsed and then executed. At parse time, all variable reads inside the line are replaced with their corresponding value.
This applies to lines and blocks, where a block are all the lines enclosed in parenthesis. Blocks are readed, parsed, and get variables reads replaced with variables values before executing any line inside the block.
What you are seeing in your code is that the variable %file% gets its value assigned inside a block, and then, inside the same block, you try to read the variable value. But as all variable reads has been replaced with the value they have before entering the block, you can't get the changed value.
To handle it, delayed expansion is needed. When delayed expansion is active, you can indicate to cmd that some variable reads should be delayed to the moment the line is executed. Your code should be something like
#echo off
setlocal enabledelayedexpansion
REM create
if -%1-==-- (
REM Piped
set /p name=
copy nul !name! > nul
echo !name!
) else (
REM Not piped
copy nul %1 > nul
)
#echo off
setlocal enabledelayedexpansion
REM edit
if -%1-==-- (
REM Piped
set /p file=
start notepad++.exe !file!
) else (
REM Not piped
start notepad++.exe %1
)
variables that need delayed read are accessed using !var! sintax.

How do you strip quotes out of an ECHO'ed string in a Windows batch file?

I have a Windows batch file I'm creating, but I have to ECHO a large complex string, so I'm having to put double quotes on either end. The problem is that the quotes are also being ECHOed to the file I'm writing it to. How do you ECHO a string like that and strip the quotes off?
UPDATE:
I've spent the last two days working on this and finally was able to kludge something together. Richard's answer worked to strip the quotes, but even when I put the ECHO in the subroutine and directly outputted the string, Windows still got hung up on the chars in the string. I'll accept Richard's answer since it answers the question asked.
I ended up using Greg's sed solution, but had to modify it because of sed/windows bugs/features (it didn't help that it came with no documentation). There are a few caveats to using sed in Windows: you have to use double quotes instead of single quotes, you can't escape the double quotes in the string directly, you have to endquote the string, escape using the ^ (so ^") then beqin quote for the next section. Also, someone pointed out that if you pipe input to sed, there's a bug with a pipe being in the string (I didn't get to verify this since in my final solution, I just found a way not to have all quotes in the middle of the string, and just removed all quotes, I never could get the endquote to be removed by itself.) Thanks for all the help.
The call command has this functionality built in. To quote the help for call:
Substitution of batch parameters (%n) has been enhanced. You can
now use the following optional syntax:
%~1 - expands %1 removing any surrounding quotes (")
Here is a primitive example:
#echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof
:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof
Output:
C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text
I should credit the 'environment variable tunneling' technique (endlocal&set ret=%thestring%) to Tim Hill, 'Windows NT Shell Scripting'. This is the only book I have ever found that addresses batch files with any depth.
The following approach can be used to print a string without quotes:
echo|set /p="<h1>Hello</h1>"
pushing this string into file:
echo|set /p="<h1>Hello</h1>" > test.txt
pushing this string into file and appending a CR/LF:
echo|(set /p="<h1>Hello</h1>" & echo.) > test.txt`
To check:
type test.txt
You can use the %var:x=y% construction that replaces all x with y.
See this example what it can do:
set I="Text in quotes"
rem next line replaces " with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without'
echo stripped %J:in=without%
To remove all quotation marks from a set variable, you need Delayed Variable Expansion to securely expand the variable and process it. Expansion using percent signs (i.e. %VAR% and %1) are inherently unsafe (they are vulnerable to command injection; read this for details).
SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.
To strip quotes from a text file or a command output, things will get complicated because with Delayed Expansion, string like !VAR! within the text document will get expanded (within the %%i expansion in FOR /F) when it shouldn't. (This is another vulnerability—information disclosure—that's not documented elsewhere.)
To safely parse the document, a switch between delayed-expansion-enabled and -disabled environment is needed.
REM Suppose we fetch the text from text.txt
SETLOCAL DisableDelayedExpansion
REM The FOR options here employs a trick to disable both "delims"
REM characters (i.e. field separators) and "eol" character (i.e. comment
REM character).
FOR /F delims^=^ eol^= %%L IN (text.txt) DO (
REM This expansion is safe because cmd.exe expands %%L after quotes
REM parsing as long as DelayedExpansion is Disabled. Even when %%L
REM can contain quotes, carets and exclamation marks.
SET "line=%%L"
CALL :strip_quotes
REM Print out the result. (We can't use !line! here without delayed
REM expansion, so do so in a subroutine.)
CALL :print_line
)
ENDLOCAL
GOTO :EOF
REM Reads !line! variable and strips quotes from it.
:strip_quotes
SETLOCAL EnableDelayedExpansion
SET line=!line:^"=!
REM Make the variable out of SETLOCAL
REM I'm expecting you know how this works:
REM (You may use ampersand instead:
REM `ENDLOCAL & SET "line=%line%"`
REM I just present another way that works.)
(
ENDLOCAL
SET "line=%line%"
)
GOTO :EOF
:print_line
SETLOCAL EnableDelayedExpansion
ECHO !line!
ENDLOCAL
GOTO :EOF
The delims^=^ eol^= in the code above probably needs explanation:
This effectively disables both "delims" characters (i.e. field separators) and "eol" character (i.e. comment character). Without it, the "delims" will default to tab and space and "eol" defaults to a semicolon.
The eol= token always read whichever the next character it is after the equal sign. To disable it this token has to be in the end of the options string so that no character may be used for "eol", effectively disabling it. If the options string is quoted, it might use quotation mark (") as the "eol", so we must not quote the options string.
The delims= option, when it's not the last option in the options string, will be terminated by a space. (To include space in "delims" it has to be the last option of FOR /F options.) So delims= followed by a space and then another option disables the "delims".
I know that it is not actually for the author, but if you need to send some text to the file without quotes - the solution below works for me. You do not need to use quotes in the echo command, just surround the complete command with brackets.
(
echo first very long line
echo second very long line with %lots% %of% %values%
) >"%filename%"
This worked for me:
SET "SOMETHING=Complex (String) (of stuff!)"
echo !SOMETHING! >> file.txt
This will turn "C:\Program Files\somefile.txt" into C:\Program Files\somefile.txt
while still preserving cases such as Height=5'6" and Symbols="!##
:DeQuote
SET _DeQuoteVar=%1
CALL SET _DeQuoteString=%%!_DeQuoteVar!%%
IF [!_DeQuoteString:~0^,1!]==[^"] (
IF [!_DeQuoteString:~-1!]==[^"] (
SET _DeQuoteString=!_DeQuoteString:~1,-1!
) ELSE (GOTO :EOF)
) ELSE (GOTO :EOF)
SET !_DeQuoteVar!=!_DeQuoteString!
SET _DeQuoteVar=
SET _DeQuoteString=
GOTO :EOF
Example
SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%
The above answer (starting with :DeQuote) assumes delayed environment variable expansion is set to on. From cmd /?:
Delayed environment variable expansion is NOT enabled by default. You
can enable or disable delayed environment variable expansion for a
particular invocation of CMD.EXE with the /V:ON or /V:OFF switch. You
can enable or disable completion for all invocations of CMD.EXE on a
machine and/or user logon session by setting either or both of the
following REG_DWORD values in the registry using REGEDT32.EXE:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion
and/or
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion
to either 0x1 or 0x0. The user specific setting takes precedence over
the machine setting. The command line switches take precedence over the
registry settings.
If delayed environment variable expansion is enabled, then the exclamation
character can be used to substitute the value of an environment variable
at execution time.
The following batch file starts a series of programs with a delay after each one.
The problem is to pass a command line with parameters for each program. This requires quotes around the program argument, which are removed when the call is made. This illustrates a few techniques in batch file processing.
Look in the local subroutine :mystart for how an argument in quotes is passed in, and the quotes are removed.
#echo off
rem http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/if.mspx?mfr=true
rem Start programs with delay
rem Wait n seconds
rem n number retries to communicate with the IP address
rem 1000 milliseconds between the retries
rem 127.0.0.1 is the LocalHost
rem start /b (silent) /min (minimized) /belownormal (lower priority)
rem /normal provides a no-op switch to hold the place of argument 1
rem start /normal "Opinions" %SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion
rem ping 127.0.0.1 -n 8 -w 1000 > nul
rem Remove quotes in Batch
rem http://ss64.com/nt/syntax-dequote.html
rem String manipulation in Batch
rem http://www.dostips.com/DtTipsStringManipulation.php
rem ^ line continuation
rem
rem set p="One Two" p has the exact value "One Two" including the quotes
rem set p=%p:~1,-1% Removes the first and last characters
rem set p=%p:"=% Removes all double-quotes
rem set p=%p:cat=mouse% Replaces cat with mouse
rem ping 127.0.0.1 -n 12 -w 1000 > nul
rem 1 2 3 4
#echo on
call :mystart /b/min "Opinions" "%SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion" 8
#echo on
call :mystart /b/min "Notepad++" D:\Prog_D\Notepad++\notepad++.exe 14
#echo on
call :mystart /normal "Firefox" D:\Prog_D\Firefox\firefox.exe 20
#rem call :mystart /b/min "ProcessExplorer" D:\Prog_D\AntiVirus\SysInternals\procexp.exe 8
#echo on
call :mystart /b/min/belownormal "Outlook" D:\Prog_D\MSOffice\OFFICE11\outlook.exe 2
#echo off
goto:eof
:mystart
#echo off
rem %3 is "program-path arguments" with the quotes. We remove the quotes
rem %4 is seconds to wait after starting that program
set p=%3
set p=%p:"=%
start %1 %2 %p%
ping 127.0.0.1 -n %4 -w 1000 > nul
goto:eof
Using the FOR command to strip the surrounding quotation marks is the most efficient way I've found to do this. In the compact form (Example 2) it's a one-liner.
Example 1: The 5-line (commented) solution.
REM Set your string
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
REM Echo your string into the FOR loop
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO (
REM Use the "~" syntax modifier to strip the surrounding quotation marks
ECHO %%~A
)
Example 2: The 1-liner real-world example.
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO #ECHO %%~A
I find it interesting that the inner echo ignores the redirection characters '<' and '>'.
If you execute ECHO asdfsd>asdfasd you will write file out instead of std out.
Hope this helps :)
Edit:
I thought about it and realized there is an even easier (and less hacky) way of accomplishing the same thing. Use the enhanced variable substitution/expansion (see HELP SET) like this:
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
ECHO %STR:~1,-1%
That will print all but the first and last characters (your quotation marks). I would recommend using SETLOCAL ENABLEDELAYEDEXPANSION too. If you need to figure out where quotation marks are located in the string you can use FINDSTR to get the character #s.
Daniel Budzyński's response is brilliant. It works even in situations where there are special characters in the output. For example:
C:\> for /f "usebackq tokens=2 delims=:" %i in (`%comspec%\..\ping -n 1 -w 200 10.200.1.1 ^| \
findstr /c:"TTL="`) do echo|set /p="%i"
bytes=32 time<1ms TTL=255
If you try tried a simple echo without the quotes, you get a error, due to the "<" in the variable:
C:\> set "output=bytes=32 time<1ms TTL=255"
C:\> echo %output%
The system cannot find the file specified.
C:\> echo|set /p="%output%"
bytes=32 time<1ms TTL=255
Brute force method:
echo "foo <3 bar" | sed -e 's/\(^"\|"$\)//g'
This requires finding a suitable Win32 version of sed, of course.
http://unxutils.sourceforge.net/ is a native win32 port of a bunch of GNU utilities including sed, gawk, grep and wget. (sorry that I don't have enough rep to post this as a comment!)

Resources