1.

Solve : Batch file - conditional backup upon startup?

Answer»

Quote from: The Raddish

I do admit I do not fully understand the logic in the following command:

echo "!thisline!" | find "<setting id=""21"">" | find "</setting>"

You have to consider the whole line:

Code: [Select]echo "!thisline!" | find "<setting id=""21"">" | find "</setting>" && goto foundline
What's happening is this...

We send !thisline! through a pipe to an instance of the find command*. The search string is "". The quotes around "21" need to be doubled to make them literal so that find will treat them as part of the search string. If that search string is present, all of !thisline! is output by find. If it is not present, there will be no output. Any output (including the null output if the string was not found) is conducted by another pipe to a second instance of find. This time the search string is "". If that string is also present in !thisline!, then two things happen. First, !thisline! is output (to the console)** by the second instance of find. Secondly, find returns an errorlevel of zero. If either the first or second string are not found, the errorlevel will be nonzero. The && double ampersand operator*** means "if the previous operation gave a zero errorlevel, then perform the operation immediately following." Thus only if both strings are found in !thisline! will the goto command be executed.

* echo string1 | find string2 will echo string1 only if it contains string2. Find returns a zero errorlevel if the search string was found, and a nonzero errorlevel if it was not. If you only want the errorlevel and don't care to see the string, you can redirect the output to nul.

** to avoid screen clutter, I redirected the output of the second find to the null device with >nul but I see you have removed that.

*** command1 && command2 ... EXECUTE command1 and if it is successful (i.e. returns a errorlevel of zero) execute command2

simple example

dir cat.txt && echo There is a file called cat.txt in this folder

Or

echo %monthname% | find "December" && (
echo CHRISTMAS is coming!
echo The goose is getting fat
call Santa.bat
)

The converse is the || (double pipe) operator

operation1 || operation2 means execute command1 and if it "fails" (i.e. returns a nonzero errorlevel) execute command2.

I must have read dozens of descriptions of how and what pipe does. I loosely understood the concept, but was thoroughly confused when it came to using multiple pipes in a single line.

Your explanation in the above post was the most clear and and easy to understand description of how the pipe operator works that I have read to date. My hat's off to you, sir!

I have another question, but I'll post a new thread for it. It's related to this script but is a good question in it's own right.

Again, thank you for the time and effort you spend here educating others. Quote from: Salmon Trout on May 03, 2010, 12:28:27 PM
SPECIAL characters need escaping: the escape for most is ^. To echo a string with < or > or both, quote it. To escape one quote, use another.

note all quotes...

Code: [Select]@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%A in (test.xml) do (
REM note quotes in next line
set "thisline=%%A"
echo "!thisline!" | find "<setting id=""21"">" | find "</setting>">nul && goto foundline
)
:foundline
for /f "tokens=1-2 delims=^<^>" %%A in ("%thisline%") do set filepath=%%B
echo %filepath%

Using the above as a model, mine looks like this:

Code: [Select]@echo off
setlocal EnableExtensions
setlocal EnableDelayedExpansion

set XMLFILE=C:\test\file.xml

for /f "delims=" %%A in (%XMLFILE%) do (
set "THISLINE=%%A"
echo "!THISLINE!" | find "<setting id=""21"">" | find "</setting>">nul && goto FOUNDLINE
)

:FOUNDLINE
for /f "tokens=1-3 delims=^<^>" %%A in ("!THISLINE!") do set RAW_PATH=%%C
echo. %RAW_PATH%

This works on my sample file, but I found that when deployed on another machine that has a larger XML file, I got the following error on four lines:
Code: [Select]'#178' is not recognized as an internal or external command, operable program or batch file.
'#178' is not recognized as an internal or external command, operable program or batch file.
'#178' is not recognized as an internal or external command, operable program or batch file.
'#178' is not recognized as an internal or external command, operable program or batch file.
In searching the XML setup file on the other machine, there were four lines with #178 in them. So I copied those lines into a test file, and sure enough, the error appears when the batch script is run on the test file.

It doesn't really affect anything other than displaying the error while parsing the XML file for the file path, but I'd like to understand why it triggers on these lines and if there is anything that can be done to correct it.

sample file.xml:
Code: [Select] <column data-type="9" description="" modifying-command="276" name="Solar_kW" process="" units="kW/m&#178;">
<column data-type="9" description="" modifying-command="276" name="Solar_kJ" process="" units="kJ/m&#178;">
<column data-type="7" description="Smp" modifying-command="0" name="Solar_kW" process="Smp" units="kW/m&#178;">
<column data-type="7" description="Smp" modifying-command="0" name="Solar_kJ" process="Smp" units="kJ/m&#178;">



<setting id="2">1</setting>
<setting id="3">1</setting>
<setting id="12">257149</setting>
<setting id="15">1</setting>
<setting id="16">2</setting>
<setting id="17">%a\raw_data.dat</setting>
<setting id="18">10</setting>
<setting id="20">3</setting>
<setting id="21">C:\Datalogger\raw_data.dat</setting>
<setting id="22">0</setting>
<setting id="23">30000</setting>
<setting id="1" />
<setting id="2">0</setting>
<setting id="3">2</setting>
<setting id="12">9</setting>
<setting id="15">1</setting>
<setting id="16">2</setting>
<setting id="17">%a\%s_%n.dat</setting>
<setting id="18">10</setting>
<setting id="20">3</setting>
<setting id="21">C:\Datalogger\final_storage_2.dat</setting>
<setting id="22">1</setting>
<setting id="23">30000</setting>
<setting id="28">3</setting>
<setting id="30">6619599</setting>
<setting id="31">3</setting>



<setting id="2">1</setting>
<setting id="14" />
<setting id="15">1</setting>
<setting id="16">1</setting>
<setting id="17">C:\Datalogger\ports_and_flags.dat</setting>
<setting id="18">10</setting>
<setting id="20">3</setting>
<setting id="21">C:\Datalogger\Sifter\ports_and_flags.dat</setting>
<setting id="22">1</setting>
It's the ampersand before the #178 which is causing the error message. The ampersand is a well known "poison character". The command interpreter (cmd.exe) regards it as the command chaining character.

echo hello & echo goodbye

hello
goodbye

echo hello & goodbye

hello
'goodbye' is not recognized as an internal or external command, operable program or batch file.

Processing any string with any & characters will cause errors unless special precautions are taken.

A workaround that I suggest is to replace the & with another harmless character e.g. an asterisk, before sending the line through SEND.


@echo off
setlocal EnableExtensions
setlocal EnableDelayedExpansion

set XMLFILE=C:\test\file.xml

for /f "delims=" %%A in (%XMLFILE%) do (
set "THISLINE=%%A"
set THISLINE=!THISLINE:^&=*!
echo "!THISLINE!" | find "<setting id=""21"">" | find "</setting>">nul && goto FOUNDLINE
)

:FOUNDLINE
for /f "tokens=1-3 delims=^<^>" %%A in ("!THISLINE!") do set RAW_PATH=%%C
echo. %RAW_PATH%





Thanks once again, it works as expected!


Discussion

No Comment Found