So I know how to do simple string replacing with the SET command.
Example:
set /p a=
set a=%a:<=^<%
echo %a%
(This example will change the prompted variable to the same thing but with the < character to be ^< to be be properly echoed if needed to)
I want to do the same thing but with the % character but I can't get it to work.
#ECHO OFF
SETLOCAL
SET "something=%%he%%llo%%"
ECHO %something%
ECHO ============
SETLOCAL ENABLEDELAYEDEXPANSION
SET "anotherthing=!something:%%=x!"
endlocal&SET "anotherthing=%anotherthing%"
ECHO %something%
ECHO %anotherthing%
GOTO :EOF
Like this, you mean?
There was nothing wrong with your method, short of using doublequotes to protect from poison characters.
The main issue now, is in trying to see the content, because you'd be Echoing poison characters. To see it actually in place I included two methods, a Set command to list all variables beginning with a, (with a findstr thrown in to isolate only the one named a), and by using delayed expansion, which prevents the variable from being expanded when the command line is read/parsed. At the very bottom I included a method of showing it with the Echo command without using delayed expansion or doublequotes, as you can see to escape a caret, ^, you'll need in this case to use two more carets
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "a="
Set /P "a="
Set "a=%a:<=^<%"
Echo(%a%
Pause
(Set a) 2> NUL | %SystemRoot%\System32\findstr.exe /B /L /I "a="
Pause
SetLocal EnableDelayedExpansion
Echo(!a!
EndLocal
Pause
Echo(%a:^<=^^^<%
Pause
The full (known) rules for variable replacement can be found at SO:
Percent Expansion Rules
In short:
The search expression in a percent replacement expression can not start with a percent.
The search expression in a delayed replacement expression can not start with a exclamation mark.
But you can replace percent signs with delayed expression
setlocal EnableDelayedExpansion
set /p var=
set "var=!var:%%=REPLACE!"
echo(!var!
The percent sign itself has to be doubled here, because it collapse to a single percent in phase2 (percent expansion)
Related
When i run this snippet it blows up when i type the '|' character
SET /P _test=Enter your value:
echo %_test%
Enter your value: Hello|World
'World' is not recognized as an internal or external command,
operable program or batch file.
I would like %_test% to contain the text Hello|World as supplied, any ideas?
The only way to safely echo an arbitrary string is to use delayed expansion:
set /P _test="Enter your value: "
setlocal EnableDelayedExpansion
echo(!_test!
endlocal
The odd-looking syntax echo( allows even empty strings, and also the strings on, off or /?, which would otherwise be interpreted as keywords or options by the echo command.
Regard that changes to the variable _test after setlocal are gong to be lost after endlocal.
The following can be used to safely assign and input / output any string.
Note, Delayed expansion is Disabled at the time of string assignment in order to preserve ! expansion symbols in strings.
#Echo off
(Set LF=^
%= Above Empty lines Required =%)
Set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
::: - Macro to toggle delayed expansion and output / perform actions using var value
::: %#Output% <VarName>
Set #Output=For %%n in (1 2) Do if "%%n" == "2" (%\n%
For /F "Tokens=1 Delims=, " %%G in ("!Param!") Do (%\n%
Echo !%%~G! ^&^& Endlocal%\n%
)%\n%
) Else Setlocal EnableDelayedExpansion ^& Set Param=,
:Example
CLS
Call :input "Name" "Enter your Name:"
::: - To safely access any entered string Delayed Expansion should be enabled, especially with regards to redirection characters
::: - Conditional checks should be performed using doublequoting Ie: If "!VarName!" == "value" Command
::: - Must be enabled AFTER variable is defined in order to correctly set expansion characters
%#Output% Name
Pause
Goto :Example
:input <VarName> <Prompt>
::: - preserve input of expansion characters
Setlocal DisableDelayedExpansion
Set /P "Var=%~2"
::: - Ensure a value is assigned
If "%Var%" == "" Goto :input
Endlocal & Set "%~1=%Var%"
Exit /b
Simply enclose the string with quotes (") when you enter it
Do you mean something like this:
echo "Put in your name"
read -a words
var="${words[#]}"
echo $var
I'm trying to rename my files to remove any characters that cause problems in scripts. This works well for ampersand and exclamation point but when the file has the percent sign it doesn't show up in the variable to begin with. How do I pass files with special characters via for loop?
for %%v in (*) do call :validate "%%v"
exit /b
:validate
set "original=%~nx1"
set "newtitle=%original:!=%"
set "newtitle=%newtitle:&=and%"
setlocal enabledelayedexpansion
set "newtitle=!newtitle:%%= percent!"
if not "%newtitle%"=="%original%" ren %1 "%newtitle%"
Your problem is the line for %%v in (*) do call :validate "%%v", because thecall` starts the parser a second time and there all percents are evaluated a second time.
You should save the value into a variable and access these variable in your function instead.
setlocal DisableDelayedExpansion
for %%v in (*) do (
set "filename=%%~v"
call :validate
)
exit /b
:validate
setlocal EnableDelayedExpansion
set "original=!filename!"
set "newtitle=%original:!=exclam%"
set "newtitle=!newtitle:&=and!"
set "newtitle=!newtitle:%=percent!"
A possible way is to use delayed expansion:
set "newfilename=%filename:&=and%"
setlocal EnableDelayedExpansion
set "newfilename=!newfilename:%%= percent!"
endlocal
The %-sign must be escaped by doubling it in a batch file.
Note that the variable is no longer available beyond the endlocal command.
I used the quoted syntax, which is the safest way to define variables, even with white-spaces and special characters.
I'm manipulating some HTML via Batch. I'm using delayed expansion but when a semicolon is encountered inside double quotes, the script fails to copy anything after and including the semicolon.
It's probably due to the fact that I use double quotes when I pass the variable to the putLineInHTMLFile label (I need to keep things separated in labels).
#echo off
setlocal enableDelayedExpansion
del output.html
for /f "delims=" %%x in (file.html) do call :putLineInHTMLFile "%%x"
goto :EOF
:putLineInHTMLFile
set "line=%~1"
echo !line!>> output.html
file.html contains:
<tag1>
<tag"bla;2">
After running the script, output.html contains:
<tag1>
<tag"bla
I've tried escaping the semicolon with ^ or ^^. Didn't work. I've tried escaping the double quotes too. That didn't work either.
I can change the contents of file.html anyway I please just as long as I can include that semicolon in the output file.
This seems to work for the test-case given; no guarantees for wider use:
#echo off
setlocal enableDelayedExpansion
del output.html
for /f "delims=# tokens=*" %%x in (file.html) do (
set "safe=%%x"
set "safe=!safe:"=""!"
call :putLineInHTMLFile "!safe!"
)
goto :eof
:putLineInHTMLFile
set "line=%~1"
set "line=%line:""="%"
echo !line!>> output.html
:eof
Within the "body" of the for command, the %%x has not been split, it's only when processed by the call command that this happens. To protect that, I've used safe to double-up all double-quotes in the string, and then added a line in the subroutine to strip them out again.
This doesn't work properly if the double-quotes aren't matched, but in those cases, neither does the echoing of the trailing >, even when there are no semi-colons present.
This method works in all cases, as long as the quotes be matched (even number) in the input lines:
#echo off
setlocal enableDelayedExpansion
del output.html
for /f "delims=" %%x in (file.html) do call :putLineInHTMLFile "%%x"
goto :EOF
:putLineInHTMLFile
set line=%*
echo !line:~1,-1!>> output.html
PS - Please, do not include additional parts that not appears in the original code, like the :eof label... The label is written in uppercase letters in goto :EOF command to indicate that it is special. Type goto /? for further details.
Certainly. The problem is that the subroutine receives
"<tag"bla;2">"
for that line. The parser sees that as
Token1 : "<tag"bla
Token2 : 2">"
because ; like Space is a separator.
Sadly, without knowing what you intend to do within the subroutine, it's difficult to advise on how to circumvent the problem.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q43391363.txt"
SET "outfile=%destdir%\outfile.txt"
SET "outfile2=%destdir%\outfile2.txt"
del "%outfile%"
del "%outfile2%"
(for /f "delims=" %%x in (%filename1%) do set "line=%%x"&call :putLineInHTMLFile "%%x")>"%outfile2%"
goto :eof
:putLineInHTMLFile
ECHO %*
echo !line!>>"%outfile%"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
I used a file named q43391363.txt containing your data for my testing.
Produces files defined as %outfile% and %outfile2%
So - here's two different ways, one using conventional output direct to outfile1 and the other using redirection from a subroutine into outfile2.
At work I need to create a .bat script that reads the first 2 chars on the first line, of multiple files, and then echo them to the screen.
So far I have this:
#echo off
setlocal enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set first2 =<%%F
set first2=%first2:~0,2%
echo %first2%
)
But all it writes is: ECHO is off
Anyone got an idea what I have done wrong?
You are missing /p! This should work:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /r I:\Test\Filer %%F in (*.*) do (
SET /p first2=<%%F
SET first2=!content:~0,2!
ECHO !first2!
)
PAUSE
#echo off
setlocal enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set /p first2=<%%F
set "first2=!first2:~0,2!"
echo(!first2!
)
In delayedexpansion mode, %var% is the value of var at parse-time and !var! is the run-time value.
The ( in the echo will ensure that a newline is shown if var is not set (or "set" to a zero-length string)
The quotes in a set statement ensure that trailing spaces are not included in the value assigned to the variable.
Note that spaces are not allowed after the variablename in a string "set" statement; a variable with a trailing space in its name will be set, and this is not the same as the variable with no space in its name.
set /p is required to assign a value from a file. Be carefu of zero-length files and files containing a newline (CR LF) at the start!
Delayed Expansion will cause variables to be expanded at execution time rather than at parse time, this option is turned on with the SETLOCAL command. When delayed expansion is in effect variables may be referenced using !variable_name! (in addition to the normal %variable_name% )
#echo off
setlocal enableextensions enabledelayedexpansion
for /r I:\Test\Filer %%F in (*.*) do (
set /p first2=<"%%~F"
set "first2=!first2:~0,2!"
echo !first2!
)
Here in set /p first2=<"%%~F" use double quoted "%%~F" (for a case if a path or file name contains e.g. space) and ~ modifier (to avoid doubling of double quotes)
Resources:
EnableDelayedExpansion
Command Line arguments (Parameters) and their ~ modifier(s)
I have a script that has a lot of use of the SETLOCAL ENABLEDELAYEDEXPANSION command, so I start the script off that way (less headaches). However, it does not allow you to use the ! character without escaping each instance of it (and I want to create a long line of !s for an error logging section =D ) and I don't want to escape every one of them.
Is there a way to temporarily break out of SETLOCAL, then reenter it keeping all previously created variables within the original SETLOCAL?
For example:
SETLOCAL ENABLEDELAYEDEXPANSION
set var=HELLO
ECHO %var%
ENDLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %var%
The 2nd ECHO will not give you the previous value of var
EDIT: ^ will not allow you to escape the ! inside SETLOCAL ENABLEDELAYEDEXPANSION
setlocal DisableDelayedExpansion
set var=Value! with! many! Bangs!
setlocal EnableDelayedExpansion
echo !var!
You can nest it like Aacini shows it.
Or you can use the return technic or escape ! inside a EnableDelayed block with ^^!
Setlocal EnableDelayedExpansion
echo 1^^!^^!^^!^^!^^!^^!^^!
REM *** Or use a self removing quote
echo !="! 2^!^!^!^!^!^!
Setlocal DisableDelayedExpansion
echo 3 !!!!!!!!
set var=Hello
(
endlocal
rem Bring the value behind the endlocal barrier
set var=%var%
)
echo var is still there, %var%
The return technic can also be used for exclamation marks, but then it is a bit more complex.
It can be found at Make an environment variable survive ENDLOCAL