Search code examples
listbatch-filenested-loops

batch file: working with list elements in nested loop


I've been trying to get following batch script working, looks like I need to ask someone with more expertise in Batch, as I don't have any clue, why it keeps not working. My intention is to get two elements of the list VAR gets swapped:

    @echo off

    rem enable delayed expansion, required for extended usage of environment variables
    SETLOCAL EnableDelayedExpansion
    SETLOCAL EnableExtensions

    set VAR=abcd efgh ijkl mnopq rstvw qwert yxcva rtzewrw yxvys
    set fst=qwert
    set scnd=rstvw

    call :test %VAR%

    :test
    SETLOCAL

    for %%i in (%*) do (
        for %%j in (%* %%i) do (
            if %scnd% equ %%i (
                if %fst% equ %%j (
                echo "gotcha before swapping: " "i: " %%i "j: " %%j
                    set tempor=%%i
                    set i=%%j
                    set j=!tempor!
                    echo "gotcha after swapping: " "i: " !i! "j: " !j!          
                    set List=!List! %%j %%i
                )
            )
        )
        set List=!List! %%i
        echo "List: " !List!
    )

    ENDLOCAL
    goto :eof

    :ende

I am trying to get the List to look like this:

abcd efgh ijkl mnopq qwert rstvw yxcva rtzewrw yxvys 

where the fst (for first element) and scnd (second element) get swapped.

The output is like this: "List: " abcd efgh ijkl mnopq qwert rstvw rstvw qwert yxcva rtzewrw yxvys, so I get double entry of qwert and rstvw, and I know it is because of the position of set List=!List! %%i.

At least I know, the swapping is working. But my problem is: if I put this in the else branch, as I would normally do in any other script language, the List will be filled with %%i and %%j in every loop, so it becomes useless....


Solution

  • Your problem appears to be that %%i and %i% are entirely different variables. You cannot assign values to %%i - only the for command can.

    You appear to be attempting to perform an insertion-sort to build a sorted list of strings. Your code-structure may be a legacy of edits to present the problem, but as posted, the routine will be re-entered by flow-through. Also, since the routine :test is enclosed in a setlocal/endlocal bracket, changes to list will not be visible outside of the :test routine. And having two setlocal commands in succession establishes two nested local environments. Both of the options can be specified simultaneously in one setlocal statement. Note that setlocal is not a switch - it establishes a local environment (and yes, microsoft has been asked to establish delayed expansion and the like as separate swtich-type operations like echo on/off)

    Also note that your generated list contains a leading space. I've followed that idea with the following substitute routine:

    REM

    SET "list2="
    for %%i in (%*) do (
     REM %%i has each element in turn
     SET "startlist= "
     SET "endlist= "
     IF defined list2 for %%j in (!list2!) do (
      IF "%%j" lss "%%i" (
       SET "startlist=!startlist!%%j "
      ) ELSE (
       SET "endlist=!endlist!%%j "
      )
     )
     SET "list2=!startlist!%%i!endlist:~0,-1!"
    )
    ECHO "List2:" %list2%+
    

    (I've added a + to the end to show the end of the string list2.


    Yes - specifying the required output in the original question makes the problem easy to solve

    :test
    SETLOCAL
    SET "List="
    for %%i in (%*) do (
     if %fst% equ %%i ( SET "List=!List! %scnd%"
     ) ELSE (
      if %scnd% equ %%i ( SET "List=!List! %fst%"
      ) ELSE set List=!List! %%i
     )
     echo "List: " !List!
    )
    ENDLOCAL
    goto :eof
    

    I'm assuming for lack of information otherwise that it's guaranteed that fst and scnd are both guaranteed to appear exactly once in the input.