1

The code fragment below in a batch file works perfectly fine, but doesn't work when there are ampersands in the string variable, which unfortunately will happen in the project I'm working on. Is there a way to rewrite these two statements so that the ampersands don't hijack the execution of the statements?

My apologies if the "purpose" of this isn't apparent; I would have to paste an overwhelming number of lines to make it truly apparent what I'm trying to do. I'm hoping people can focus on the micro level of these lines rather than letting the apparent lack of "big picture" get in the way.

Other than this batch file, there is a file called file.txt that has just one line in it: /Here and There/Over & Yonder/This & That. Here is the batch file code:

setlocal enabledelayedexpansion

set "FolderName=This & That"
set "ChosenFolder=Here & There/Over & Yonder/This & That"
set "NewFolder=Yin & Yang/Up & Down"

:: Ideally the following problematic line would change the value of %ChosenFolder% to 'Here & There/Over & Yonder', but the ampersands make it fail
For /f "delims=" %%a in ("/!FolderName!") do set "ChosenFolder=!ChosenFolder:%%a=!"
set /a count=0
:: The next problematic line should search file.txt for a string that matches "/Here & There/Over & Yonder" and count the number of matches, but the ampersands make it fail
for /f "delims=" %%a in ('findstr /i /n /c:"/!ChosenFolder!" file.txt" ^| find /c /v ""') do set "count=%%a">nul
:: And finally this problematic line is supposed to actually replace the string with "Yin & Yang/Up & Down"
if %count% gtr 0 type file.txt"|jrepl "/!ChosenFolder!" "/!NewFolder!" /l >temp.txt

echo.
echo FolderName:  %FolderName%
echo ChosenFolder:  %ChosenFolder%  - should be "Here & There/Over & Yonder"
echo NewFolder:  %NewFolder% - should be "Yin & Yang/Up & Down"
echo.
echo file.txt should display "Yin & Yang/Up & Down"
type file.txt
echo.

This is not something solvable by simply escaping various characters. The strings themselves must be "Yin & Yang" etc., not Yin && Yang, Yin ^& Yang, etc. as they will be used for filenames, titles of pages, etc., and the escaping characters themselves would end up displaying. I've seen really tricky solutions to this type of thing before like putting call in front of statements, wrapping statements in parentheses, or, as I try to do below, sticking them in for loops... I just haven't been able to crack it myself.

This uses jrepl.bat, which can be found here. As a side note, I'm happy to consider alternatives for text file search/replace that don't require me to put my eggs in some .exe command line utility that might not be supported in Windows 12 or Windows 13, such as a wonderful "srch.exe" file that I used like 20 years ago but no longer works today.

