Page 1 of 2

Creating Symbolic and Hard Links with a Batch File

Posted: 06 Nov 2012 10:54
by soad1789
I'm trying to write a batch file that will take the files in folder X (has subdirectories) and create absolute symbolic links with the same filename and directory structure in folder Y (I want ACTUAL folders, only files as symlinks).

I already have this so far, but I'm stuck because I don't understand the delayed expansion premise... I'm pretty sure it's relevant here, but even with it on I can't seem to get %%G into a variable to perform string functions on it (another thing that confuses me a lot in batch... how do I trim the filepath to just a filename here?).

Any help would be greatly appreciated, seems like you guys know what you're doing! :mrgreen:

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

IF EXIST "FILESINLOOP.txt" DEL "FILESINLOOP.txt"

SET SRC="X"
SET DST="Y"

PAUSE

FOR /F "USEBACKQ DELIMS=|" %%G IN (`dir /B /S /A:-D "X"`) DO (
ECHO %%G >> FILESINLOOP.txt
SET CURFILE=%%G
ECHO %CURFILE%
MKLINK "Y\[trimmed curfile path>filename]" %%G
)

PAUSE


Thanks in advance for any advice / help!

EDIT: Changed the topic title to make this easier to find for others with similar goals.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 12:57
by timbertuck
i think this might make it work a little better, but it doesnt work on the files in the source dir, just the subdirs and those files. you can easily create a loop from below just to operate on the source dir. hope it helps

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

IF EXIST "%temp%\FILESINLOOP.txt" DEL "%temp%\FILESINLOOP.txt"

SET SRC=x
SET DST=y

for /f "tokens=1-2* delims= " %%a in ('dir /b /ad /s') do (
   if not exist %DST%\%%~nxa echo mkdir %DST%\%%~nxa
   FOR /F "delims=|" %%G IN ('dir /B /A-D %%a') DO (
      ECHO %%~nG >> FILESINLOOP.txt
      SET CURFILE=%%~nG
      echo MKLINK !curfile! %DST%\%%~nxa\!curfile!
   )
)
PAUSE


wasnt real sure how to use the mklink command, you can sort that out yourself i think.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 13:43
by soad1789
Thanks for the input, timbertuck, however I think your nested FOR loop confused me more than it helped :? . The main issue I'm having with the original code is the %%G parameter in the FOR loop.

Code: Select all

