batch file to symbolic link files from different folders into common folder - for-loop

I have been trying to make symbolic links from multiple sources.
I have a reg.txt file in the new directory as well as the sort.bat.
the reg.txt :-
redcar1=123456
greencar2=345678
In directory called vehicles with sub directories of 'reg_numbers' ie:- 123456,
within that directory I have a sub directory called keys, or key, with a *.txt file.
I want to symbolic link all the 'reg_numbers' (parsing the reg.txt - changing the folder name in the process) directories into the new directory the sort.bat file is in, and all the keys or Key directory files (*.txt), into a common keys directory in the new folder
so say:-
D:\vehicles\123456\keys\this.txt
D:\vehicles\345678\key\that.txt
symbolic linked
e:\new\redcar1\
e:\new\greencar2\
e:\new\keys\this.txt
e:\new\keys\that.txt
sort.bat is in the new folder.
#echo off
setlocal EnableDelayedExpansion
set NEWPATH=%~dp0
set OLDPATH=d:\vehicles
for /f %%d in ('dir /b %NEWPATH%\keys') do (
if not "%%d"=="not.txt" del /Q "%NEWPATH%Keys\%%d" ::clean out files
)
for /f "tokens=1,2 delims==" %%a in (reg.txt) do (
rmdir /Q "%NEWPATH%%%a" ::clean out dir
mklink /D %NEWPATH%"%%a" %OLDPATH%\"%%b"
for /f %%c in ('dir /b %OLDPATH%\%%b\keys' ) do (
mklink %NEWPATH%Keys\"%%c" %OLDPATH%\"%%b"\"%%c"
)
)
It's probably a mess but it works for nearly everything but I cannot get the that.txt from key folder.

#echo off
setlocal EnableDelayedExpansion
set "NEWPATH=%~dp0"
set "OLDPATH=D:\vehicles"
for /f %%A in ('2^>nul dir /b /a-d "%NEWPATH%\keys"') do (
if not "%%~A" == "not.txt" del /Q "%NEWPATH%\Keys\%%~A"
)
for /f "usebackq tokens=1,2 delims==" %%A in ("%NEWPATH%\reg.txt") do (
rmdir /Q "%NEWPATH%\%%~A"
mklink /D "%NEWPATH%\%%~A" "%OLDPATH%\%%~B"
for /f %%C in ('2^>nul dir /b "%OLDPATH%\%%~B\keys" "%OLDPATH%\%%~B\key"' ) do (
mklink "%NEWPATH%\Keys\%%~C" "%OLDPATH%\%%~B\%%~C"
)
)
This may help to get symlinks to the files this.txt and that.txt. You have a keys folder and a key folder, yet your code only searches the directory of one of them. So now dir will search both directories.
I also adjusted quoting and use ~ in the for variables to remove possible quotes. Backslashes added as path separators where needed.
The double quotes for the set commands is to ensure that the value does not include any trailing space that is invisible to see.
2^>nul in the for commands is to redirect stderr stream to nul, so output of no files found by dir will not be output.
usebackq in for options changes the rules for the command. Double quotes without usebackq, interprets a double quotes as a string, not a path. With usebackq, double quotes can be used on a path. %~dp0 is a path that may have spaces so double quoting seems a good idea to add. View for /? for more help.

Related

Symlink all directories whose names contain word (Windows Batch)