fortissimo
  • 51
  • 8
  • Maybe you don't want to use delayed expansion. – konsolebox Jan 15 '23 at 21:40
  • I tried replacing the `!` symbols with `%`, but that didn't work either - same result. When there are `&` symbols in filenames, code execution interprets the `&` as a way to execute an additional command even though it's all part of the same command. – fortissimo Jan 15 '23 at 23:27
  • The snippet is insufficient for us to reproduce your problem. Ideally we need to be able to see everything up to and including that snippet. Can you please [Edit] your question, to include a [mcve] for us to work with. – Compo Jan 16 '23 at 00:59
  • From what is see in your incomplete code, and from the body text you included, I'm not sure why you even need a `for` loop, or in fact need to number or count the matching lines. This is because you just need to determine one match, and should be able to do that like this: ```%SystemRoot%\System32\findstr.exe /MLIC:"!OldChosenFolder!/!OldFolderName!" "..\source\!ChosenFolder!\!FolderName!\index.txt" 2>NUL 1>&2 && type "..\source\!ChosenFolder!\!FolderName!\index.txt" | P:\athTo\jrepl.bat "!OldChosenFolderLinux!/!OldFolderName!" "!OldChosenFolderLinux!/!NewFolderName!" /l 1>"temp.txt"``` – Compo Jan 16 '23 at 01:31
  • Does this answer your question? [Batch character escaping](https://stackoverflow.com/questions/6828751/batch-character-escaping) – Ken White Jan 16 '23 at 01:35
  • @KenWhite Thanks but I was already aware of character escaping. Putting carats or double-ampersands inside the strings would make the strings themselves messed up (like a visitor of the website will actually see "Cats && Dogs" as a page name or whatever). I will edit my question soon with simpler code as requested. – fortissimo Jan 16 '23 at 07:35
  • @Compo OK I just updated the code with something people can copy and paste into their own batch file (and create their own file.txt too). I think the edited question should also answer the issue you raised about why I use the `for` loop. – fortissimo Jan 16 '23 at 08:00
  • Surely you would know when you want to use a string with certain special characters, you need to double quote the string or escape the characters. When the string can be anything, then double quoting is the best option. i.e `set "test=X & Y problem"` and `for %%i in ("%test%") do echo %%~i`. standalone variables will need to be either auto escaped, i.e `set "test=%test:&=^&%" & echo %test%` or double quote the variable `echo "%test%"`. one or two minor tweaks and I made your code work. – Gerhard Jan 16 '23 at 08:24
  • PS! You missed a double quote in the `findstr` line, before `file.txt` it should be `for /f "delims=" %%a in ('findstr /i /n /c:"/!ChosenFolder!" "file.txt" ^| find /c /v ""') do set "count=%%a"` – Gerhard Jan 16 '23 at 08:34
  • @fortissimo, sorry but you have included nothing which indicates that a `for` loop is required. In addition, as you're specically working mainly with the `FolderName` and `ChosenFolder` variables, you should include the code which defines them. If these come from parsing something else, you should provide that too, so that we can replicate it. – Compo Jan 17 '23 at 11:27
  • @Compo see https://stackoverflow.com/questions/74838121/trying-to-echo-redirect-append-a-variable-value-that-has-and-spaces-in-it-with to understand why this `'for` loop technique is necessary. As for how the variables get their values, I don't believe that how those variables got their values is relevant to my question, namely how do we manipulate these variables _given_ their assigned values. But I can tell you that ChosenFolder and FolderName are obtained via a menu system that I got off of Stack Overflow (has since been deleted by moderators), and NewFolder is obtained via `set /p `. – fortissimo Jan 18 '23 at 19:00
  • @fortissimo, I had already seen your previous questions, when I was trying to get the information I have asked for. It is completely irrelevant to me, and does not prove to me that a `for` loop is required, nor do they help me to understand your thinking. If your variables are being defined elsewhere in the code, then any problematic characters they may contain, if this is your problem, can be handled in other ways. Your question here however, must be reproducible from the information in your question, not by visiting your previous posts or any reference material you've used, (if not deleted). – Compo Jan 18 '23 at 19:20

1 Answers1

1

I am not sure what your intended results should be, because you claim what file.txt contains, yet you never replace anything in file.txt instead, you redirect the output to temp.txt.

Regardless, here is an example of your code working:

@echo off
setlocal enabledelayedexpansion

set "FolderName=This & That"
set "ChosenFolder=Here & There/Over & Yonder/This & That"
set "NewFolder=Yin & Yang/Up & Down"

For /f "delims=" %%a in ("/!FolderName!") do set "ChosenFolder=!ChosenFolder:%%a=!"

set /a count=0

for /f "delims=" %%a in ('findstr /i /n /c:"/!ChosenFolder!" "file.txt" ^| find /c /v ""') do set "count=%%a"

if %count% gtr 0 type "file.txt"|"jrepl.bat" "/!ChosenFolder!" "/!NewFolder!" /l > temp.txt

echo(
echo FolderName:  "%FolderName%"
echo ChosenFolder:  "%ChosenFolder%"  - should be "Here & There/Over & Yonder"
echo NewFolder: "%NewFolder%" - should be "Yin & Yang/Up & Down"
echo(
echo file.txt should display "This & That"
type file.txt
echo temp.txt should display "/Yin & Yang/Up & Down/This & That"
type temp.txt
echo.
Gerhard
  • 22,678
  • 7
  • 27
  • 43