0

I am trying to make a batch file, that will:

  1. Ask for a directory (where many files are contained)

  2. Ask for a second directory (this is the location where the batch will create directories for each file, and then copy each file to its own directory)

  3. Number of characters to remove from the right hand side of the created directory. (Eg, two documents 'NewDoc_Ver1' and 'NewDoc_Ver2', would both be copied into the same directory 'NewDoc').

Below are some similar questions that might help.

https://superuser.com/questions/1138283/batch-script-for-moving-files-to-the-same-name-folder

How do you get the string length in a batch file?

batch files calling %~1 and getting the variable's current value/string

https://ss64.com/nt/syntax-substring.html

I am currently stuck on trying to get the 'String Left' to work with a dynamic number. (I haven't looked at how to put in a user input yet) Any help would be great.

@echo off
setlocal enabledelayedexpansion
set folderpath=C:\Users\james.shaw\Desktop\R2
for %%f in (%folderpath%\*.*) do (
  set "foldername=%%~nf"
  set f1=!foldername!
  call :strlen folderlength foldername
REM set JS1=%%foldername:~0,!folderlength!%%
set JS1=!f1!:~0,!folderlength!
  md !JS1!
REM md "!foldername:~0,!folderlength!!" >nul 2>&1
  move "%%f" "!foldername:~0,!folderlength!!"
pause
)
goto :eof

:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    set "s=!%~2!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" ( 
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
( 
    endlocal
    set "%~1=%len%"
    exit /b
)

Update:

below is a batch I have found that is similar to what I am looking for (I have lost the web URL), however this only runs within the same directory that the batch file does, and doesn't allow for truncating the created directories: I am still interested in learning what I was doing wrong in my original attempt.

@echo off
setlocal EnableDelayedExpansion

set RemoveStrings="[ www.AnnoyingSpam.com ]",
Rem     RemoveStrings     variable notes:
Rem     Surround strings to remove with double quotes.
Rem     Separate each separate string to remove with a comma.

goto :main

: trim_leading_spaces VariableName
setlocal EnableDelayedExpansion
    set "_=!%~1!"
    set _=%_:"=%
: trim_leading_spaces__while
    if "%_:~0,1%"==" " ( set "_=%_:~1%"& goto :trim_leading_spaces__while)
endlocal & set "%~1=%_%"
goto :eof

: trim_trailing_spaces VariableName
setlocal EnableDelayedExpansion
    set "_=!%~1!"
    set _=%_:"=%
: trim_trailing_spaces__while
    if "%_:~-1%"==" " ( set "_=%_:~0,-1%"& goto :trim_trailing_spaces__while)
endlocal & set "%~1=%_%"
goto :eof

: main
for /f "delims=" %%I in (     dir /b /a:-d ^| findstr /vixc:"%~nx0"     ) do (
    Set file = "%%~I"
    for %%J in (%REMOVESTRINGS%) do set "file=!FILE:%%~J=!"
    call :trim_leading_spaces  file
    call :trim_trailing_spaces file
    for %%J in ("!FILE!") do set "NewDirName=%%~nJ"
    md "!NEWDIRNAME!"
    ren "%%~I" "!FILE!"
    move "!FILE!" "!NEWDIRNAME!"
)
James
  • 123
  • 9
  • 1
    Show examples of you input files and expected output, this script seems like a bit of an overkill. – Gerhard May 18 '18 at 09:33

2 Answers2

1

Judging by you examples:

NewDoc_Ver1
NewDoc_Ver2

It seems that you might have a common delimiter, being _

If that is infact the case and you merely want the first word, before _ as a folder name, then this might help.

@echo off
setlocal enabledelayedexpansion
cls
:input
set /p "input=1. Enter Source directory: "
if not exist "%input%" echo Invalid source: "%input%" enter valid path && goto :input 
:output
set /p "output=2. Select Destination Directory: "
if not exist "%output%" echo Invalid Dest: "%output%" enter valid path && goto :output

for %%i in (%input%\*) do (
 set "file=%%~nxi"
 for /f "delims=_" %%a in ("!file!") do (
 set "folder=%%a"
 if not exist "!output!\!folder!" mkdir "!output!\!folder!"
  copy /Y "!input!\!file!" "!output!\!folder!" >nul
  echo Copied "!input!\!file!" to "!output!\!folder!\!file!"
  )
)

Explanation:

This prompts user for a source directory. If directory does not exist, it will re-prompt for it, if it does exist, it will prompt for destination directory, if destination path is not valid, echo it and re-prompt for it.

Next, we take each file and assign it to a variable name %file% or rather in this enabledelayedexpansioncase !file! then for each file name, we split it by _ and assign the first part of the name to !folder!. Now we simply check if the folder exists in the previously user given destination, if not, create it, then copy each file in the source to the matching destination directory where the new folders are created.

If your file layout is not as per your examples, please provide me with proper examples and I will amend my answer.

Gerhard
  • 22,678
  • 7
  • 27
  • 43
  • I would suggest that you change all instances of `!output!` and `!input!` in your `for` loop to `%output%` and `%input%` respectively. _This will hopefully allow those who struggle understanding delayed expansion to see that only the variables which are set within the loop require it._ – Compo May 18 '18 at 12:49
1

Here's an example script for you to work with:

@Echo Off
SetLocal EnableDelayedExpansion
Set /P "dirSrc=Enter full path of your files source directory: "
Set /P "dirDst=Enter the full path to hold your destination directories: "
Set /P "numEnd=Enter the number of characters to right trim the filenames by: "
For %%A In ("%dirSrc%\*") Do (Set "fileNm=%%~nA"
    If "%numEnd%"=="0" (XCopy "%%A" "%dirDst%\%%~nA\" 2>Nul
    ) Else XCopy "%%A" "%dirDst%\!fileNm:~,-%numEnd%!\" 2>Nul)

This should work fine as long as the input data is correct.

I expect you to implement those checks and verify the input data, (your end user can enter anything they wish).

Compo
  • 36,585
  • 5
  • 27
  • 39
  • 1
    @JimmyWilliams, well not only does that almost defeat the exercise, it is also something I expected you to cater for yourself as part of your input data checks! I have nonetheless updated my code to cater for that scenario. – Compo May 21 '18 at 04:28