FOR /F "USEBACKQ DELIMS=|" %%G IN (`dir /B /S /A:-D "X"`) DO (
ECHO %%G >> FILESINLOOP.txt
SET CURFILE=%%~nG
ECHO %CURFILE%
REM MKLINK "Y\%%~nG" %%G


The ECHO command works just fine using the %%G parameter, but I can't figure out how to set a variable to %%G. I must be missing something simple, no?

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 13:48
by timbertuck
you need to put the "~n" in between the "%%" and the "G". that will extract just the filename (but not the path or extension,etc)

is that what you mean?

and as for setting a var, its "set Var=%%G" or "set Var=%%~nG" depending on your needs

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 13:51
by timbertuck
soad1789 wrote:Thanks for the input, timbertuck, however I think your nested FOR loop confused me more than it helped :? . The main issue I'm having with the original code is the %%G parameter in the FOR loop.
The ECHO command works just fine using the %%G parameter, but I can't figure out how to set a variable to %%G. I must be missing something simple, no?


well the first for loop went through the current folders and subfolders to create them as new folders under the TargetDirectory\
and then the second for loop worked on any file in those folders by doing an mklink...

but as i said, it didn't work on the current files but that is just additional code to run at the end of the current loops

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 13:59
by soad1789
:oops: Der! Thank you so much timbertuck, that's what I needed!

Code: Select all

FOR /F "USEBACKQ DELIMS=|" %%G IN (`dir /B /S /A:-D "X"`) DO (
ECHO %%G >> FILESINLOOP.txt
ECHO MKLINK "Y\%%~nG" %%G


The only problem I have now is that I won't preserve any subdirectory structure-- which is why you were nesting the FOR loops... der again... ahhh... :!:

OK. I don't quite understand the purpose of 'tokens1-2*' in your first loop. Aren't you just hitting all files anyway with the asterisk in there?

I'm gonna play around with it again, thanks again timbertuck. I swear I'm not always that inept, but the density of batch gets me overwhelmed sometimes.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 14:08
by timbertuck
soad1789 wrote::oops: Der! Thank you so much timbertuck, that's what I needed!
The only problem I have now is that I won't preserve any subdirectory structure-- which is why you were nesting the FOR loops... der again... ahhh... :!:
OK. I don't quite understand the purpose of 'tokens1-2*' in your first loop. Aren't you just hitting all files anyway with the asterisk in there?
I'm gonna play around with it again, thanks again timbertuck. I swear I'm not always that inept, but the density of batch gets me overwhelmed sometimes.


you can build a loop to create just the subdir's in Target, then another loop to work on all files in Source+subdirs. By nesting i just made the code a little more concise.

on the tokens, i made a mistake there actually i meant to remove it, it should only be "tokens=1 delims=". the asterisk says anything left after delim1 and delim2 so in this case it would have captured a file that had spaces in the name. but not needed.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 14:55
by soad1789
OK, so this is *almost* in working condition. The one thing I can't seem to figure out is how to get the MKDIR to act recursively.

Instead of recreating the subdirectories a few levels deep, it's creating all subdirectories as first-level ones under the main one :|

Also, I gave some bad example path names before, these directories and files actually DO include spaces. :roll:

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

IF EXIST "FILESINLOOP.txt" DEL "FILESINLOOP.txt"

SET SRC=X space
SET DST=Y space

FOR /F "tokens=1 delims=" %%a in ('dir /b /ad /s "%SRC%"') do (
   echo %%a & echo.
   if not exist %DST%\%%~nxa echo mkdir %DST%\%%~nxa
   FOR /F "delims=|" %%G IN ('dir /B /A-D "%%a"') DO (
      ECHO %%~nG >> FILESINLOOP.txt
      ECHO MKLINK "%%~nxG" "%%~fa\%%~nxG"
   )
)


How can I get that MKDIR cmd fixed? I'm working on it, but if you have any suggestions that'd be excellent :)

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 14:58
by timbertuck
soad1789 wrote:OK, so this is *almost* in working condition. The one thing I can't seem to figure out is how to get the MKDIR to act recursively.

Instead of recreating the subdirectories a few levels deep, it's creating all subdirectories as first-level ones under the main one :|

Also, I gave some bad example path names before, these directories and files actually DO include spaces. :roll:

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

IF EXIST "FILESINLOOP.txt" DEL "FILESINLOOP.txt"

SET SRC=X space
SET DST=Y space

FOR /F "tokens=1 delims=" %%a in ('dir /b /ad /s "%SRC%"') do (
   echo %%a & echo.
   if not exist %DST%\%%~nxa echo mkdir %DST%\%%~nxa
   FOR /F "delims=|" %%G IN ('dir /B /A-D "%%a"') DO (
      ECHO %%~nG >> FILESINLOOP.txt
      ECHO MKLINK "%%~nxG" "%%~fa\%%~nxG"
   )
)


How can I get that MKDIR cmd fixed? I'm working on it, but if you have any suggestions that'd be excellent :)


well that makes it a little more in depth. however i must be away from my computer till tomorrow, so if you can wait till then, ill see what i can do.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 15:25
by soad1789
That'd be excellent, timbertuck. Your help's worth the wait, because this just went way over my head!

The premise is simple, but making the for loop recursive is really confusing me.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 06 Nov 2012 21:36
by foxidrive
Try this: filenames with ! and probably % and ^ will cause issues.

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

SET "SRC=c:\Files\bat"
SET "DST=d:\abc"

pushd "%src%"

del "%dst%\FILESINLOOP.txt" 2>nul

