0

Based on this stackhowto, https://stackhowto.com/batch-file-to-list-folder-names/ , I tried to write a batch script that goes through all subfolders of a folder and renames .txt files based on the original folder name. However, I can't seem to actually store the name of the original folder and pass it along to rename the files, even though I can print them out directly just fine using echo %%~nxD. My dummy folder structure looks like this:

Folder
   subfolder
       subsubfolder
           test.txt

Where my batch script sits in the Folder.

The script I tried to use is pasted below. It is supposed to run from within the Folder, go into each subfolder, save that subfolders name, then go into each subfolder within that subfolder, and rename any text files that contain the pattern by adding the subfoldername before the pattern in the filename.

However, the subfolder name is not properly saved, instead, what is returned from the echo %replace% is an empty string, and that is what the test.txt file will be renamed to: ".txt".

If I just type

echo %%~nxD

the folder name gets printed out correctly as expected, so it's the saving that isn't working

If I just add

set "replace=thisworksfine_%pattern%"

right at the beginning of this script after set "pattern=test", then the file will be renamed into "thisworksfine_test.txt" as expected, so normal saving of a parameters works fine.

So clearly I am not understanding how one can save a variable in such a manner using these loops through folders.

Any help would be greatly appreciated!

setlocal enabledelayedexpansion
@echo off

set "pattern=test"
for /d %%D in (*) do (
    cd %%~nxD
    set "replace=%%~nxD_%pattern%"
    echo %replace%
    for /d %%D in (*) do (
        cd %%~nxD
        for %%I in (*.txt) do (
            set "file=%%~I"
                ren "%%I" "!file:%pattern%=%replace%!"  
        )   
    )
    cd ..
)
cd ..
Compo
  • 36,585
  • 5
  • 27
  • 39
FwFranz
  • 11
  • 3
  • This looks like you're writing a batch script, not bash. They have similar names, but very different syntax. I'd recommend correcting your description and the tags on this question. – Gordon Davisson Dec 06 '22 at 19:44
  • Beware of the [delayed expansion trap](https://stackoverflow.com/a/30284028/2128947) Since `replace` is undefined at the start of the `outer `for/D`, %replace% will be *nothing* throughout the code block. You are attempting to use `for...%%D` within `for...%%D` - how is `cmd` supposed to determine which `%%D` you mean? Change one of them. Prefer to avoid ADFNPSTXZ (in either case) as metavariables (loop-control variables) as ADFNPSTXZ are metavariable-modifiers which can lead to difficult-to-find bugs (See `for/f` from the prompt for documentation) – Magoo Dec 06 '22 at 20:30
  • You should have noticed that `echo %replace%` doesn't work, outputting `ECHO IS OFF`, because that should read as `echo !replace!`. The next issue with your code is once again because `%replace%` is used without delaying it. However, you cannot just change that to `!replace!` because it is nested within another delayed variable. You will therefore need to introduce another layer of delayed expansion, or find an alternative way without it. – Compo Dec 06 '22 at 20:31
  • Since the dynamic value of `replace` is `%%~nxD_%pattern%`, then use `%%~nxD_%pattern%` in place of `%replace%` in you string-substitution command. – Magoo Dec 06 '22 at 20:32
  • @Magoo this "works" in the sense that it renames the file, but it will rename to the foldername at that level (in my example subsubfolder), where I wanted to rename it to the subfolder one level up (subfolder), and in later versions I want it 2 or 3 levels up – FwFranz Dec 06 '22 at 21:15
  • In that case, show examples in your question. You could also use `for %%s in ("%%~nxD_%pattern%") do` or `for %%s in ("%%~nxD_!pattern!") do` and use `%%~s` in place of `%replace%` in the string-substitution. (naturally, the substitution must be made in the context of the `for...%%s`) – Magoo Dec 06 '22 at 21:24

1 Answers1

1

Thank you everyone, with those comments I got it to work, here is the (probably dirty by your standards) solution:

Basically use !! instead of %% to avoid delayed expansion, while also redefining the replace string at each level, and then using rename in the end instead of ren because that didn't seem to work with !replace3! inside of the argument.

setlocal enabledelayedexpansion
@echo off

set "pattern=test.txt"
for /d %%D in (*) do (
    cd %%~nxD
    set "replace=%%~nxD_%pattern%"
    for /d %%D in (*) do (      
        set "replace2=!replace!"
        cd %%~nxD
        for %%I in (*.txt) do (
            set "file=%%~I"
            set "replace3=!replace2!"
            echo !replace3!
                rename %pattern% !replace3! 
        )   
    )
    cd ..
)
cd ..
FwFranz
  • 11
  • 3