I'm trying to rename the latter part of a file, before the extension, in a batch script.
For instance:
block1.txt --> block1-%mydate%-%mytime%.txt
block2.zip --> block2-%mydate%-%mytime%.txt
The file name is passed to the program as %1. Only one file name will be changed per run. The program is intended to append a time-stamp to the end of a file, in the form of MMDDYYYY-HHMM.
The first part of the program produces the expression %mydate%-%mytime%.
I can't for the life of me figure out how to do it in a generic and consistently functional way.
Any help?
Did you mean: FileName-MMDDYYYY-HHSS.*
for /f "tokens=2-7 delims=/:. " %%a in ("%date% %time: =0%") do set newFileName=%~n1-%%a%%b%%c-%%d%%f%~x1
ren "%~1" "%newFileName%"
Or did you mean: FileName-MMDDYYYY-HHMM.*
for /f "tokens=2-6 delims=/:. " %%a in ("%date% %time: =0%") do set newFileName=%~n1-%%a%%b%%c-%%d%%e%~x1
ren "%~1" "%newFileName%"
For Windows here is what #hobodave answered to a similar question:
For command-line
for /F %i in ("c:\foo\bar.txt") do #echo %~ni
output: bar
For .bat Files
set FILE=bar
for /F %%i in ("%FILE%") do #echo %%~ni
output: bar
Further Reading:
http://www.computerhope.com/forhlp.htm
For Unix
You can use the basename command. It will clear path and extension from a given path.
basename /foo/bar/arch.zip .zip
Will output
arch
Basename manual: http://unixhelp.ed.ac.uk/CGI/man-cgi?basename
Related
Is there a way to list all executables available with your current PATH (environment variable) setting with a batch file?
I've been trying for a while and I can't seem to find a way (i ain't no batch intellectual).
Please help if you can even a link to an article can be useful.
Thank you!
surprisingly simple:
for %a in (%pathext%) do where *%a
the %pathext% lists all defined file extension that are executable (.exe, .bat, ...) and where lists all findings within the %path%
Note: this is command line syntax. For use in a batch file, use %%a instead of %a
As an addition to the already provided answer, and as a result of #aschipfl's comment, the following should use only the locations defined in the %Path% environment variable, and not include the current directory, (unless that itself was in %Path%).
From the Command Prompt:
For %A In (%PathExt%) Do #Where $Path:*%A 2>Nul
And from a batch file:
#For %%A In (%PathExt%) Do #Where $Path:*%%A 2>Nul
Obviously if you were only looking for .exe files as opposed to executables it would be much simpler:
Where $Path:*.exe 2>Nul
An alternative is to solely use CMD's native facilities without relying on external executables, which can also be used on older versions of windows like Windows XP where Where.exe is not available.
In a batch file:
#echo off
setlocal DisableDelayedExpansion
for %%D in ("%PATH:;=";"%") do (
for /F "eol=* delims=" %%F in ('cd /d "%%~D" 2^>nul ^&^& dir /b/a-d %PATHEXT:.=*.% 2^>nul') do (
for %%F in ("%%~D\%%F") do echo %%~fF
)
)
Technically, The innermost FOR is not vital, It is just to handle the anomalies that sometimes could be seen in the PATH environment variable, like where some path elements have trailing backslash, to output file paths in the standard format.
Because of it's length, Its not suited well for using at Command Prompt, however with my tests and to my sureprise, it is faster than the equivalent solution with Where.
One-liner for use at Command Prompt (For the sake of completeness):
#for %D in ("%PATH:;=";"%") do #for /F "eol=* delims=" %F in ('cd /d "%~D" 2^>nul ^&^& dir /b/a-d %PATHEXT:.=*.% 2^>nul') do #for %F in ("%~D\%F") do #echo %~fF
I am trying to create a batch file:
The batch file will locate the path of executable first. Then, the path will be stored in a variable for later use.
This is my code:
#echo off
setlocal
set directoryName=dir/s c:\ABCD.exe
rem run command
cmd /c %directoryName%
pause
endlocal
The command prompt does return me with the executable's path but the path is not stored in the variable. Why is it so?
Reading your question, it appears that you're not really wanting to save the path of the executable file at all, but the file name complete with it's full path:
I prefer the Where command for this type of search, this example searches the drive in which the current directory resides:
#Echo Off
Set "mPth="
For /F "Delims=" %%A In ('Where /R \ "ABCD.exe" /F 2^>Nul'
) Do Set "mPth=%%A"
If Not Defined mPth Exit /B
Rem Rest of code goes here
The variable %mPth% should contain what you need. I have designed it to automatically enclose the variable value in doublequotes, if you wish to not have those, change %%A on line 4 to %%~A. If the file is not found then the script will just Exit, if you wish it to do something else then you can add that functionality on line 5.
Note: the code could find more than one match, if it does it will save the variable value to the last one matched, which may not be the one you intended. A robust solution might want to include for this possibility.
Edit (this sets the variable, %mPth% to the path of the executable file only)
#Echo Off
Set "mPth="
For /F "Delims=" %%A In ('Where /R \ "ABCD.exe" /F 2^>Nul'
) Do Set "mPth=%%~dpA"
If Not Defined mPth Exit /B
Set "mPth=%mPth:~,-1%"
Rem Rest of code goes here
Lets walk through your code
set directoryName=dir/s c:\ABCD.exe
This fills the variable directory name with the value dir/s c:\ABCD.exe.
cmd /c %directoryName%
This executes the command in directoryname. There is no line in your code that saves the files location to a variable.
Extracting the path of a file can be done as follows
#echo off
setlocal
set executable=c:\location\ABCD.exe
FOR %%A IN ("%executable%") DO Set executablepath=%%~dpA
echo executablepath: %executablepath%
pause
endlocal
%executablepath% will contain c:\location\
The value that you are assigning to directoryname is dir /s c:\abc.exe.
this value is then substituted for %directoryname% in your cmd line, which executes the command dir/s..., showing you the location(s) of abc.exe in the familiar dir format.
If what you want is just the directoryname in directoryname, then you need
for /f "delims=" %%a in ('dir /s /B /a-d "c:\abc.exe"') do set "directoryname=%%~dpa"
which will first execute the dir command, then process each line of output from that command and assign it in its entirety to %%a.
The dir command shown would "display" the matching names found in the nominated directory (c:\) and its subdirectories (/s) in basic form (/b) - that is, names only, no size or date or report-headers or report-footers, and a-d without directorynames (should they match the "mask" abc.exe)
The delims= option to the for /f command instructs that the entire line as output by the command in single-quotes, be assigned to %%a.
When the result is assigned to the variable directoryname, only the Drive and Path parts are selected by using the ~dp prefix the the a.
Note that only the very last name found will be assigned to the variable as any earlier assignment will be overwritten by a succeeding assignment.
This may or may not be what you are looking for. This script searches through the PATH variable and looks for files that have and extension in the PATHEXT variable list.
#SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
#SET EXITCODE=1
:: Needs an argument.
#IF "x%1"=="x" (
#ECHO Usage: %0 ^<progName^>
GOTO TheEnd
)
#set newline=^
#REM Previous two (2) blank lines are required. Do not change!
#REM Ensure that the current working directory is first
#REM because that is where DOS looks first.
#PATH=.;!PATH!
#FOR /F "tokens=*" %%i in ("%PATH:;=!newline!%") DO #(
#IF EXIST %%i\%1 (
#ECHO %%i\%1
#SET EXITCODE=0
)
#FOR /F "tokens=*" %%x in ("%PATHEXT:;=!newline!%") DO #(
#IF EXIST %%i\%1%%x (
#ECHO %%i\%1%%x
#SET EXITCODE=0
)
)
)
:TheEnd
#EXIT /B %EXITCODE%
Note that this may find multiple executables. It may also find multiple types of executables. The current directory is also included first since that is what the shell, cmd.exe, does.
M:>whence wc
.\wc.BAT
.\wc.VBS
C:\Users\lit\bin\wc.BAT
C:\Users\lit\bin\wc.VBS
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'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.
I want to scan a folder whose path is defined by user input & finally apply ffmpeg to store all media files information into a text file. The following code does not work
#echo off
setLocal EnableDelayedExpansion
set /P "path=Enter folder path: "
dir %path% /B /O:N | findstr ".wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$" >filename.txt
echo. >info.txt
for /f "tokens=* delims= " %%a in ('type filename.txt') do (
set in=%in%%%a
ffprobe "%path%!in!" 2>>info.txt
)
pause
However if I strip user input as follows the code does work?
#echo off
setLocal EnableDelayedExpansion
::set /P "path=Enter folder path: "
dir d:\Trainers\out\outt\ /B /O:N | findstr ".wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$" >filename.txt
echo. >info.txt
for /f "tokens=* delims= " %%a in ('type filename.txt') do (
set in=%in%%%a
ffprobe "d:\Trainers\out\outt\!in!" 2>>info.txt
)
pause
The above script is placed in the folder containing ffprobe.exe & it successfully creates two txt files in the same directory
Note that d:\Trainers\out\outt\ is the directory to scan for media files & not the directory from where this bat file is executed
The basic syntax for ffprobe is
ffprobe "videofile"
Use a different variable name than path.
PATH already does something really important. So important, in fact, that your changing it is precisely why the script is breaking.
More specifically, when you try to execute a program using just a filename (no path at all), if the program cannot be found in the working directory, the contents of the PATH environment variable are searched. I haven't seen the error message you're getting, but it's probably failing to execute findstr, which is an executable typically found in a folder specified in PATH.
The user input command looks like the wrong context. Drop the quotes and it should work properly. The quotes are not needed to separate your prompt from your user input.