I am trying to get the file version of all the files inside a folder which I managed to do (but not in a good way) but now I want to stick the folder name along with the version so I would know which version is for which folder.
I am not very good in command line and only use it for some small tasks whenever I need it so my apology in advance..
Here is what I have done:
For /d %%a in (C:\high\low\*) Do (For /d %%* in (%%a) Do wmic datafile where name="%%~da\\high\\low\\%%~nx*\\bin\\Services.dll" get Version /value)
and I get output as:
`Version=2.2.0.1 Version=2.2.0.4 Version=2.2.0.4....Version=2.2.0.4
there are 20 folders under C:\high\low and I want to go into the bin directory of each sub folder so I can see which folder has been upgraded and which one is not.
Edit
There are more than 20 folders and structure is like this:
C:\high\low\office.Services.Bolton\bin\Services.dll
C:\high\low\office.Services.Slough\bin\Services.dll
C:\high\low\office.Services.Hull\bin\Services.dll
.
.
.
C:\high\low\office.Services.Cosham\bin\Services.dll
I want to check the version number of Services.dll and need the output as:
Bolton - 2.2.0.1
Slough - 2.3.0.1
Hull - 2.5.0.1
.
.
.
Cosham - 2.0.0.0
Thanks in advance..
Instead of stacking for /d you could do a dir /b/s to find all Services.dll and parse the nasty (cr,cr,lf) output of wmic with a for /f:
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
For /F "tokens=*" %%A in (
'Dir /B/S C:\high\low\Services.dll ^|findstr /i "bin\\Services.dll$"'
) Do (
Set "DLL=%%~fA"
Set "DLL=!DLL:\=\\!"
For /F "tokens=1* delims==" %%B in (
'wmic datafile where name^="!DLL!" get Version /value^|findstr Version'
) Do For /f "delims=" %%D in ("%%C") Do Echo Version: %%D %%~fA
)
The first For /f parses the output of the commamd inside the '' iterating through each line passed in %%A (I prefer upper case variables to better distinguish between lower case~ modifiers.
Since Dir will allow wildcards only in the last element I can't do a Dir /B/S C:\high\low\*\bin\Services.dll
To ashure I get only Services.dll in a bin folder I pipe dir output to findstr /i "bin\\Services.dll$ (findstr uses by default a limited RegEx so the \ has to be escaped with another one, the $ anchors the expression at the end of the line).
The wmic command needs the backslashes in the path also escaped what is possible with string substitution (works only with normal variables)
In a (code block) we need delayed expansion to get actual values for variables changed in the code block, so ! instead of % for framing the variable names
The 2nd For /f parses wmic output splitting at the equal sign, assigning content to var %%C
EDIT added another for /f to remove the wmic cr
Related
Ok so I'm super close to doing what I need to do.
I'm having an issue with my rename command and a double letter at the end of the folder. The folder names in the code have been changed for privacy, Spaces have been kept to show how the folders would be named.
The double letter is uppercase I (eye), this can't be changed.
Yes this file exists.
Example:
FolderII - error: The system cannot find the path specified.
Folder - Works
FolderI - works
for /r "C:\Folder Name" %%a in (*) do if "%%~nxa"=="FileFound" set p=%%~dpnxa
for /f "usebackq tokens=1* delims=." %%A in ("%p%") do set Build=%%B
for /f "tokens=2 delims==" %%G in ('wmic os get localdatetime /value') do set datetime=%%G
for /f "tokens=3 delims=\" %%Z in ("%p%") do set filepath=%%Z
set year=%datetime:~0,4%
set month=%datetime:~4,2%
set day=%datetime:~6,2%
set dbname=Logdb%year%.%Build%
REN "C:\Folder Name\%filepath%\%dbname%" "Logdb%month%-%day%-%year%.%Build%"
OUTPUT
EDITED!
CMD>REN "C:\Folder Name\FolderII\Logdb2020.ext" "Logdb11-23-2020.ext"
The system cannot find the file specified.
Added
CMD>REN "C:\Folder Name\Folder\Logdb2020.ext" "Logdb11-23-2020.ext"
THIS works
EDIT FOR CLARIFICATION*
I'll explain this how I intended it to work, which it does as long as the folder it's being assigned to doesn't have a II in it.
1st line: Search this particular folder for a file called "SYSCON" no extension, once found assign to p the file path of the file for 2nd line
2nd line:Open file found at 1st line and get the extension of the file listed inside the file and assign it to Build
3rd line:Get the current date to assign to the new file name in REN
4th line:Use the file path found in line 1 to get the folder name for the REN
5-7 set date variables
Line 8:Assign the new file name to variable
Line 9:Rename the old file at the location found to the new file name generated
I'm not a batch developer, I've literally written these lines as they work for me, but I'm always willing to learn how to do better, I'm a PHP programmer. This is a different project.
The folder structure is fluid for the application. The reason for the search for the initial file is to find the file in 1 of 4 folders and then get that actual folder name.
I can echo all the variables and see the correct file path, the correct file name and the correct new file name.
When it comes to rename the file in the folder with II, it fails to find the actual file to do the rename on, that's where I'm stuck.
IMAGE of Output echoed as it steps through the lines, for privacy sake I have to change the file names. Here's the CMD output for, I hope, better understanding
I'm not positive, based upon your lack of specific information, but as a best guess, I'd assume that something like this should perform the task, I think your example is trying to achieve.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H") Do Set "Build=%%J"
SetLocal EnableDelayedExpansion
Ren "%%G\Logdb%YYYY%.!Build!" "Logdb%MM%-%DD%-%YYYY%.!Build!"
EndLocal)
The example above expects the the string you're using for the Build variable is on the last non empty line of the target file, (ASCII text with CRLF line endings). If it is the only non empty line in that target file, then perhaps the following would be more useful:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Tokens=1-3 Delims=/ " %%G In (
'""%__AppDir__%Robocopy.exe" \: . /NJH /L | "%__AppDir__%find.exe" " 123""'
) Do Set "YYYY=%%G" & Set "MM=%%H" & Set "DD=%%I"
For /D %%G In (C:\Folder Name\*) Do For %%H In ("%%G\SYSCON"
) Do If "%%~aH" Lss "d" If "%%~aH" GEq "-" (
For /F "UseBackQ Tokens=1,* Delims=." %%I In ("%%H"
) Do Ren "%%G\Logdb%YYYY%.%%J" "Logdb%MM%-%DD%-%YYYY%.%%J")
It would seem that the data assigned to build contains trailing spaces and perhaps some invisible characters. The easy way would be to simply change 1* to 1,2.
Since Space is a default delimiter, %%B will be assigned the value between the first and second spaces on the line. Tough if you want spaces in the extension, but do you really want to use extensions with spaces?
The syntax SET "var=value" (where value may be empty; in which case var becomes undefined) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
I would like to write a batch that will copy all of the files in a given source path to a given output path, and plot the target path of the files that were actually changed.
XCOPY is doing almost that. It plots the source paths.
I guess it would be easier with PowerShell, but I would rather keeping it in the bat file.
Extending Sumit's suggestion of the /F option - you could use FOR /F to parse out only the destination files. There is no need for a batch script. It can be a one liner on the interactive command line.
for /f "delims=> tokens=2" %A in ('xcopy /f "someSourcePath\*.txt" "someDestinationPath"') do #echo %A
The above will include an unwanted leading space on each line of output. If needed, you can use an extra FOR /F to remove the leading space.
for /f "delims=> tokens=2" %A in ('xcopy /f "someSourcePath\*.txt" "someDestinationPath"') do #for /f "tokens=* delims= " %B in ("%A") do #echo %B
Either way, the file count at the end is also removed.
Double all % as %% if you put the command in a batch script.
The solution is even simpler if you have my JREPL.BAT regular expression text processing utility - a purely script based utility (hybrid JScript/batch) that runs natively on any Windows machine from XP onward.
xcopy /F "someSourcePath\*.txt" "someDestinationPath" | jrepl "> (.*)" $1 /jmatch
If you want to preserve the file count at the end, then you could use an even simpler variation
xcopy /F "someSourcePath\*.txt" "someDestinationPath" | jrepl "^.*> " ""
You can print source path and new destination path together with F switch in xcopy
Consider this example
xcopy * DRIVE-LETTER:\New\ /F
Will output in this format
F:\OLD-FOLDER\DSCN.JPG -> F:\New\DSCN.JPG
F:\OLD-FOLDER\DSCN1.JPG -> F:\New\DSCN1.JPG
This script takes two arguments: the source dir and the dest dir
It is a functional example. (You'll need to customize the output to suit your needs.) The script does not check for errors. You may (or may not) wish to do that.
#SETLOCAL ENABLEDELAYEDEXPANSION
#ECHO OFF
REM
SET "SRC_PATH=%~1"
SET "DST_PATH=%~2"
MKDIR "%DST_PATH%"
REM Copy the files
FOR %%f IN (%SRC_PATH%\*.*) DO (
SET "SRC_FILE=%%~f"
SET "DST_FILE=%DST_PATH%\%%~nxf"
#ECHO SOURCE FILE: !SRC_FILE!
#ECHO DEST FILE : !DST_FILE!
COPY "!SRC_FILE!" "!DST_FILE!"
)
REM Recursively descend into the subdirectories
FOR /D %%d IN (%SRC_PATH%\*.*) DO (
SET "SRC_SUBDIR=%%~d"
SET "DST_SUBDIR=%DST_PATH%\%%~nxd"
#ECHO SOURCE DIR: !SRC_SUBDIR!
#ECHO DEST DIR : !DST_SUBDIR!
cmd /c %~s0 "!SRC_SUBDIR!" "!DST_SUBDIR!"
)
Alter the ECHO statements to do what you need.
I want to list all files (with relative path) in a folder with a specific sub-folder, and write that list to a text file. The folder is a network folder so I can not set it as current directory. All this via batch script.
So like this:
Folder structure:
\\OtherComputer\MyFiles\libs
--File1.dll
--File2.dll
\\OtherComputer\MyFiles\libs\Editor\
----File3.dll
I want to generate a file with the following text:
File1.dll
File2.dll
Editor\File3.dll
This is how far I have come:
SET LibPath=\\OtherComputer\MyFiles\
break >"%LibPath%metadata"
for %%F in (%LibPath%*.*) do (
echo %%F>>"%LibPath%metadata"
)
for %%F in (%LibPath%Editor\*.*) do (
echo Editor\%%F>>"%LibPath%metadata"
)
But this solution write the full path. I tried this to remove the path:
set str=%%F:%LibPath%=%
But it does not seem to handle variable SET or the %%F variable too well inside a for-loop.
Is it even possible? Would like to not have to write a C# executable for this.
Thanks in advance!
Try the following:
#echo off
setlocal enabledelayedexpansion
set "dir=\\OtherComputer\MyFiles\"
FOR /F "tokens=*" %%f IN ('dir /s /b /A-d "%dir%"') do (
set "full=%%f"
echo !full:*%dir%=!
)
setlocal enabledelayedexpansion, in addition to creating a localized environment, turns on delayed expansions of variables, which allows variables to be modified inside the for loop's body and used with their modified values. (see help set). Note that in order for a variable to be expanded dynamically, you must enclose it in !, not %; e.g., !full! instead of %full%.
Note: A side effect of enabling delayed expansion is that any ! characters are interpreted as part of a variable reference, resulting in potentially unwanted removal of ! chars. from strings, such as in echo hi!. To output a literal ! while delayed expansion is enabled, use ^^! in unquoted strings, and ^! in double-quoted strings. Furthermore, literal ^ chars. in double-quoted strings then have to be represented as ^^.
dir /s /b /A-d "%dir%" lists all files - and files only, due to excluding directories with /A-d - in the current subtree (/s), as paths only (b). Note that using /s implies that full paths are output.
set "full=%%f" sets aux. variable full to the absolute path being processed in the current loop iteration.
!full:*%dir%=! then strips the input dir.'s path from the absolute path using prefix string substitution, leaving the relative path desired (again, see help set).
Just to contrast this with a PowerShell (v3+) solution, which demonstrates how much more advanced PowerShell is compared to cmd.exe.:
$dir = '\\OtherComputer\MyFiles\'
(Get-ChildItem -File -Recurse $dir).FullName.replace($dir, '')
I have a way to to this with two bat files:
code1.bat: Looping through all the files in "C:\Mypath"
#echo off
FOR /F "tokens=*" %%G IN ('dir /s /b C:\Mypath\*.*') do (
CALL code2.bat %%G
)
code2.bat: removing the main path string
SET _var=%1
SET _endbit=%_var:*Mypath\=%
Echo %_endbit%
Probably can be done in one file... take a look at http://ss64.com/nt/
The xcopy commmand is capable of returning relative paths. If the /L switch is given, nothing is actually copied but all items are listed that would be copied without /L. The pushd command handles UNC paths correctly (type pushd /? in command prompt for details). So the following code snippet should do what you want:
#echo off
pushd "\\host\share\folder"
> "\path\to\listfile.txt" xcopy /L /Y /C /I /E ".\*.*" "%TMP%"
popd
The above code results in each line to be prefixed with .\. In addition, it returns a summary line like # File(s). The code below gets rid of all those artefacts:
#echo off
pushd "\\host\share\folder"
> "\path\to\listfile.txt" (
for /F "tokens=2 delims=:" %%I in ('
xcopy /L /Y /C /I /E "*.*" "%TMP%"
') do (
echo(%%I
)
)
popd
Here I changed the file pattern from .\*.* to *.* which results in outputs like Z:rel\path\to\item.ext (rather than .\rel\path\to\item.ext). The for /F loop parses the output of xcopy and removes everything up to the first :, so the drive letter Z: is deleted. Since the : is a forbidden character for file and directory names, it cannot appear in any of the paths. Since the summary line # File(s) does not contain any columns, it is not enumerated by for /F.
I'm trying to rename .jpg files which is in one of many subdirectories of e:\study\pubpmc\test\extracted.
I want to rename files to LastFolderName_ImageName.jpg.
(For example if Figure1.jpg is in e:\study\pubpmc\test\extracted\folder1
I want it to be renamed like this: folder1_Figure1.jpg)
So I need to take out the last folder name from the file's path.
Since it's my first time with batch scripting, I'm having a hard time.
I googled and made code similar to it
but it doesn't seem to work out.
Can you help me with it and tell me where I've done wrong?
Thank you! :)
#echo off
cd /D "e:\study\pubpmc\test\extracted"
for /r %%f in (*.jpg) do (
set mydir=%%~dpf
set mydir=%mydir:\=;%
for /f "tokens=* delims=;" %%i in (%mydir%) do call :LAST_FOLDER %%i
goto :EOF
:LAST_FOLDER
if "%1"=="" (
#echo %LAST%
goto :EOF
)
set LAST=%1
SHIFT
goto :LAST_FOLDER
)
JosefZ explains the obvious problems with your code, but he failed to point out a subtle problem, though his code fixed it:
FOR /R (as well as the simple FOR) begin iterating immediately, before it has finished scanning the disk drive. It is possible for the loop to reiterate the already named file! This would cause it to be renamed twice, giving the wrong result. The solution is to use FOR /F with command 'DIR /B', because FOR /F always processes the command to completion before iterating.
JosefZ also provides code that works for most situations. But there is a much simpler solution that works always:
#echo off
for /f "delims=" %%A in (
'dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"'
) do for %%B in ("%%A\..") do ren "%%A" "%%~nxB_%%~nxA"
The "%%A\.." treats the file name as a folder and walks up to the parent folder. So %%~nxB gives the name of the parent folder.
The command could be run as a long one liner, directly from the command line (no batch):
for /f "delims=" %A in ('dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"') do #for %B in ("%A\..") do #ren "%A" "%~nxB_%~nxA"
Avoid using :label and :: label-like comment inside (command block in parentheses). Using any of them within parentheses - including FOR and IF commands - will break their context.
Using variables inside (command block in parentheses). Read EnableDelayedExpansion: Delayed Expansion will cause variables to be expanded at execution time rather than at parse time [and CLI parses all the (command block in parentheses) at once]
Next script should work for you. Note rename statement is merely echoed for debugging purposes.
#ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion
set "fromFolder=e:\study\pubpmc\test\extracted"
rem my debug setting set "fromFolder=D:\path"
for /F "tokens=*" %%f in ('dir /B /S /A:D "%fromFolder%\*.*"') do (
set "mydir=%%~ff"
set "last=%%~nxf"
call :renameJPG
)
#ENDLOCAL
goto :eof
:renameJPG
rem echo "%mydir%" "%last%"
for /f "tokens=*" %%i in ('dir /B /A:-D "%mydir%\*.jpg" 2^>nul') do (
echo ren "%mydir%\%%~nxi" "%last%_%%~nxi"
)
goto :eof
Resources:
SETLOCAL, disableDelayedExpansion, ENDLOCAL etc.
An A-Z Index of the Windows CMD command line
Windows CMD Shell Command Line Syntax
I already wrote a function for that. You give it any path and it returns you only it's filename or pathname. Works for any path: Url, Windows path, Linux path, etc...
Copy this function at the end of your batch script: (Instructions below)
rem ===========================================================================
:Name_From_Path
SetLocal
set _TMP_FOLDERNAME=%1
for %%g in ("%_TMP_FOLDERNAME%") do set _TMP_FOLDERNAME=%%~nxg
EndLocal & set _Name_From_Path=%_TMP_FOLDERNAME%
goto :EOF
rem ===========================================================================
Usage:
CALL :Name_Of_Path e:\study\pubpmc\test\extracted\folder1
ECHO %_Name_From_Path%
Result: folder1
If your program or com file traverses these folders when renaming, then it should be able to get the present working directory ( path ), pwd. You may be able to chop everything but the LAST_FOLDER out of this by also creating a PREVIOUS_FOLDER and doing a string replacement.
Or you may be able to break the folder names at the '\' token from the pwd into an array and use a -1 array reference to get the last folder name.
In any circumstance you'll want to check for a present working directory command.
If your creating a large text list of all these and issuing a single call to the batch file.
Then you may be better off with something like:
(Symmantic code warning )
(copy) /folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (to) /folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg
Instead of copy, window uses rename, linux uses mv.
The latter example would require simply creating a duplicate list and replacing the \ with a _ while parsing through the tokens.
The code you've given is difficult to make sense of, so its hard to discern if you can simple concatenate the current folder and image name (stringify) and then write or rename them where they are.
Happy Friday Think-Tank!
I need some assistance with a Batch .BAT script. Specifically I need help with some "IF statement syntax"
I have a script that is renaming files. There are two files, one ending in four digits and the other ending in five digits. The files will be renamed with variables I have already pre-set earlier within my script.
So here is a scenario: We have two files in a directory located at
c:\Users\username\Desktop\test-dir
There are two files within test-dir:
file1.12345
file2.1234
A four digit ending is one variable type (VAR1), whereas a file ending in five digits is another variable type (VAR2).
I need an if statement to:
a) read all the files(s) with the chosen directory (without using a wildcard if possible).
b) determine based on the number of digits after the "." which variable to use.
c) once making that determination rename the file with the appropriate variables.
The final re-naming convention is as so: yyyymmddtype.1234/12345
So basically it would use the datestamp variable I already created, the type variable I already created to be injected by the if statement, and append with the original ending digits of the file.
I know this seems like a lot, but I am more so a bash script guy. I have all the elements in place, I just need the if statement and what feels like a for loop of some kind to tie it all together.
Any help would be great!
Thank you!
Sorry, not the option you where asking for. Instead of iterating over the full list checking each file for extension conformance, iterate over a list of patterns that will filter file list, renaming matching files with the asociated "type"
for %%v will iterate over variable list, for %%a will split the content of the variable in pattern and type, for %%f will generate the file list, filter with findstr using the retrieved pattern and rename matching files with the corresponding "type"
Rename command is preceded with a echo to output commands to console. If the output is correct, remove the echo to rename the files.
#echo off
rem Variables defined elsewhere
set "folder=c:\somewhere"
set "timestamp=yyyymmdd"
rem Rename pattern variables in the form pattern;type
set "var1=\.....$;type1"
set "var2=\......$;type2"
set "var1=\.[^.][^.][^.][^.]$;type1"
set "var2=\.[^.][^.][^.][^.][^.]$;type2"
setlocal enableextensions disabledelayedexpansion
for %%v in ("%var1%" "%var2%") do for /f "tokens=1,* delims=;" %%a in ("%%~v") do (
for /f "tokens=*" %%f in ('dir /a-d /b "%folder%" ^| findstr /r /c:"%%~a"') do (
echo ren "%folder%\%%~f" "%timestamp%%%~b%%~xf"
)
)
endlocal
#ECHO OFF &SETLOCAL
set "yyyymmdd=yyyymmdd"
set "VAR1=VAR1"
set "VAR2=VAR2"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\....."') do echo(ren "%%~a" "%yyyymmdd%%VAR1%%%~xa"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\......"') do echo(ren "%%~a" "%yyyymmdd%%VAR2%%%~xa"
remove echo( to get it working.
If I understand you then this will rename the two files using preset variables for each one:
for %%a in ("%userprofile%\Desktop\test-dir\*") do (
if "%%~xa"==".12345" ren "%%a" "%variableA%-%variableB%%%~xa"
) else (
ren "%%a" "%variableC%-%variableD%%%~xa"
)
)