Reputation: 1214
I am trying to call a command from a batch file which is reading in lines from a file.
This is working correctly, except for when the line contains the redirection character >
.
Is there a way to tell call
to escape this character, or to replace it within the content of the for loop?
I've looked at setlocal enabledelayedexpansion
and (when the call is updated to use !
it still doesn't work).
set /p status=<%tmp_file%
for /f "delims=*" %%a in (%tmp_file%) do (
echo "%%a"
call check.bat "%%a"
echo.
if not "%errorlevel%" == "0" do exit /b 1
)
This produces the following output (when check.bat
echo's %1
)
"a"
"a"
"b -> b"
"b -"
I've tried to replace >
within %%a
but I'm not entirely sure how this can be achieved, each time i try, it yields an empty string, i.e.
set line=%a:^>=¬%
EDIT 1
Some more clarification (it appears to only be the case if %1
is set to a variable, and then that variable is used)?:
check.bat
:
set rawinput=%1
set input=%~1
echo %1
echo "%rawinput%"
echo "%input%"
echo.
This yields the following output, although im not quite sure why setting %1
to a variable causes it to mangle the value?
"a"
"a"
""a""
"a"
"b -> b"
"b -> b"
"b -"
Interestingly b -> b
is only output 2 times, echo "%rawinput%"
is not showing at all.
Both echo "%input%"
and echo "%rawinput%"
are writing to a file named b
.
This means that the check.bat
for b -> b
must be interpreted as:
echo "b -> b"
echo ""b -> b""
echo "b -> b" REM - this is what 'should' be happening, however does appear to be the case, as it writes '' to a file named b
echo.
If anyone can shed light on why echo "b -> b"
in a batch file does not appear to be behaving it would be greatly appreciated.
Upvotes: 1
Views: 1937
Reputation: 130919
You have multiple problems in your modified check.bat
The quotes are a state machine in that the 1st quote turns quoting semantics ON, the 2nd OFF, the 3rd ON, etc. An unquoted (and unescaped) >
is interpreted as an instruction to redirect output.
I've heavily modified check.bat by putting in a bunch of ECHO statements to provide a narrative of what is happening. Your original code is embedded in my version as all CAPS.
Here is the output of my modified version, which I hope explains why you are getting your results. I want you to read this output before you try to understand how my modified check.bat produces this output.
"a"
---------------------------------------------
Executing: SET RAWINPUT=%1 which expands to SET RAWINPUT="a"
Here is the result:
rawinput="a"
Executing: SET INPUT=%~1 which expands to SET INPUT=a
Here is the result:
input=a
Executing: ECHO %1 which expands to ECHO "a"
"a"
Executing: ECHO "%RAWINIPUT%" which expands to ECHO ""a""
""a""
Executing: ECHO "%INPUT%" which expands to ECHO "a"
"a"
"b -> b"
---------------------------------------------
Executing: SET RAWINPUT=%1 which expands to SET RAWINPUT="b -> b"
Here is the result:
rawinput="b -> b"
Executing: SET INPUT=%~1 which expands to SET INPUT=b -> b
Here is the result:
input=b -
Also created a file named "b" because the output of the command
is redirected. The file is empty because SET has no output.
Volume in drive C is OS
Volume Serial Number is EE2C-5A11
Directory of C:\Users\Public\utils
11/20/2012 09:30 AM 0 b
1 File(s) 0 bytes
0 Dir(s) 316,104,765,440 bytes free
Executing: ECHO %1 which expands to ECHO "b -> b"
"b -> b"
Executing: ECHO "%RAWINIPUT%" which expands to ECHO ""b -> b""
There is no screen output because output was redirected to file "b"
Here are the contents of "b":
""b -
Executing: ECHO "%INPUT%" which expands to ECHO "b -"
"b -"
Here is my modified check.bat that produces the output above.
setlocal enableDelayedExpansion
set value=%1
set "unquotedValue=%~1"
echo ---------------------------------------------
echo Executing: SET RAWINPUT=%%1 which expands to SET RAWINPUT=!value!
SET RAWINPUT=%1
echo Here is the result:
set rawinput
echo.
echo Executing: SET INPUT=%%~1 which expands to SET INPUT=!unquotedValue!
SET INPUT=%~1
echo Here is the result:
set input
if exist b (
echo.
echo Also created a file named "b" because the output of the command
echo is redirected. The file is empty because SET has no output.
echo.
dir b
del b
)
echo.
echo Executing: ECHO %%1 which expands to ECHO !value!
ECHO %1
echo.
echo Executing: ECHO "%%RAWINIPUT%%" which expands to ECHO "!rawinput!"
ECHO "%RAWINPUT%"
if exist b (
echo.
echo There is no screen output because output was redirected to file "b"
echo Here are the contents of "b":
type b
del b
)
echo.
echo Executing: ECHO "%%INPUT%%" which expands to ECHO "!input!"
ECHO "%INPUT%"
echo.
You can get your desired results via a variable if you do not add any quotes in your check.bat
set rawinput=%1
echo %rawinput%
But all hell can break loose if your original text file includes its own quotes.
That is the reason jeb suggests storing each line in a variable within your main routine and then pass the name of the variable to check.bat. Within check.bat you can use delayed expansion to safely work with any value without worrying about quotes or escapes.
Upvotes: 2
Reputation: 82418
Do not try to use call by value
, that's nearly impossible with batch.
Simply set a new variable with the value and then use the variable name.
for /f "delims=" %%a in (%tmp_file%) do (
set "line=%%a"
call :check
)
exit /b
:check
setlocal EnableDelayedExpansion
echo(!line!
endlocal
exit /b
Edit: Your problem
You try to call a function with the content "b -> b"
using
call check.bat "%%a"
this will expand to
call check.bat ""b -> b""
and that's the problem!
As the >
redirect character is now outside of the quotes, it will redirect the output of check.bat to the file b
.
You can escape a special character (outside of quotes) when using a call, but this is a bit advanced and has many problems.
So, I would recommend again, not using directly the content in a call.
You could use a reference, like
for /f "delims=" %%a in (%tmp_file%) do (
set "line=%%a"
call :check line
)
check.bat
setlocal EnableDelayedExpansion
set "var=!%1!"
echo(!var!
Upvotes: 3