Search code examples
stringpowershellbatch-filebatch-processing

Windows batch script to replace some strings if another string is present in the line


I'm new to the batch editing in Windows, and I'm getting very confused by the impossibility to use PowerShell commands inside my bat file.

Long story short I have this input file:

The quick brown fox jumped over the lazy white dog
The quick red fox jumped over the lazy dog
The quick green wolf jumped over the lazy brown dog
The quick brown fox jumped over the lazy dog
The quick red lion jumped over the lazy dog
The quick green pig jumped over the lazy brown dog
The quick brown fox jumped over the lazy dog

I would like to substitute brown with white, if the sentence is containing the term fox.

As an extra requirement, I would like to replace brown only if it's the first occurrence.

I tried to work with .contains and with find, but still it all get's messy when I try to use the outcome of the if condition.

The best I managed to put together was this; but it's still crap.

@echo on &setlocal
set "search=brown"
set "replace=white"
set "textfile=C:\JavaLogs\ReplaceDemo.txt"
set "newfile=C:\JavaLogs\Output.txt"
set lines=0
(
for /f "delims=" %%i in (%textfile%) do (
    set lines=echo %%i | findstr /C:"fox" |  measure -w -c -l
    echo %lines%
    if "%lines%">"0" echo "There is a fox"
    if "%lines%"=="0" echo "There is no fox"
    set %%i=%%i:%search%=%replace% echo(%%i>%newfile%)  

    else echo(!%%i!)>"%newfile%"
    ) 
)

The final resut would be an output file like this:

The quick white fox jumped over the lazy white dog
The quick red fox jumped over the lazy dog
The quick green wolf jumped over the lazy brown dog
The quick white fox jumped over the lazy dog
The quick red lion jumped over the lazy dog
The quick green pig jumped over the lazy brown dog
The quick white fox jumped over the lazy dog

Solution

  • @ECHO OFF
    SETLOCAL ENABLEDELAYEDEXPANSION
    rem The following settings for the directories and filenames are names
    rem that I use for testing and deliberately includes spaces to make sure
    rem that the process works using such names. These will need to be changed to suit your situation.
    
    SET "sourcedir=u:\your files"
    SET "destdir=u:\your results"
    SET "filename1=%sourcedir%\q77026292.txt"
    SET "outfile=%destdir%\outfile.txt"
    
    SET "prerequisite=fox"
    SET "replace=brown"
    SET "replacement=white"
    
    (
    FOR /f "usebackqdelims=" %%e IN ("%filename1%") DO (
     rem line is in %%e
     SET "foundpre="
     FOR %%o IN (%%e) DO IF "%%o"=="%prerequisite%" SET "foundpre=y"
     IF DEFINED foundpre (
      SET "outline="
      SET "replace1=y"
      FOR %%o IN (%%e) DO IF DEFINED replace1 (
       IF "%%o"=="%replace%" (
        SET "replace1="
        SET "outline=!outline! %replacement%"
       ) ELSE SET "outline=!outline! %%o"
      ) ELSE SET "outline=!outline! %%o"
      ECHO !outline:~1!
     ) ELSE ECHO %%e
    )
    )>"%outfile%"
    
    GOTO :EOF
    

    Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around %filename1% can be omitted.

    Note the use of delayedexpansion Stephan's DELAYEDEXPANSION link as the value of outline is changing in the for %%e loop, and of Boolean variables which are interpreted on their run-time state.

    Revision in the light of comments ----

    @ECHO Off
    SETLOCAL ENABLEDELAYEDEXPANSION
    rem The following settings for the directories and filenames are names
    rem that I use for testing and deliberately includes spaces to make sure
    rem that the process works using such names. These will need to be changed to suit your situation.
    
    SET "sourcedir=u:\your files"
    SET "destdir=u:\your results"
    SET "filename1=%sourcedir%\q77026292.txt"
    SET "outfile=%destdir%\outfile.txt"
    
    SET "prerequisite=fox"
    SET "replace=brown"
    SET "replacement=white"
    
    (
    FOR /f "usebackqdelims=" %%e IN ("%filename1%") DO (
     rem line is in %%e
     SET "foundpre="
     SET "line=%%e"
     SET "line=!line:|=" "!"
     FOR %%o IN ("!line!") DO IF "%%~o"=="%prerequisite%" SET "foundpre=y"
     
     IF DEFINED foundpre (
      SET "outline="
      SET "replace1=y"
      FOR %%o IN ("!line!") DO IF DEFINED replace1 (
       IF "%%~o"=="%replace%" (
        SET "replace1="
        SET "outline=!outline! "%replacement%""
       ) ELSE SET "outline=!outline! %%o"
      ) ELSE SET "outline=!outline! %%o"
    SET "outline=!outline:~2,-1!"
      ECHO !outline:" "=^|!
     ) ELSE ECHO %%e
    )
    )>"%outfile%"
    
    TYPE "%outfile%"
    
    GOTO :EOF
    

    The original code used the characteristic of the for command that it assigns each of the space-separated items in the list in turn to the metavariable.

    With | as the item-separator, we need to massage the line a little.

    line would be initially set to (eg)

    The quick|brown|fox|jumped|over|the|lazy|brown|unicorn
    

    so the SET "line=!line:|=" "!" changes replaces each | with " ", so changes this to

    The quick" "brown" "fox" "jumped" "over" "the" "lazy" "brown" "unicorn
    

    and then FOR %%o IN ("!line!")... processes

    "The quick" "brown" "fox" "jumped" "over" "the" "lazy" "brown" "unicorn"
    

    and assigns each quoted substring in turn to %%o.

    It's then a matter of replacing %%o with %%~o to strip the enclosing quotes from %%o when appropriate. (Yes - "%%~o" is the same as %%o if we know (as we do here) that %%o is quoted)

    and then reversing the transformation to replace " " with | - the | needs to be escaped with ^ here.