I have some files in the form:
filename1 1.ext
filename1 2.ext
filename1 3.ext
...
filename2 1.ext
filename2 100.ext
...
filename20 1.ext
filename20 15.ext
(etc.)
...where filename can contain spaces.
And I want to move them to folder filename1, filename2, etc., respectively.
I know I can do a for loop for %%i in (*.ext) do and remove the extension with set folder=%%~ni. So what I am missing is how to remove everything after the space just before the number, and get only filename1, for example.
I also know I can split variable folder, but in this case I do not know by at which character I need to split, although I know it will be a space followed by a number.
So basically, I want something like this:
#echo off
set folder=
for %%i in (*.ext) do set folder=%%~ni & set folder=getfoldernamefromvariablefoldersomehow & mv %%i %folder%
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*.ext" '
) DO (
CALL :sub1 "%%a" %%a
)
GOTO :EOF
:sub1
SET "filename=%~1"
:subloop
SHIFT
SET "numname=%~1"
IF NOT "%~2"=="" GOTO subloop
CALL SET "dirname=%%filename: %numname%=%%
ECHO( MD "%sourcedir%\%dirname%" 2>nul
ECHO( MOVE "%sourcedir%\%filename%" "%sourcedir%\%dirname%\%numname%"
GOTO :eof
You would need to change the setting of sourcedir to suit your circumstances.
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories.
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
Perform a directory list of the required files in basic form without directorynames. Send the full fulename in quotes and without to the subroutine sub1.
In the subroutine, save the source filename in filename then shift each parameter supplied until there is no second parameter; the value in numname must then be the last or required filename.
Remove numname with a leading space from filename to get the required subdirectoryname, make that subdirectory and move the file.
[edit in the light of comment]
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*.ext" '
) DO (
CALL :sub1 "%%a" %%a
)
GOTO :EOF
:sub1
SET "filename=%~1"
SET "destdirname=%~2"
:subloop
SHIFT
SET "numname=%~1"
IF NOT "%~2"=="" GOTO subloop
CALL SET "dirname=%%filename: %numname%=%%
ECHO( MD "%sourcedir%\%destdirname%" 2>nul
ECHO( MOVE "%sourcedir%\%filename%" "%sourcedir%\%destdirname%\%numname%"
GOTO :eof
It's difficult to scry your intentions when you give no example.
destdirname is set to the second parameter on entering sub1 which will be the first group of characters before the first space.
the md does not need to be gated since the 2>nul will suppress the directory exists error message.
Here is a script that does what you want. It splits off the last SPACE followed by numerals from the file name and uses the remaining string as the name of the destination directory of the movement.
This approach handles all valid characters for file names properly, even ^, &, %, !, ( and ). It can even handle file names that contain SPACE plus numerals plus .ext again correctly.
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."
for /F "eol=| delims=" %%F in ('
dir /B "%_SOURCE%\*.ext" ^| findstr /R /I /C:" [0123456789][0123456789]*\.ext$"
') do (
set "FILE=%%F"
call :SPLIT LAST REST "%%F"
setlocal EnableDelayedExpansion
2> nul mkdir "!_TARGET!\!REST!"
ECHO move /Y "!_SOURCE!\!FILE!" "!_TARGET!\!REST!"
endlocal
)
endlocal
exit /B
:SPLIT rtn_last rtn_rest val_string
setlocal DisableDelayedExpansion
set "RES=" & set "STR=%~3"
:LOOP
for /F "tokens=1,* delims= " %%I in ("%STR%") do (
if "%%J"=="" (
set "RES=%%I"
) else (
set "STR=%%J"
goto :LOOP
)
)
set "STR=%~3|"
call set "STR=%%STR: %RES%|=%%"
(
endlocal
set "%~1=%RES%"
set "%~2=%STR:^^=^%"
)
exit /B
After having tested the script, remove the upper-case ECHO command to actually move any files. Unless you remove the /Y option from the move command, files become overwritten without prompt. To suppress summary messages (like 1 file(s) moved.), add > nul to the move command line. Note that any prompt was also hidden then in case you removed the /Y option.
Thank to all of you for your comments. Finally, i was able to get a solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "_source=C:\Users\kurok_000\Downloads"
set "_target=C:\Users\kurok_000\YandexDisk\Mangas"
for /f "eol=| delims=" %%f in ('dir /b "%_source%\*.7z"') do (
call :fixNames "%%f" %_source%
)
for /f "eol=| delims=" %%f in ('dir /b "%_source%\*.7z" ^| findstr /r /i /c:" [0123456789][0123456789]*\.7z$"') do (
set "file=%%f"
call :split last rest "%%f"
setlocal EnableDelayedExpansion
2> nul mkdir "!_target!\!rest!"
move /y "!_source!\!file!" "!_target!\!rest!" >nul
echo moved %%f to !_target!\!rest!
endlocal
)
endlocal
exit /b
:split rtn_last rtn_rest val_string
setlocal DisableDelayedExpansion
set "res=" & set "str=%~3"
:loop
for /f "tokens=1,* delims= " %%i in ("%str%") do (
if "%%j"=="" (
set "res=%%i"
) else (
set "str=%%j"
goto :loop
)
)
:quit
set "str=%~3|"
call set "str=%%str: %res%|=%%"
(
endlocal
set "%~1=%res%"
set "%~2=%str:^^=^%"
)
exit /b
:fixNames _file _folder
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FILE=%1"
set "FILE=%file:~1,-1%"
set "folder=%2"
for /F "tokens=1,* delims=0123456789" %%A in ("%FILE%") do (
set filename=!FILE:%%B=!%%~xB
)
if not "%filename%"=="%FILE%" (rename "!folder!\!FILE!" "!filename!")
Related
Apologies for my poorly worded question and my scatterbrain workings. Essentially I want to set an unknown number of variables that are parsed from each line of a text file.
I have written batch file to create symbolic links for network shares to a C:\Volumes folder.
#echo off
echo:
set /p dest=ENTER FOLDER PATH:
set dest="%dest%"
net use %dest%
if not exist "C:\Volumes" MD "C:\Volumes"
for %%i in (%dest%) do (set "fold=%%~ni")
mklink /d "c:\VOLUMES\%fold%" "%dest%"
pause
What I want to try is the same theory but have the script point at a text file mounts.txt with a list of folder paths and for a for loop to cycle through the list make a symbolic link for each path in the list. I have toyed with counters and cannot get it working correctly. I don't think I am going about it the right way at all.
Contents of mounts.txt
\\10.19.10.238\Masters\Removed bin\Work here
\\10.19.10.241\Scanning\WIP\to process
This does not work:
#echo off
setlocal enableDelayedExpansion
set i=1
:add
Set /a "i+=1"
for /F "tokens=*" %%A in (mounts.txt) do (set dest%i%=%%A)
if exist %dest%%i% goto:add
echo %dest%
echo %dest%%i%
echo !dest!
echo !dest!%i%
pause
Nor this:
#echo off
setlocal enableDelayedExpansion
set i=0
For /F "Tokens=1* Delims=] EOL=" %%A In ('Find /N /V ""^<"mounts.txt"') Do (
set /a i=i+1
set "dest!i!=%%B"
)
For /l %%a in (1,1,4) do echo _dest%%a is !dest%%a!
For /l %%a in (1,1,4) do set dest%%a=!dest%%a!
echo !dest!
pause
I did get something like this to work to an extent but cannot figure out how to use the dest[1], dest[2] as variables in other processes further down in the script.
#echo off
setlocal enabledelayedexpansion
set counter=0
for /f "tokens=*" %%a In (mounts.txt) do (
set /a counter+=1
set "dest[!counter!]=%%a"
)
set dest[
And the list could be added to with many more. If %dest%n variables can be set, the use the same theory to set different %fold% variables based on each %dest%n then maybe the links can be set using the same process as the original script.
Any help is appreciated. Thank you.
If your question actually describes what you want to do, you don't need to set variables. Just use the lines from the text file with a for /f loop:
for /f "delims=" %%i in (mount.txt) do mklink /d "C:\VOLUMES\%%~ni" "%%i"
It's safer to quote the filename, especially if you want/need to use the FQFN. Therefore you need the usebackq option, else a quoted string will be processed as a string, not a filename:
for /f "usebackq delims=" %%i in ("C:\full path\mount.txt") do mklink /d "C:\VOLUMES\%%~ni" "%%i"
You seemingly want to dynamically set the variables as dummy array's and return results based on the line numbers. If so, use the counter you created to become the max of the for /L loop, here is an example by just echoing the results:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,!cnt!) do echo !var[%%a]!
Edit
As highlighted by #Compo in the comments; after the initial code block where we increment the %cnt% variable, we no longer require using delayedexpansion on the %cnt% variable specifically and can therefore use %cnt% instead of !cnt!:
#echo off & set cnt=0
setlocal enabledelayedexpansion
for /F "usebackq delims=" %%i in ("mounts.txt") do (
set /a cnt+=1
set "var[!cnt!]=%%i"
)
for /L %%a in (1,1,%cnt%) do echo !var[%%a]!
This is a courtesy example, just to show you how you could have still used find.exe, as in one of your examples, and additionally includes a different method of iterating the variables with unknown increments:
#Echo Off
SetLocal EnableExtensions
Rem The next line ensures that there are no variables defined with names beginning _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Rem The next lines parse the directory paths content file and defines the incrementing variables
For /F "Tokens=1,* Delims=]" %%G In (
'"%SystemRoot%\System32\find.exe /N "\" 0< "C:\Users\roar\My Directory\mounts.txt" 2>NUL"'
) Do (
Set "_Path%%G]=%%H"
Set "_Name%%G]=%%~nxH"
)
Rem The next lines iterate the defined variables beginning _Path[ and runs commands against them
For /F "Tokens=2 Delims=[]" %%G In ('"(Set _Path[) 2>NUL"') Do (
SetLocal EnableDelayedExpansion
MkLink /D "C:\Volumes\!_Name[%%G]!" "!_Path[%%G]!"
EndLocal
)
Rem The next line undefines any previously defined variables named beginning with _
For /F "Delims==" %%G In ('"(Set _) 2>NUL"') Do Set "%%G="
Please note that is likely you may need to run this script elevated, in order for the MkLink command to create the symbolic links.
i have loads of files which i want to organize differently. The batch script should create folders with the substring on the left side of the date in the filename.
Files are now named like this:
This_is_my_file_21.01.29_22-00_abc_115.avi
This_is_my_file_20.09.29_21-10_abc_15.avi
This_is_another_file_21.01.29_22-00_abc_55.avi
Pattern:
<Name with unknown number of underscores>_<YY.MM.DD>_<hh-mm>_<string with unknown length>_<number n from 1-999>.avi
Folders should be named like this:
This_is_my_file <- two files will go into this directory
This_is_another_file <- only one file.
The Problem is, how do I get the correct substring for my folder name?
This is what I have so far:
#echo off
setlocal
set "basename=."
for /F "tokens=1* delims=." %%a in ('dir *.avi /B /A-D ^| sort /R') do (
set "filename=%%a"
setlocal EnableDelayedExpansion
for /F "delims=" %%c in ("!basename!") do if "!filename:%%c=!" equ "!filename!" (
set "basename=!filename!"
md "!basename:~0,-23!"
)
move "!filename!.%%b" "!basename:~0,-23!"
for /F "delims=" %%c in ("!basename!") do (
endlocal
set "basename=%%c
)
)
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include 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\t w o"
FOR /f "delims=" %%b IN ('dir /b /a-d "%sourcedir%\*.avi" ' ) DO (
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :countus "%%b"
IF DEFINED subdir (
MD "!subdir!" 2>NUL
ECHO MOVE "%sourcedir%\%%b" "%sourcedir%\!subdir!\"
) ELSE (
ECHO Failed pattern check %%b
)
ENDLOCAL
)
GOTO :EOF
:: count number of underscores before pattern YY.MM.DD_hh-mm
:countus
SET /a ucount=0
:countusloop
SET /a ucount+=1
SET /a scount=ucount+1
FOR /f "tokens=%ucount%,%scount%delims=_" %%q IN ("%~1") DO SET "str1=%%q"&SET "str2=%%r"
IF NOT DEFINED str2 SET "subdir="&GOTO :EOF
:: is %str1%.%str2:-=.%. of form np.np.np.np.np where np is a number-pair?
SET "candidate=%str1%.%str2:-=.%."
FOR /L %%c IN (10,1,99) DO IF DEFINED candidate SET "candidate=!candidate:%%c.=!"&IF NOT DEFINED candidate GOTO success
FOR /L %%c IN (0,1,9) DO IF DEFINED candidate SET "candidate=!candidate:0%%c.=!"&IF NOT DEFINED candidate GOTO success
GOTO countusloop
:success
SET "subdir=%~1"
FOR /f "delims=:" %%e IN ("!subdir:_%str1%_%str2%=:!") DO SET "subdir=%%e"
GOTO :eof
The "move" command is merely echoed for verification. Remove the echo from echo move to actually move the files.
This possible solution uses the fact that your filenames have a known number of underscores if you work backwards. All I do is replace those underscores with backslashes, which obviously cannot already be contained in the filename. I can then use the relative paths to step up the filename, as if it were a directory tree, until all I have left is the part ahead of the date sequence, which I then replace the backslashes with underscores again. I use the result of that with robocopy, which has a move option, and will create the destination directory automatically, if it does not already exist. At the outset, I perform the directory search, in the same directory as the batch-file, using where.exe, (you can change that, on line three, from "%~dp0." to ".", if you want to use the current directory instead, or "any other path" as necessary). where.exe not only treats the ? wildcard as exactly one character, (unlike the dir command which is zero or one), but also ignores 8.3 naming. It therefore treats the .avi extension exactly as written, (and not 'beginning with' .avi, which dir, or a standard for loop, would).
Anyhow, feel free to give it a try:
#Echo Off & SetLocal EnableExtensions DisableDelayedExpansion
Set "}=" & For /F Delims^= %%G In ('(Set PATHEXT^=^) ^& %__AppDir__%where.exe
"%~dp0.":"?*_??.??.??_??-??_?*.avi" 2^> NUL') Do (Set "}=%%~nG"
SetLocal EnableDelayedExpansion & For %%H In ("\!}:_=\!") Do (
EndLocal & For %%I In ("%%~pH..\..") Do (Set "}=%%~pI"
SetLocal EnableDelayedExpansion & Set "}=!}:~1,-1!"
For %%J In ("!}:\=_!") Do (EndLocal & %__AppDir__%robocopy.exe ^
"%%~dpG." "%%~dpG%%~J" "%%~nxG" /Mov 1> NUL))))
If you want even further robustness, and do not wish to use a more suitable scripting technology, the following, extremely complex looking, version, is the same code, except that it uses findstr to validate the date and time sequence. It filters those avi files containing the following pattern, _yy.MM.dd_hh-mm_ in the avi filenames, using all dates from the beginning of 1970 up until the end of 2021:
#Echo Off & SetLocal EnableExtensions DisableDelayedExpansion
Set "}=" & For /F Delims^= %%G In ('(Set PATHEXT^=^) ^& %__AppDir__%where.exe
"%~dp0.":"?*_??.??.??_??-??_?*.avi" 2^> NUL ^| %__AppDir__%findstr.exe
/RC:"_[789][0123456789].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].3[01]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].3[01]_2[0123]-[012345][0123456789]_"') Do (Set "}=%%~nG"
SetLocal EnableDelayedExpansion & For %%H In ("\!}:_=\!") Do (
EndLocal & For %%I In ("%%~pH..\..") Do (Set "}=%%~pI"
SetLocal EnableDelayedExpansion & Set "}=!}:~1,-1!"
For %%J In ("!}:\=_!") Do (EndLocal & %__AppDir__%robocopy.exe ^
"%%~dpG." "%%~dpG%%~J" "%%~nxG" /Mov 1> NUL))))
Why does this for loop not work for files with "!" in the filename? And how can I make it recognize files with "!" or other possible symbols that may not work.
#Echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
set my_dir=C:\Test
set my_ext=txt
cd /d !my_dir!
for %%F in ("*.!my_ext!") do (
for /F "tokens=1,* delims=|" %%K in ('
forfiles /M "%%~F" /C "cmd /C echo #path^|#ext"
') do (
echo "%%~K": %%L
set list=!list!%%~K;
)
)
I get a returned message like this, with the ! missing from the output.
ERROR: Files of type "C:\Test\My file name has an explanation point here.txt" not found.
Here's an example of something which may work for you:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "my_dir=C:\Test"
Set "my_ext=txt"
CD /D "%my_dir%" 2> NUL || GoTo :EOF
Set "list="
For %%G In ("*.%my_ext%") Do (Echo "%%~fG"^|%%~xG
If Not Defined list (Set "list=%%~fG") Else (
For /F "Tokens=1*Delims==" %%H In ('Set list'
) Do Set "list=%%I;%%~fG"))
SetLocal EnableDelayedExpansion
Echo(!list!
EndLocal
Pause
If you wanted each of your filepaths to be doublequoted, then a couple of small changes are all you need:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "my_dir=C:\Test"
Set "my_ext=txt"
CD /D "%my_dir%" 2> NUL || GoTo :EOF
Set "list="
For %%G In ("*.%my_ext%") Do (Echo "%%~fG"^|%%~xG
If Not Defined list (Set "list="%%~fG"") Else (
For /F "Tokens=1*Delims==" %%H In ('Set list'
) Do Set "list=%%I;"%%~fG""))
SetLocal EnableDelayedExpansion
Echo(!list!
EndLocal
Pause
It is important to note, especially because you're using full paths for each of them, that there is a limit to the size of a user defined environment variable of 32767 characters. This means that depending upon the number of matching files in %my_dir%, you could exceed that maximum. In both examples, you can obviously remove the Echo "%%~fG"^|%%~xG part, if you didn't really require it.
I write batch script to find contents for file in folder. Contents are in text file and have special characters like exclamation mark.
How do I get FILENAME and FOLDERNAME which contain exclamation mark.
#ECHO off
SETLOCAL EnableDelayedExpansion
set /p SRC="Enter source folder link: "
set /p DST="Enter destination folder link: "
FOR /F "delims=" %%a IN ('DIR /b /s /a-d "%SRC%"') do (
Set "CODE=%%~na"
Set "EXT=%%~xa"
findstr /c:"!CODE!" "%SRC%\Content.txt">nul
IF "!errorlevel!" EQU "0" (
for /F "tokens=2,3" %%c in ('findstr /c:"!CODE!" "%SRC%\Content.txt"') do (
ECHO !CODE!
Set "NEWNAME=%%c"
Set "FOLDERNAME=%%d"
Set "NEWNAME=!NEWNAME:_= !"
Set "FOLDERNAME=!FOLDERNAME:_= !"
IF not exist "%DST%\!FOLDERNAME!" md "%DST%\!FOLDERNAME!"
mklink "%DST%\!FOLDERNAME!\!NEWNAME!!EXT!" "%%a"
)
)
)
Endlocal
Exit
PS: Source folder has many files.
One solution is using a subroutine to avoid usage of delayed environment variable expansion:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
:GetSource
set "SRC="
set /P SRC="Enter source folder link: "
if not defined SRC goto GetSource
set "SRC=%SRC:"=%"
if not defined SRC goto GetSource
:GetDestination
set "DST="
set /P DST="Enter destination folder link: "
if not defined DST goto GetDestination
set "DST=%DST:"=%"
if not defined DST goto GetDestination
for /F "eol=| delims=" %%I in ('dir /A-D /B /S "%SRC%" 2^>nul') do (
if exist "%SRC%\Content.txt" for /F "tokens=2,3" %%A in ('%SystemRoot%\System32\findstr.exe /C:"%%~nI" "%SRC%\Content.txt" 2^>nul') do (
set "NEWNAME=%%~A"
set "FOLDERNAME=%%~B"
call :MakeLink "%%I"
)
)
endlocal
exit /B
:MakeLink
echo %~n1
set "NEWNAME=%NEWNAME:_= %"
set "FOLDERNAME=%FOLDERNAME:_= %"
if not exist "%DST%\%FOLDERNAME%" md "%DST%\%FOLDERNAME%"
mklink "%DST%\%FOLDERNAME%\%NEWNAME%%~x1" %1
goto :EOF
Open a command prompt window and run call /? for help explaining how to use the command CALL with enabled command extensions to run a block in same batch file like a subroutine. See also Where does GOTO :EOF return to?
I have not studied your code, but I'd assume that enabling the delayed expansion after setting the variable names would be more appropriate:
#Echo Off
SetLocal DisableDelayedExpansion
Set /P "SRC=Enter source folder link: "
Set /P "DST=Enter destination folder link: "
For /D /R %%A In (*) Do For /F "Tokens=2-3" %%B In (
'FindStr/C:"%%~nxA" "%SRC%\Content.txt" 2^>Nul') Do (Echo %%~nA
Set "NEW=%%B"
Set "FLD=%%C"
SetLocal EnableDelayedExpansion
If Not Exist "%DST%\!FLD:_= !\" MD "%DST%\!FLD:_= !" 2>Nul && (
MkLink "%DST%\!FLD:_= !\!NEW:_= !%%~xA" "%%A")
Endlocal)
Exit /B
I would strongly suggest you perform some proper verification of the user input prior to performing tasks using them, i.e. before the For loop.
I'm attempting to make a script that creates a set of folders from list.txt (a list of file directory names separated by carriage returns), with each folder containing a particular number of subdirectories named by the user.
This script does exactly that and works correctly:
#echo off
setlocal enableextensions
set /P q="How many subdirectories would you like to add in each folder?[0/1/2/3]"
if /I "%q%" EQU "0" goto :somewhere0
if /I "%q%" EQU "1" goto :somewhere1
if /I "%q%" EQU "2" goto :somewhere2
if /I "%q%" EQU "3" goto :somewhere3
if errorlevel 1 goto :problem
:somewhere0
echo All done! Press any key to exit.
pause
exit
...(code cut for brevity)
:somewhere3
set /P c="What is the name of the first subdirectory?"
for /F "tokens=1 delims=," %%d IN (list.txt) DO md "%%c"\"%%d"
set /P c="What is the name of the second subdirectory?"
for /F "tokens=1 delims=," %%d IN (list.txt) DO md "%%c"\"%%d"
set /P c="What is the name of the third subdirectory?"
for /F "tokens=1 delims=," %%d IN (list.txt) DO if not exist %%d md "%%d" cd "%%d" md "%%c" cd ..
if errorlevel 1 goto :problem
goto :somewhere0
...
You get the picture. However, I'm attempting to do this in a loop instead of hard-coding each instance. The code I've developed looks like this:
#echo off
setlocal enableextensions
set "var=string"
set /P q="How many subdirectories would you like to add in each folder?"
for /l %%x in (1, 1, %q%) do (
set /P c="What is the name of subdirectory %%x?"
for /F "tokens=1 delims=," %%d IN (list.txt) DO md "%%d\%c%"
)
Trying to echo the variable %%d or %c% in the middle of the loop doesn't yield anything. Stranger, the script actually creates the top level directories - ie, this code runs
for /F "tokens=1 delims=," %%d IN (list.txt) DO md "%%d
but the subdirectories do not show up. Suggestions?
Note that I don't honestly know why the first working code demands this particular order of % signs, but that is the only way I could get it to work.
enabledelayedexpansion is what you want here.
#echo off
setlocal enableextensions enabledelayedexpansion
set "var=string"
set /P q="How many subdirectories would you like to add in each folder? "
for /l %%x in (1, 1, %q%) do (
set /P c="What is the name of subdirectory %%x? "
for /F "tokens=1 delims=," %%d IN (list.txt) DO md "%%d\!c!"
)
from cmd.exe if you run setlocal /? you will get some more help, but in short, enabledelayedexpansion enables delayed environment variable expansion. It will cause variables within a batch file to be expanded at execution time rather than at parse time. Can also be enabled as CMD /V:ON on commandline, and not in Batch.
You basically tell the command processor to delay the resolution of variables until it executes them. % is substituded with ! to show which variables are to be used in the expansion.