FOR /F "delims=" %%a in ('dir /b /s /a-d') do (
   echo %%a & echo.
   set "var2=%%~dpa"   
   set "var2=!var2:%src%=!"
   md "%dst%!var2!" 2>nul
   ECHO %%~na >> "%dst%\FILESINLOOP.txt"
   ECHO MKLINK "%dst%!var2!%%~nxa" "%%a"
pause
)
popd

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 07 Nov 2012 07:55
by soad1789
Interesting take foxidrive, thanks for the input.

The trouble with your version is that I'm running this batch one folder up from the source and destination folders, and relative paths must be used for the source and destination vars.

I need to figure out how to run the FOR loop in a way that I allows me to make a directory in "%DST%\!var2!", where var2 is the path of the subdirectories under %SRC%.

This script will be running on a server I don't have direct access to, so I can't be sure what the absolute paths look like. I know... makes it a lot trickier... hmmm... :|

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 07 Nov 2012 08:42
by foxidrive
soad1789 wrote:The trouble with your version is that I'm running this batch one folder up from the source and destination folders, and relative paths must be used for the source and destination vars.


It's also troublesome when people don't spell out the entire task clearly - because people like me write some code and test it, only to find the goalposts have been shifted.

So many people use fake filenames, and paths and it just makes almost every task like a 50 questions guessing game - where you do what you think the OP wants.
People don't understand that batch files often rely on the filenames and paths and format of the text being parsed.

Anyway, </rant>

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 07 Nov 2012 09:28
by soad1789
You're absolutely right, foxidrive, and I understand you're frustrated. Sorry about that. Thing is, some of the files and pathnames I'm shifting around are sensitive and I had to use discretion with names and paths.

Nonetheless, your code was indeed helpful and very much appreciated, and in fact I think it was the catalyst to helping me accomplish what I had set out to do originally.

Code: Select all

@ECHO OFF
SETLOCAL EnableDelayedExpansion

SET "SRC=A n B"
SET "DST=Y n Z"

if exist "FILESINLOOP-2.txt" del "FILESINLOOP-2.txt" 2>nul

::pushd "%src%"

FOR /F "delims=" %%a IN ('DIR /b /s /a-d "%SRC%"') DO (
   ECHO %%a & ECHO.
   SET "var2=%%~dpa"
   SET "var2=!var2:%CD%\=!"
   ECHO MD "%dst%\!var2!" 2>nul
   ECHO.
   ECHO %%~na >> "FILESINLOOP-2.txt"
   ECHO MKLINK "%%~nxa" "%%a" & ECHO.
)
PAUSE
::popd


I ended up taking pushd/popd out as the MD command was creating the links inside of the source directory.

As the code stands, it seems like the script will now create a copy of the 'SRC' folder (A n B) inside the 'DST' directory (i.e. "%CD%\Y n Z\A n B\subdir1\etc..."), then maintain subdirectory structure from there.

You're absolutely right about batch, foxidrive, and I didn't mean to imply you weren't being helpful in any way. I just didn't want to be verbose about the specifics of the task simply because I thought others would gloss over the post and think "TL;DR" and move on, my bad. :) Good to know that's not the case (I mean this is batch after all, specifics are paramount)!

Looking back, I probably could've done this easier with VBS as I find it easier, but I wanted to make sure there would be no anomalies running this on the server.

Thanks to both of you, I think this script should work. I'm gonna do a "dry run" of sorts on a local copy of the file structure to check it, then go from there.

Thank you both, sincerely, for taking the time to help me with what I'm sure you'd both describe as a fairly menial task.

Re: Simple (?) DelayedExpansion / String Problems [NOOB]

Posted: 07 Nov 2012 10:24
by foxidrive
soad1789 wrote:Looking back, I probably could've done this easier with VBS as I find it easier, but I wanted to make sure there would be no anomalies running this on the server.


No worries. VBS is a better choice in cases where poison characters are in filenames - such as ! % ^

Plain batch will give you anomalies in such a case. :)