1.

Solve : Escape characters in for loop delimiter?

Answer»

Hi,

I've searched everywhere without luck for the answer to how to escape a double quote as a delimiter in the for /F "tokens=1* delims=:\=" etc command syntax. All the delimiters currently listed are valid and work, but the " is also used as a delimiter in the input file, and I can't figure out how to include it in my delimiters.

Thanks, in ADVANCE,
KarenI tried using the escape character (^) but the for command choked and spit it back out. Any chance you can use %~ notation to remove the quotes from a token.

This would be easier if we could see your code and a sample of the data.

 Here is the script:

for /F "usebackq tokens=1-6 delims=:\=" %%A in (
`findstr /C:"\"ORACLE_HOME\"=" c:\temp\tns_loc.txt`
) do (
 set drvltr=%%B
REM set drvltr=%drvltr:~2,1% (this didn't work. the " confuses it)
 set dir4=%%F
 echo %%B %%C %%D %%E %%F
 echo %%B %drvltr%
 echo %%F %dir4%
)

Here is the record in the file:
"ORACLE_HOME"="C:\\oracle\\product\\10.2.0\\client_1"

Here is the current output:
"C oracle product 10.2.0 client_1"
"C        <--- Notice, %drvltr% is blank
client_1" client_1"

The first token is ignored. The second token comes up as "C and the sixth token comes up as client_1". I need to find a way to strip the ", and the set var doesn't work. So, I thought if I could specify the " as a delimiter, I could remove it that way. However, because the double quote is used to contain the tokens option syntax, I have to escape it somehow. I tried doubling up on the double quote "", but that made no difference. The normal escape character \ is already specified as a delimiter and it's working fine.
Okay. I've decided I'm losing my mind. The following code works consistently and properly when you execute it from the command line:
set drvltr="C
set drvltr2=%drvltr:~1%
set drv
drvltr="C
drvltr2=C

When I run the same code in a bat file two times in a row (with no changes at all):
Execution one: (new session)
C:\temp>(
set drvltr="C
 set drvltr2=~1
 set dir4=client_1"
 echo "C oracle product 10.2.0 client_1"
 echo "C
 echo client_1"
)
"C oracle product 10.2.0 client_1"
"C
client_1"

C:\temp>set dr
drvltr="C
drvltr2=~1




Execution two: (same session)
C:\temp>(
set drvltr="C
 set drvltr2=C
 set dir4=client_1"
 echo "C oracle product 10.2.0 client_1"
 echo "C ~1
 echo client_1" client_1"
)
"C oracle product 10.2.0 client_1"
"C ~1
client_1" client_1"

C:\temp>set dr
drvltr="C
drvltr2=C


Why would it take two executions to result in the variable having the proper value? I figured it out, finally:

I moved the second set and the echo statements out of the for loop:

for /F "usebackq tokens=1-6 delims=:\=" %%A in (
`findstr /C:"\"ORACLE_HOME\"=" c:\temp\tns_loc.txt`) do (
 set drvltr=%%B
 set dir4=%%F
)

 set drvltr2=%drvltr:~1%

 echo %%B %%C %%D %%E %%F
 echo %%B %drvltr2%
 echo %%F %dir4%

However, since the possiblity exists that this file will have more than one oracle_home record in it and I need to process both, I have to find some way to manage this. Perhaps by executing a sub-routine outside the loop and then returning into the loop?


Sometimes it's easier to break down the task rather than do everything at once.

Code: [Select]echo off
for /F "tokens=1-2 delims==" %%A in ('findstr "ORACLE_HOME" c:\temp\tns_loc.txt') do (
echo drive: %%~dB
echo path: %%~pB
echo file: %%~nB
for /f "tokens=1-5 delims=\" %%I in ("%%~B") do (
echo drive: %%I
echo top level: %%J
echo subfolder: %%K
echo subfolder: %%L
echo file: %%M
)
)

Good luck. 
Here is the final code: It works on single and multiple records in the file.


REM retrieve all subkeys for the ORACLE installation from the
REM Windows registry and subset entries with "ORACLE_HOME"
REM to a temp file

 regedit /e c:\temp\tns_location.txt  "HKEY_LOCAL_MACHINE\Software\ORACLE"
 find "ORACLE_HOME" c:\temp\tns_location.txt > c:\temp\tns_loc.txt

REM there are header rows in the file
REM read through the rows in the resulting file until we reach the row that has data in it
REM test the record to see if it has data
REM parse the record for the data values we seek

for /F "tokens=1-4 delims=/- " %%S in ('date/T') do set DATE=%%V%%T%%U

echo %DATE%

echo "for loop"

for /F "usebackq tokens=1-6 delims=:\=" %%A in (
`findstr /C:"\"ORACLE_HOME\"=" c:\temp\tns_loc.txt`) do (
 set drvltr=%%B
 set dir1=%%C
 set dir2=%%D
 set dir3=%%E
 set dir4=%%F

 echo %%B %%C %%D %%E %%F
 echo %drvltr% %dir1% %dir2% %dir3% %dir4%
 )

 set drvltr2=%drvltr:~1%:
 echo %drvltr2% %dir1% %dir2% %dir3% %dir4%
 set ORACLE_HOME=%drvltr2%\%dir1%\%dir2%\%dir3%\%dir4%
 ECHO %ORACLE_HOME%
 cd %ORACLE_HOME%\NETWORK\ADMIN
 copy tnsnames.ora tnsnames.ora.bkp%DATE%
 copy c:\temp\tnsnames.ora %ORACLE_HOME%\NETWORK\ADMIN

:eofWhy not use the = as the delimiter and dequote each token using the ~ modifier?

Since the 2nd token appears to be a valid path you can use the ~d ~p ~n modifiers
to get the drive letter, path and folder name if you want those

Code: [Select]for /f "tokens=1,2 delims==" %%S in (token.txt) do (
    echo token 1 is          %%S
    echo token 2 is          %%T
    echo dequoted token 1 is %%~S
    echo dequoted token 2 is %%~T
    echo drive letter  is    %%~dT
    echo path is             %%~pT
    echo name is             %%~NT
    )

Token.txt

Code: [Select]"ORACLE_HOME"="C:\\oracle\\product\\10.2.0\\client_1"
Code output

Code: [Select]token 1 is          "ORACLE_HOME"
token 2 is          "C:\\oracle\\product\\10.2.0\\client_1"
dequoted token 1 is ORACLE_HOME
dequoted token 2 is C:\\oracle\\product\\10.2.0\\client_1
drive letter  is    C:
path is             \oracle\product\10.2.0\
name is             client_1

Well, actually, client_1 is the  lowest folder in the path name, but that's not a huge ISSUE.

I guess EITHER way would work. But I was slogging through this without any help to speak of, and that's what I came up with. Quote from: kscarroll54 on November 14, 2008, 12:07:35 PM

Well, actually, client_1 is the  lowest folder in the path name, but that's not a huge issue.

It is the folder name, the last element in the full path, and is extracted using the ~n variable modifier, which is called the "name" modifier in the FOR documentation.


Discussion

No Comment Found