How to parse a directory recursively and MKLINK each file into a target path with the same tree structure
Solution 1
Create symbolic links with MKLink
from one folder structure to another recursively but for files only that do not already exist in the target directory
Note: The below solutions will skip making symbolic links to files at target from the source if the same file name already exists at the target. It will also create the target path sub-folders that don't exist already if a symbolic link needs to be created.
1. Batch Script (pure batch)
Below is a pure batch script solution using a for /r loop with setlocal enabledelayedexpansion and variable substrings to get the iterated full file path and directory names from the source location. This sets additional variables from those values parsing the source root path from the string and then concatenates the target root path back to the string to be used to create the symbolic links accordingly as per your requirements and the above topmost note.
Important: It is important to understand the number of characters in the
SrcRoot=
path variable value here so you can set the variable substring number to skip that same number of characters in that string to parse it out so it can be replaced by theTargetRoot=
variable value instead.For Example: So
Z:\a
is exactly 4 characters whereZ
,:
,\
, anda
each count as 1 character. Summed up this is 4 total; thus, this is where the~4
comes into play in the!oDir:~4!
and!oFile:~4!
portions of the logic within the loop. So each literal character in theSrcRoot
value will each count as 1 so sum those up and replace the number after the tilde (~<#>
) with it.@ECHO ON SET SrcRoot=Z:\a SET TargetRoot=Z:\b SETLOCAL ENABLEDELAYEDEXPANSION FOR /R "%SrcRoot%" %%A IN ("*") DO ( SET oDir=%%~DPA SET oFile=%%~A IF NOT EXIST "%TargetRoot%!oDir:~4!" MD "%TargetRoot%!oDir:~4!" IF NOT EXIST "%TargetRoot%!oFile:~4!" MKLINK "%TargetRoot%!oFile:~4!" "%%~A" ) PAUSE EXIT
2. Batch Script (with PowerShell)
Below is a batch script solution using a for /r loop nested into a for /f loop to get a variable name from a dynamically created and executed PowerShell script with variables passed in accordingly to then process with the replace method to replace the source path with the target path to then created the symbolic links as per your requirements and the above topmost note.
@ECHO ON SET SrcRoot=Z:\a SET TargetRoot=Z:\b CALL :PowerShell FOR /R "%SrcRoot%" %%A IN ("*") DO ( CD /D "%PowerShellDir%" FOR /F "TOKENS=*" %%B IN ('Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%' '"%SrcRoot%"' '"%TargetRoot%"' '"%%~A"'"') DO ( IF NOT EXIST "%%~DPB" MD "%%~DPB" IF NOT EXIST "%%~B" MKLINK "%%~B" "%%~A" ) ) PAUSE EXIT :PowerShell SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0 SET PSScript=%temp%\~tmpStrFldrRplc.ps1 IF EXIST "%PSScript%" DEL /Q /F "%PSScript%" ECHO $Source = $args[0]>"%PSScript%" ECHO $Dest = $args[1]>>"%PSScript%" ECHO $FPath = $args[2]>>"%PSScript%" ECHO $var = $FPath.Replace($Source,$Dest)>>"%PSScript%" ECHO Write-Output $Var>>"%PSScript%" GOTO :EOF
Further Resources
- FOR /R
- Setlocal EnableDelayedExpansion
- Variables: extract part of a variable (substring)
- FOR /F
- Replace
-
Batch Substitutions (FOR /?)
In addition, substitution of FOR variable references has been enhanced. You can now use the following optional syntax:
%~dI - expands %I to a drive letter only %~pI - expands %I to a path only
-
mklink /?
Creates a symbolic link. MKLINK [[/D] | [/H] | [/J]] Link Target /D Creates a directory symbolic link. Default is a file symbolic link. /H Creates a hard link instead of a symbolic link. /J Creates a Directory Junction. Link Specifies the new symbolic link name. Target Specifies the path (relative or absolute) that the new link refers to.
Solution 2
Emulating a Recursive File and Folder Structure with MKLink
Note: This works with an already existing root level target folder.
You can use a for /d loop and iterate the first level root sub-folders within the source directory, and then use the mklink command with the /D
parameter to
create directory symbolic links to link those sub-folders in the target path's root directory creating an emulated directory structure beneath each as you desire with files beneath each being referenced recursively too—the root level target folder can already exist with this method.
You can then use a for loop iterating the first level files within the source directory and then use the mklink command accordingly to create those as direct symbolic links within the root of the target directory, and the root level target folder can already exist with this method too.
Batch Script
@ECHO ON
SET SrcRoot=Z:\a
SET TargetRoot=Z:\b
FOR /D %%A IN ("%SrcRoot%\*") DO (
MKLINK /D "%TargetRoot%\%%~NA" "%%~A"
)
FOR %%A IN ("%SrcRoot%\*") DO (
MKLINK "%TargetRoot%\%%~NXA" "%%~A"
)
PAUSE
EXIT
Results
Further Resources
- FOR /D
-
Batch Substitutions (FOR /?)
In addition, substitution of FOR variable references has been enhanced. You can now use the following optional syntax:
%~nI - expands %I to a file name only %~xI - expands %I to a file extension only
-
mklink /?
Creates a symbolic link. MKLINK [[/D] | [/H] | [/J]] Link Target /D Creates a directory symbolic link. Default is a file symbolic link. /H Creates a hard link instead of a symbolic link. /J Creates a Directory Junction. Link Specifies the new symbolic link name. Target Specifies the path (relative or absolute) that the new link refers to.
Related videos on Youtube
Zhro
Updated on September 18, 2022Comments
-
Zhro over 1 year
I have a directory
a\
containing files and sub-directories that I want to copy into pathb\
where instead of copying the files I want to perform a call toMKLINK <link> <target>
on each file into the new path rather than performing an actual copy.So if I have a directory:
Z:\a\file1.txt Z:\a\file2.txt Z:\a\some_path\file3.txt Z:\a\some_path\file4.txt
And I copy links from path
a\
tob\
the result will look like:Z:\b\file1.txt <<===>> z:\a\file1.txt Z:\b\file2.txt <<===>> z:\a\file2.txt Z:\b\some_path\file3.txt <<===>> z:\a\some_path\file3.txt Z:\b\some_path\file4.txt <<===>> z:\a\some_path\file4.txt
The directory hierarchy is to be preserved as non-link folders in the event that the target directory does not have a matching folder structure. Note that only the files are links.
A successful test will succeed where
Z:\b
is an empty directory,Z:\b
contains a folderZ:\b\some_path
, and either previous tests butZ:\b
my already contain files of the same name; conflicts are ignored and no link is created for them.How can I do this using a batch file with no additional dependencies beyond what is available in a standard Windows 10 installation?
-
Zhro almost 6 yearsThis does not answer the question. To be more specific, directory
b
already exists and contains other files already. The idea is to merge in a bunch of symbolic links instead of copying a folder over and duplicating disk space. -
Zhro almost 6 yearsI'm not able to test this tonight but I will look into your answer more closely tomorrow.
-
Zhro almost 6 yearsThis is certainly closer but only files are to be links. This requirement was in the original question but I've modified it to added additional clarification and emphasis. Using the code from your answer with my question's test case, if
Z:\b\some_path
as a folder already exists thenMKLINK /D Z:\b\some_path Z:\a\some_path
will fail and subsequentlyZ:\b\some_path\file3.txt
andZ:\b\some_path\file4.txt
won't exist. And in the extent that it does succeed,Z:\b\some_path
is a link toZ:\a\some_path
and thereforeZ:\b\some_path\file3.txt
andZ:\b\some_path\file4.txt
are not links. -
Zhro almost 6 yearsThe the question is asking how to solve this using batch scripting. Introducing PowerShell, while technically available, is outside the scope of what I had intended by mentioning Windows 10. I meant that you could call other programs which might be available, such as MKLINK.
-
Zhro almost 6 yearsI haven't had a chance to look at this yet as I've been very busy. Sorry for the delay. Please continue to be patient.
-
Vomit IT - Chunky Mess Style almost 5 yearsWhat's up @Zhro .... Let me know if you've taken a stab at it yet and what results you got.