I have Directory A, which contains a bunch of subdirectories, and empty Directory B. I would like to create a .bat file that symlinks all of the subdirectories inside Directory A whose names contain "april" (only the top-level ones) into Directory B. Is this possible?
What I have so far is:
echo off
setlocal EnableDelayedExpansion
title Updating Directories...
if exist "C:\path\to\directory\a" (
echo Updating Directories...
set "dira=C:\path\to\directory\a"
set "dirb=C:\path\to\directory\b"
for /f "usebackq delims=|" %%f in (`dir /b "!dira!"`) do (mklink /d "!dirb!\%%f" "!dira!\%%f")
title Symlinks Created^^!
echo Done^^!
pause
) else (
echo Cannot find Parent Directory.
pause
)
This works, but it symlinks all of the subdirectories inside Directory A into Directory B. Is there a way I can, for example, search for top-level directories whose names contain "april," return the list, and then only symlink those?
Not sure why you want a batch file. Just type the command.
for /f "delims=" %A in ('dir /b /ad "%userprofile%\desktop\*u*.*"') Do mklink /d "%userprofile%\desktop\b\%~nxA" "%A%
This create a link in a folder called B on the desktop (so create it first) for any folder on the desktop that contains the letter u in the name. See dir /?.
Note in Windows (NT family) the wildcard operators are regular expressions unlike Dos.
?*net*.* shows all files that contain net, but don't begin with net.
Thanks to #CatCat I was able to figure it out. Here's what's now working, for posterity's sake:
echo off
setlocal EnableDelayedExpansion
title Updating Directories...
if exist "!userprofile!\path\to\directory\a" (
echo Updating Directories...
set "dira=!userprofile!\path\to\directory\a"
set "dirb=!userprofile!\path\to\directory\b"
for /f "usebackq delims=|" %%f in (`dir /b "!dira!\*april*.*"`) do (mklink /d "!dirb!\%%f" "!dira!\%%f")
title Symlinks Created^^!
echo Done^^!
pause
) else (
echo Cannot find Parent Directory.
pause
)

Copying files with name containing just numbers using a batchfile

I have a Directory with a deep Directory->Sub-directory tree structure. I need to write a batch file to copy all the numbered files (files with names as digits and no alphabetic characters) from all the sub-directories.
For example, a sub-directory might contain the following files:
WR10091.txt
AX10091.htm
10091.txt
AX10091.xml
10091.xml
I need to copy 10091.txt and 10091.xml to another location. I can copy files like AX10091.xml and AX10091.htm by specifying AX*.*. But I cannot figure out how to copy just numbered files with no alphabetic characters. There are thousands of directories and the directory structure does not have any pattern (the depth of a tree branch can vary considerably).
Any help will be appreciated.
#echo off
setlocal enableextensions disabledelayedexpansion
set "source=%cd%"
set "target=x:\target\folder"
for /r "%source%" %%a in (*) do (
(for /f "delims=0123456789" %%b in ("%%~na") do (
break
)) || echo copy "%%~fa" "%target%"
)
In this code the for %%a will iterate over all the files under the indicated folder. For each of them, the for /f %%b will try to tokenize the file name (%%~na) using numbers as delimiters. If the file name only contains numbers, there will be nothing to process (only delimiters) and the inner for raises errorlevel. This is checked with conditional execution (the code after the || is executed if the previous command fails) and if errorlevel was raised the copy operation is echoed to console.
If the output is correct, remove the echo to perform the copy.
note: the break in the inner for loop is included just to have a command that does nothing when files with non numeric names are found.
#echo off
for /f "tokens=* delims=" %%a in ('dir /b /s /a:-d "*"') do (
echo %%~na|findstr /e /b /r "[1-9]*" >nul 2>nul && (
copy %%~fa c:\somewhere\
)
)
should be executed in the same directory as the files.
for /f "delims=" %%a in ('dir /b/s/a-d ^| findstr /reic:"\\[0-9][0-9]*\..*" /c:"\\[0-9][0-9]*"') do copy "%%~a" "targetDir"
This might not work with XP and/or Vista, but this can be fixed if needed (see What are the undocumented features and limitations of the Windows FINDSTR command).

Windows batch - match folders with a dot (.) in the folder name

I'm trying to figure out how to match folders with a dot in the file name (e.g., ".svn") in a Windows batch script.
Here's the basic script:
setlocal
pushd c:\myDir
#echo off
FOR /D /r %%G in ("*\.whatever") DO (
echo %%G
REM do stuff
)
#echo on
popd
endlocal
This works just fine for most folder names (e.g., "*bin"), but I can't figure out the method to specify a folder with the dot. "*.whatever" and "*\.whatever" return no results. I'm guessing I'm missing some escape character or something equally simple, but I haven't been able to find any documentation on it.
(Before anyone asks, no I'm not trying to recursively delete subversion folders; "*.svn" is just an example.)
Maybe I am missing something, but as you say it seems simple
for /r /d %%a in (.*) do echo %%~fa
But if the folders are hidden, the normal for will not be able to see them, so we need to execute a dir command an process its output with a for /f
for /f "delims=" %%a in ('dir /ad /s /b .*') do echo %%~fa

Adding Parent Directory name as Prefix to sub directory files using batch file

Adding Parent Directory name as Prefix to sub directory files using batch file
I need to add the prefix of the parent directory to all the files present in sub directories
for example we receive html and text files within Directories 101 as parent directory and Creatives as sub directory
F:\Files\101\Creatives\filename.htm and filename.txt
F:\Files\102\Creatives\filename.htm and filename.txt
F:\Files\103\Creatives\filename.htm and filename.txt
here I want to omit the sub directory name (Creatives) and add 101_, 102_, 103_ as the prefix to the filenames present in sub directories
example 101_filename.htm also for the text file as 101_filename.txt in sub folders
with the below code I can add the prefix to the sub folder files but I can only replace it with a static value (Prefix_), here I need to add the first directory name(101, 102, etc) as prefix to all the files present in (F:\Files) folder
#echo off
pushd "F:\Files"
for /r %%j in (*) do (
rename "%%j" "Prefix_%%~nxj"
)
popd
#echo off
pushd "F:\Files"
for /d %%P in (*) do for /f "delims=" %%F in ('dir /b /s /a-d "%%P"') do rename "%%F" "%%P_%%~nxF"
popd
The inner loop is FOR /F with DIR command instead of FOR /R to eliminate possibility of loop renaming the same file twice.
I guess you could find a solution involving 2 for loop.
Something like
for /f "tokens=*" %%d in ('dir /b') do ( for /f "tokens=*" %%f in ('dir /s /b %%d') do ( rename "%%f" "%%d_%%~nxf" ) )
Best Regards,
Michel.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "source=u:\Files"
pushd "%source%"
for /r %%j in (*) do (
SET "prefix=%%~dpj"
CALL :setpfx
ECHO rename "%%j" "!Prefix!_%%~nxj"
)
popd
GOTO :EOF
:setpfx
SET prefix=!prefix:*%source%=!
SET prefix=%prefix:\=.%
FOR /f %%t IN ("%prefix%") DO SET prefix=%%~nt
SET prefix=%prefix:.=_%
SET "prefix=%prefix:~1%"
GOTO :eof
This may do what you require. The required commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO RENAME to REN to actually rename the files.

Iterate all files in a directory using a 'for' loop

How can I iterate over each file in a directory using a for loop?
And how could I tell if a certain entry is a directory or if it's just a file?
This lists all the files (and only the files) in the current directory and its subdirectories recursively:
for /r %i in (*) do echo %i
Also if you run that command in a batch file you need to double the % signs.
for /r %%i in (*) do echo %%i
(thanks #agnul)
Iterate through...
...files in current dir: for %f in (.\*) do #echo %f
...subdirs in current dir: for /D %s in (.\*) do #echo %s
...files in current and all subdirs: for /R %f in (.\*) do #echo %f
...subdirs in current and all subdirs: for /R /D %s in (.\*) do #echo %s
Unfortunately I did not find any way to iterate over files and subdirs at the same time.
Just use cygwin with its bash for much more functionality.
Apart from this: Did you notice, that the buildin help of MS Windows is a great resource for descriptions of cmd's command line syntax?
Also have a look here: http://technet.microsoft.com/en-us/library/bb490890.aspx
To iterate over each file a for loop will work:
for %%f in (directory\path\*) do ( something_here )
In my case I also wanted the file content, name, etc.
This lead to a few issues and I thought my use case might help. Here is a loop that reads info from each '.txt' file in a directory and allows you do do something with it (setx for instance).
#ECHO OFF
setlocal enabledelayedexpansion
for %%f in (directory\path\*.txt) do (
set /p val=<%%f
echo "fullname: %%f"
echo "name: %%~nf"
echo "contents: !val!"
)
*Limitation: val<=%%f will only get the first line of the file.
There is a subtle difference between running FOR from the command line and from a batch file. In a batch file, you need to put two % characters in front of each variable reference.
From a command line:
FOR %i IN (*) DO ECHO %i
From a batch file:
FOR %%i IN (*) DO ECHO %%i
This for-loop will list all files in a directory.
pushd somedir
for /f "delims=" %%f in ('dir /b /a-d-h-s') do echo %%f
popd
"delims=" is useful to show long filenames with spaces in it....
'/b" show only names, not size dates etc..
Some things to know about dir's /a argument.
Any use of "/a" would list everything, including hidden and system attributes.
"/ad" would only show subdirectories, including hidden and system ones.
"/a-d" argument eliminates content with 'D'irectory attribute.
"/a-d-h-s" will show everything, but entries with 'D'irectory, 'H'idden 'S'ystem attribute.
If you use this on the commandline, remove a "%".
Hope this helps.
%1 refers to the first argument passed in and can't be used in an iterator.
Try this:
#echo off
for %%i in (*.*) do echo %%i
I had trouble getting jop's answer to work with an absolute path until I found this reference: https://ss64.com/nt/for_r.html
The following example loops through all files in a directory given by the absolute path.
For /R C:\absoulte\path\ %%G IN (*.*) do (
Echo %%G
)
Here's my go with comments in the code.
I'm just brushing up by biatch skills so forgive any blatant errors.
I tried to write an all in one solution as best I can with a little modification where the user requires it.
Some important notes: Just change the variable recursive to FALSE if you only want the root directories files and folders processed. Otherwise, it goes through all folders and files.
C&C most welcome...
#echo off
title %~nx0
chcp 65001 >NUL
set "dir=c:\users\%username%\desktop"
::
:: Recursive Loop routine - First Written by Ste on - 2020.01.24 - Rev 1
::
setlocal EnableDelayedExpansion
rem THIS IS A RECURSIVE SOLUTION [ALBEIT IF YOU CHANGE THE RECURSIVE TO FALSE, NO]
rem By removing the /s switch from the first loop if you want to loop through
rem the base folder only.
set recursive=TRUE
if %recursive% equ TRUE ( set recursive=/s ) else ( set recursive= )
endlocal & set recursive=%recursive%
cd /d %dir%
echo Directory %cd%
for %%F in ("*") do (echo → %%F) %= Loop through the current directory. =%
for /f "delims==" %%D in ('dir "%dir%" /ad /b %recursive%') do ( %= Loop through the sub-directories only if the recursive variable is TRUE. =%
echo Directory %%D
echo %recursive% | find "/s" >NUL 2>NUL && (
pushd %%D
cd /d %%D
for /f "delims==" %%F in ('dir "*" /b') do ( %= Then loop through each pushd' folder and work on the files and folders =%
echo %%~aF | find /v "d" >NUL 2>NUL && ( %= This will weed out the directories by checking their attributes for the lack of 'd' with the /v switch therefore you can now work on the files only. =%
rem You can do stuff to your files here.
rem Below are some examples of the info you can get by expanding the %%F variable.
rem Uncomment one at a time to see the results.
echo → %%~F &rem expands %%F removing any surrounding quotes (")
rem echo → %%~dF &rem expands %%F to a drive letter only
rem echo → %%~fF &rem expands %%F to a fully qualified path name
rem echo → %%~pF &rem expands %%A to a path only
rem echo → %%~nF &rem expands %%F to a file name only
rem echo → %%~xF &rem expands %%F to a file extension only
rem echo → %%~sF &rem expanded path contains short names only
rem echo → %%~aF &rem expands %%F to file attributes of file
rem echo → %%~tF &rem expands %%F to date/time of file
rem echo → %%~zF &rem expands %%F to size of file
rem echo → %%~dpF &rem expands %%F to a drive letter and path only
rem echo → %%~nxF &rem expands %%F to a file name and extension only
rem echo → %%~fsF &rem expands %%F to a full path name with short names only
rem echo → %%~dp$dir:F &rem searches the directories listed in the 'dir' environment variable and expands %%F to the fully qualified name of the first one found. If the environment variable name is not defined or the file is not found by the search, then this modifier expands to the empty string
rem echo → %%~ftzaF &rem expands %%F to a DIR like output line
)
)
popd
)
)
echo/ & pause & cls
To iterate through all files and folders you can use
for /F "delims=" %%a in ('dir /b /s') do echo %%a
To iterate through all folders only not with files, then you can use
for /F "delims=" %%a in ('dir /a:d /b /s') do echo %%a
Where /s will give all results throughout the directory tree in unlimited depth. You can skip /s if you want to iterate through the content of that folder not their sub folder
Implementing search in iteration
To iterate through a particular named files and folders you can search for the name and iterate using for loop
for /F "delims=" %%a in ('dir "file or folder name" /b /s') do echo %%a
To iterate through a particular named folders/directories and not files, then use /AD in the same command
for /F "delims=" %%a in ('dir "folder name" /b /AD /s') do echo %%a
for %1 in (*.*) do echo %1
Try "HELP FOR" in cmd for a full guide
This is the guide for XP commands. http://www.ss64.com/nt/
The following code creates a file Named "AllFilesInCurrentDirectorylist.txt" in the current Directory, which contains the list of all files (Only Files) in the current Directory. Check it out
dir /b /a-d > AllFilesInCurrentDirectorylist.txt
It could also use the forfiles command:
forfiles /s
and also check if it is a directory
forfiles /p c:\ /s /m *.* /c "cmd /c if #isdir==true echo #file is a directory"
I would use vbscript (Windows Scripting Host), because in batch I'm sure you cannot tell that a name is a file or a directory.
In vbs, it can be something like this:
Dim fileSystemObject
Set fileSystemObject = CreateObject("Scripting.FileSystemObject")
Dim mainFolder
Set mainFolder = fileSystemObject.GetFolder(myFolder)
Dim files
Set files = mainFolder.Files
For Each file in files
...
Next
Dim subFolders
Set subFolders = mainFolder.SubFolders
For Each folder in subFolders
...
Next
Check FileSystemObject on MSDN.
I use the xcopy command with the /L option to get the file names. So if you want to get either a directory or all the files in the subdirectory you could do something like this:
for /f "delims=" %%a IN ('xcopy "D:\*.pdf" c:\ /l') do echo %%a
I just use the c:\ as the destination because it always exists on windows systems and it is not copying so it does not matter. if you want the subdirectories too just use /s option on the end. You can also use the other switches of xcopy if you need them for other reasons.
Try this to test if a file is a directory:
FOR /F "delims=" %I IN ('DIR /B /AD "filename" 2^>^&1 ^>NUL') DO IF "%I" == "File Not Found" ECHO Not a directory
This only will tell you whether a file is NOT a directory, which will also be true if the file doesn't exist, so be sure to check for that first if you need to. The carets (^) are used to escape the redirect symbols and the file listing output is redirected to NUL to prevent it from being displayed, while the DIR listing's error output is redirected to the output so you can test against DIR's message "File Not Found".
try this:
::Example directory
set SetupDir=C:\Users
::Loop in the folder with "/r" to search in recursive folders, %%f being a loop ::variable
for /r "%SetupDir%" %%f in (*.msi *.exe) do set /a counter+=1
echo there are %counter% files in your folder
it counts .msi and .exe files in your directory (and in the sub directory). So it also makes the difference between folders and files as executables.
Just add an extension (.pptx .docx ..) if you need to filter other files in the loop
In my case I had to delete all the files and folders underneath a temp folder. So this is how I ended up doing it. I had to run two loops one for file and one for folders. If files or folders have spaces in their names then you have to use " "
cd %USERPROFILE%\AppData\Local\Temp\
rem files only
for /r %%a in (*) do (
echo deleting file "%%a" ...
if exist "%%a" del /s /q "%%a"
)
rem folders only
for /D %%a in (*) do (
echo deleting folder "%%a" ...
if exist "%%a" rmdir /s /q "%%a"
)

Resources