I am trying to move files after sorting the files from one folder to another folder but I am always getting this exception "The System cannot find the path specified"
Below is my batch command code:
setlocal EnableDelayedExpansion
set destinationFolder=C:\Test_Actual_Queue
rem Create an array with filenames in right order
for /f "tokens=*" %%f in ('dir /b "C:\Test Print Queue\" ^| sort') do (
echo %%f
move %%f %destinationFolder%
)
pause
I am able to sort and display the file names in console but when I try to move to the destination folder , I am getting the above mentioned exception.
Both the folder paths are correct.
I tried debugging and this is the data I am getting in the console:
C:\TestFoder>setlocal EnableDelayedExpansion
C:\TestFoder>set destinationFolder=C:\Test_Actual_Queue
C:\TestFoder>rem Create an array with filenames in right order
C:\TestFoder>for /F "tokens=*" %f in ('dir /b "C:\Test Print Queue\" | sort') do (
echo %f
move %f C:\Test_Actual_Queue
)
C:\TestFoder>(
echo data1.Print_Job
move data1.Print_Job C:\Test_Actual_Queue
)
data1.Print_Job
The system cannot find the file specified.
C:\TestFoder>(
echo data2.Print_Job
move data2.Print_Job C:\Test_Actual_Queue
)
data2.Print_Job
The system cannot find the file specified.
what am I doing wrong here?
Looking forward to your solutions. Thanks in advance.
The command DIR with the arguments /b and "C:\Test Print Queue\" outputs just the names of all non hidden files and directories in specified directory without path. The current directory on execution of the batch file is C:\TestFoder which is a different directory than C:\Test Print Queue. For that reason the command MOVE cannot find the file/directory to move stored in C:\Test Print Queue specified without path in current directory C:\TestFoder and outputs the error message.
The command DIR would output the file/folder names with full path if additionally option /S is used to search also in subdirectories.
One solution is specifying source path also on MOVE command line:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test Print Queue"
set "DestinationFolder=C:\Test_Actual_Queue"
set "CreatedFolder="
if not exist "%DestinationFolder%\" (
md "%DestinationFolder%" 2>nul
if not exist "%DestinationFolder%\" (
echo Error: Failed to create folder "%DestinationFolder%"
goto EndBatch
)
set "CreatedFolder=1"
)
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /ON "%SourceFolder%\*" 2^>nul') do (
echo Moving file "%SourceFolder%\%%I" ...
move "%SourceFolder%\%%I" "%DestinationFolder%\"
)
if defined CreatedFolder rd "%DestinationFolder%" 2>nul
:EndBatch
endlocal
pause
Command extensions are explicitly enabled as required for for /F although enabled by default. Delayed environment variable expansion is explicitly disabled as not needed for this task. Files with one or more exclamation marks in file name could not be successfully processed within the FOR loop if delayed environment variable expansion is enabled explicitly although not enabled by default and not needed here. Read this answer for details about the commands SETLOCAL and ENDLOCAL.
The batch file first creates the destination folder if not already existing with verifying if folder creation was successful.
The command FOR executes the command line
dir /A-D-H /B /ON "C:\Test Print Queue\*" 2>nul
in a background command process started with cmd.exe /C.
Command DIR outputs
just non hidden files because of /A-D-H which means all directory entries not having attribute directory or hidden set
in bare format because of /B which means just the file name with file extension and without file path
sorted by name because of /ON
found in directory C:\Test Print Queue matching the wildcard pattern * (any file).
It is possible that the source directory does not exist at all or does not contain any file matching the criteria. The error message output in these cases by DIR is suppressed by redirecting it from handle STDERR to device NUL.
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR with option /F as used here captures everything written to handle STDOUT of background command process and then processes the captured text line by line.
Empty lines are ignored by FOR, but DIR with the used options does not output empty lines at all.
Lines starting with ; would be also ignored by default by FOR. File names can start with a semicolon. For that reason option eol=| is used to change the end of line character from semicolon (default) to a vertical bar which a file name can't contain at all.
FOR would split up each line into substrings (tokens) using the default delimiters space and horizontal tab and would assign to loop variable I just the first space/tab delimited string. This splitting behavior is not wanted here and so option delims= is used to define an empty list of delimiters to disable the line splitting and get assigned to I always the entire file name even on containing one or more spaces. tokens=* could be also used to get entire line (= file name) assigned to I.
For each file output by DIR with name and extension, but without path, the name of the file is output and command MOVE is executed to move the file to destination folder without overwriting a file with same name in that folder because of option /Y is not used here.
Finally the batch file deletes the destination folder if it was created by the batch file and if it is still empty because there was no file to move at all.
Another solution would be changing the current directory to source directory.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
cd /D "C:\Test Print Queue" || goto EndBatch
set "DestinationFolder=C:\Test_Actual_Queue"
set "CreatedFolder="
if not exist "%DestinationFolder%\" (
md "%DestinationFolder%" 2>nul
if not exist "%DestinationFolder%\" (
echo Error: Failed to create folder "%DestinationFolder%"
goto EndBatch
)
set "CreatedFolder=1"
)
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /ON 2^>nul') do (
echo Moving file "%%I" ...
move "%%I" "%DestinationFolder%\"
)
if defined CreatedFolder rd "%DestinationFolder%" 2>nul
:EndBatch
endlocal
pause
If command CD fails to change the current directory to source directory because of not existing, the well known error message is output:
The system cannot find the path specified.
Then the batch file jumps to the label EndBatch to restore previous environment and halt batch file execution until user presses any key.
On successfully changing the current directory the batch file continues and with command ENDLOCAL the initial current directory C:\TestFoder is set again as current directory for the command process executing the batch file.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cd /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
move /?
pause /?
rd /?
set /?
setlocal /?
Related
File: stack.bat
#echo off
#setlocal enabledelayedexpansion
for %%a in (%*) do (
call set "%%~1=%%~2"
shift
)
ECHO para1 %--para1%
ECHO para2 %--para2%
if "%--para2%"=="" (
echo missing para2
for /f "eol=: delims=" %F in ('dir /b/o:N %--folder%\*.001') do #set "newest=%F"
echo latest %newest%
)
This batch file is called with:
stack.bat --para1 c:\Sample\temp
The execution results in output of the error message:
N was unexpected at this time.
There is no error if the line for /f "eol=: ... is commented out with command REM.
Delayed expansion is already enabled.
What do I need to do to fix the error?
It is not described what the batch file code should do at all. It looks like it should find the newest file by its name containing most likely a date string in name in a directory passed as argument to the batch file and should define an environment variable with name passed also as argument left to the directory path with the file name of newest file.
I suggest following commented batch code for this purpose:
#echo off
rem Remove this line if the environment variables defined by this batch
rem file should still exist after processing of this batch file finished.
setlocal EnableExtensions DisableDelayedExpansion
rem Delete all environment variables of which name starts with --.
for /F "delims=" %%I in ('set -- 2^>nul') do set "%%I"
:ProcessArguments
rem Get current first argument (option) with surrounding " removed.
set "Option=%~1"
rem Is there no more option?
if not defined Option goto EndBatch
rem Remove all double quotes from the option.
set "Option=%Option:"=%"
rem This condition is just for 100% fail safe code. It should be never true.
if not defined Option goto EndBatch
rem Does the option not start with two hyphens?
if not "%Option:~0,2%" == "--" (
echo ERROR: Invalid option: "%Option%"
echo/
goto EndBatch
)
rem Get current second argument (folder path) with surrounding " removed.
set "Folder=%~2"
rem Is there no folder path?
if not defined Folder goto MissingFolder
rem Remove all double quotes from the folder path.
set "Folder=%Folder:"=%"
rem This condition is just for 100% fail safe code. It should be never true.
if not defined Folder goto MissingFolder
rem Replace all / in folder path by \ as many users type folder paths wrong
rem with slashes as on Linux/Mac instead of backslashes as required on Windows.
set "Folder=%Folder:/=\%"
rem Make sure the last character of folder path is a backslash.
if not "%Folder:~-1%" == "\" set "Folder=%Folder%\"
rem Search in specified folder for *.001 files output reverse by name and
rem define the option as environment variable with first output file name
rem assigned with full qualified absolute path even if environment variable
rem Folder referencing a relative path. Then shift the arguments list by
rem two arguments to the left and process the remaining arguments.
for /F "eol=| delims=" %%I in ('dir "%Folder%*.001" /A-D /B /O-N 2^>nul') do (
for %%J in ("%Folder%%%I") do set "%Option%=%%~fJ"
shift
shift
goto ProcessArguments
)
rem It is not possible to define an environment variable with no string.
rem So an error message is output if no file could be found like on
rem wrong folder path or no *.001 file found in the specified folder.
echo ERROR: Could not find a *.001 file for option "%Option%" in folder:
echo "%Folder%"
echo/
goto Endbatch
:MissingFolder
echo ERROR: Missing folder path for option: "%Option%"
echo/
:EndBatch
set "Option="
set "Folder="
echo Options parsed successfully:
echo/
set -- 2>nul
rem Remove this line if the environment variables defined by this batch
rem file should still exist after processing of this batch file finished.
endlocal
This batch file can be started for example with the command line:
stack.bat --para1 c:\Sample\temp "--para2" "C:/Temp/Development & Test!/" --para3 . --para4 "\Program Files\Internet Explorer\" -para5 .."
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains how to reference batch file arguments
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
shift /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /c and the command line within ' appended as additional arguments.
I suggest also reading:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
This question with its answers should be read first by every beginner in batch file coding.
Problems checking if string is quoted and adding quotes to string
This answer explains very detailed how to process arguments passed to a batch file.
Syntax error in one of two almost-identical batch scripts: ")" cannot be processed syntactically here
This answer describes common issues made by beginners in batch file coding and how to avoid them.
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
Another extensive answer which describes how to work with environment variables in batch files.
Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files
This also very long answer describes in detail how a string comparison is done by Windows command processor and what a batch file writer must take into account on using string comparisons.
I am trying to convert a number of .doc files into .docx files and I found a solution:
for %F in (*.doc) do "C:\Program Files\Microsoft Office\Office12\wordconv.exe" -oice -nme "%F" "%Fx"
For the detailed info see: Automation: how to automate transforming .doc to .docx?
Now I want to use the absolute path of wordconv.exe as an input parameter.
Then my approach is like this:
The contents of doc2docx.bat:
for %F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
Run doc2docx.bat in console with:
doc2docx.bat "C:\Program Files\Microsoft Office\Office12\wordconv.exe"
I got the result below:
D:\book\work\temp\5. SPEC_NEW>D:\book\doc2docx.bat "C:\Program Files (x86)\Microsoft Office\Office12\Wordconv.exe"
此时不应有 1。
D:\book\work\temp\5. SPEC_NEW>for 1 -oice -nme "Fx")
D:\book\work\temp\5. SPEC_NEW>
The message 此时不应有 1。 means '1' was unexpected at this time.
How could I solve it?
I know little about batch script coding.
I recommend to open a command prompt, run for /? and read the output help from top of first to bottom of last page. There is already written in fourth paragraph that in a batch file the loop variable must be referenced with doubling the percent sign in comparison to usage of command FOR directly on Windows command prompt.
So the solution could be:
for %%F in (*.doc) do %1 -oice -nme "%%F" "%%~nF.docx"
But I can't recommend to use this command line in the batch file because of following reasons.
Reason 1 is explained in detail by this answer by the chapter Issue 7: Usage of letters ADFNPSTXZadfnpstxz as loop variable. It is possible to use these letters for a loop variable, but it is advisable not doing that. There are lots of other ASCII characters with no special meaning which are always safe to use as loop variable.
Reason 2 is that command FOR searches with *.doc in current directory for files with .doc in long or in short file name. So if the directory contains Test1.doc and Test2.docx, FOR runs the converter executable with both file names as it can be seen on running in the command prompt window the command line:
for %I in (*.doc) do #echo Long name: %I - short name: %~snxI
The output for a directory containing Test1.doc and Test2.docx is:
Long name: Test1.doc - short name: TEST1.DOC
Long name: Test2.docx - short name: TEST2~1.DOC
Reason 3 is often problematic on FAT32 and exFAT drives, but is sometimes even a problem on NTFS drives. FOR accesses the file system on processing the files matched by the wildcard pattern after each iteration. There is executed in background _findfirst, _findnext, _findnext, ..., _findclose. The problem is that the directory entries change because of the conversions of the Microsoft Word files as the *.docx files are created in same directory as the processed *.doc files. All file systems return the file names as stored in their table. The difference is that the NTFS master file table is locale specific sorted by name while the table of FAT32 and exFAT is not sorted at all and so changes dramatically with each creation or deletion of a file or folder in a directory. For that reason it could happen that some .doc files are processed more than once and others are skipped and even an endless running loop could be the result. In other words the FOR loop behavior is undefined in this case and so the loop could work by chance, but could also fail.
The solution is using the command line:
for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe *.doc 2^>nul') do %1 -oice -nme "%%I" "%%~dpnI.docx"
Problem 1 is avoided by using I as loop variable. It would be also possible to use # or B or J and lots of other ASCII characters.
FOR with option /F and a set enclosed in ' results in starting in background one more command process with %ComSpec% /c and the command line within ' appended as additional arguments. Therefore it is executed in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c C:\Windows\System32\where.exe *.doc 2>nul
WHERE is different to FOR or DIR. It searches only in long file name for files with extension .doc. So problem 2 with matching also files with file extension .docx is avoided by using command WHERE which outputs the found files matching the wildcard pattern with full qualified file name (drive + path + name + extension).
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded where command line with using a separate command process started in background.
Everything written by where to handle STDOUT (standard output) of started background command process is captured by cmd.exe processing the batch file. The captured lines are processed after started cmd.exe terminated itself after where.exe finished. For that reason the problem 3 is avoided as the list of file names with file extension .doc does not change anymore on running the conversion. The file names list is already completely loaded into memory of cmd.exe before starting processing them.
FOR with option /F results by default in ignoring empty lines, splitting up each line into substrings using normal space and horizontal tab as string delimiters, ignoring the line if the first space/tab delimited string starts with a semicolon, and otherwise assigning just first space/tab delimited string to the specified loop variable. This default line processing behavior is not wanted here because of the full qualified file names can contain one or more spaces. The option string "delims=" defines an empty list of delimiters which results in disabling the line splitting behavior completely. where outputs the file names with full path and so no captured line can have a ; at beginning and for that reason the implicit default eol=; can be kept in this case. Otherwise on using a different command line resulting in captured lines being just the names of the files matching a wildcard pattern eol=| or eol=? could be used as neither | nor ? can be used in a file name to avoid that files of which name starts unusually with ; are ignored by FOR.
I suggest to use the following batch file which searches itself for wordconv.exe by using the path stored in Windows registry for winword.exe or excel.exe or powerpnt.exe added by the installer of Office for Application Registration on being started with no file name of an executable.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
goto Main
:GetConvertToolName
for %%# in (winword excel powerpnt) do (
for /F "skip=2 tokens=1,2*" %%I in ('%SystemRoot%\System32\reg.exe query "%~1\%%#.exe" /v Path') do (
if /I "%%I" == "Path" if exist "%%~K\wordconv.exe" for %%L in ("%%~K\wordconv.exe") do set "ConvertTool=%%~fL" & goto :EOF
)
)
goto :EOF
:Main
set "ConvertTool="
if not "%~1" == "" if exist "%~1" if /I "%~x1" == ".exe" set "ConvertTool=%~1"
if not defined ConvertTool call :GetConvertToolName "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths"
if not defined ConvertTool call :GetConvertToolName "HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths"
if not defined ConvertTool (
echo ERROR: Failed to find the program wordconv.exe.
echo/
echo Please run %~nx0 with full name of wordconv.exe as argument.
echo/
pause
) else for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe *.doc 2^>nul') do "%ConvertTool%" -oice -nme "%%I" "%%~dpnI.docx"
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
reg /?
reg query /?
set /?
setlocal /?
where /?
The command line:
for %F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
should read:
for %%F in (*.doc) do ("%~1" -oice -nme "%%F" "%%Fx")
to fixe syntax errors (doubled %-symbols in a batch file as stated in the help of for /?) and to properly handle quotation.
But there is still room for improvement:
The pattern *.doc may even match *.docx files when you have short 8.3 file names enabled on your system (because a file called some long name.docx has got a short name like SOMELO~1.DOC, which dir regards too).
Files may already have been converted, hence a check if there already exists a respective *.docx file might be helpful.
There might no argument be provided.
The following code regards these issues:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Check whether first argument points to an existing file:
if exist "%~1" (
rem // Change into target directory:
pushd "D:\path\to\root\directory" && (
rem /* Instead of a standard `for` loop, use `for /F` over `dir /B` to gain the possibility
rem to apply an additional filter by `findstr` to avoid `*.docx` to match: */
for /F "delims= eol=|" %%F in ('dir /B /A:-D-H-S "*.doc" ^| findstr /I "\.doc$"') do (
rem // Check whether there is already a respective `*.docx` file:
if not exist "%%~nF.docx" (
rem // Attempt to convert the current `*.doc` file to `*.docx`:
"%~1" -oice -nme "%%F" "%%Fx"
)
)
rem // Return from target directory:
popd
)
) else (
rem // Raise an error in case the first argument does not point to an existing file:
>&2 echo "%~1" not found!
exit /B 1
)
endlocal
exit /B
for %%F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
Batch is interpreting %F in (*.doc) do (% as a variable which, unsurprisingly, has no value hence it executes
for 1 -oice -nme "%F" "%Fx")
Which explains your error message as 1 is not expected after for.
The metavariable (F in this case) within a batch must be %%F. Only if run directly from the prompt, is it %F.
I'm trying to create a batch script that will zip all the contents in each subdirectory except the latest (or latest few). I'm currently attempting in Windows with 7-Zip but the directory is technically on a Linux server so any suggestions geared towards a Linux command is welcome.
The directory structure is like this:
Directory-Parent
---Sub-Directory-1
--------File1
--------File2
--------File3
---Sub-Directory-2
--------File1
--------File2
I would like to run a batch at the Directory-Parent level that will create a zip in each sub-directory of all the files except the latest 1 (or few if possible). I also want to add the year to the end of the zip file name.
So the result would be:
Directory-Parent
-Sub-Directory-1
--------File1
--------Sub-Directory-12019.zip
---Sub-Directory-2
--------File1
--------Sub-Directory-22019.zip
I've tried a nested for loop but can't seem to get it. I've tried the for command with skip and dir in the set (IN), but can't get it to work.
I currently have the following script.
SET theYear=2019
For /D %%d in (*.*) do 7z a "%%d\%%d%theYear%.zip" ".\%%d\*"
This accomplishes it all except I don't know how to exclude the latest file (newest file according to last modification time) in each folder.
This batch file can be used for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FilesToIgnore=1"
set "theYear=%DATE:~-4%"
set "ListFile=%Temp%\%~n0.lst"
del "%ListFile%" 2>nul
for /D %%I in (*) do call :CompressFiles "%%I"
goto EndBatch
:CompressFiles
pushd %1
set "ZipFile=%~nx1%theYear%.zip"
for /F "skip=%FilesToIgnore% eol=| delims=" %%J in ('dir /A-D /B /O-D /TW 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /C:"%ZipFile%"') do >>"%ListFile%" echo %%J
if exist "%ListFile%" (
echo Compressing files in directory %1 ...
7z.exe a -bd -bso0 -i"#%ListFile%" -mx9 -scsDOS -- "%ZipFile%"
del "%ListFile%"
)
popd
goto :EOF
:EndBatch
endlocal
The batch file sets environment variable theYear dynamically from region dependent date string of dynamic environment variable DATE. Please execute in a command prompt window echo %DATE:~-4% and verify if output is the current year because of echo %DATE% outputs current local date with last four characters being the year.
The batch file ignores the FilesToIgnore newest files in each directory. Ignored is also the ZIP file if already existing from a previous execution of the batch file. The ZIP file is never included in number of FilesToIgnore because of filtered out already by findstr which filters output of command dir which outputs the file names without path in current directory ordered by last modification time with newest files output first and oldest files output last.
Please read help of 7-Zip for the used switches and parameters.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
popd /?
pushd /?
set /?
setlocal /?
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.
Update: 7-Zip version 19.00.0.0 outputs a warning and creates an empty ZIP file in each subdirectory on using the command line as written below and used initially in batch file. I first thought this is a bug of 7-Zip version 19.00.0.0 because of this version should support also -- according to its help and 7-Zip version 16.04.0.0 works on using the command line:
7z.exe a -bd -bso0 -mx9 -scsDOS -- "%ZipFile%" "#%ListFile%"
It was necessary to remove -- from this command line to get it working with 7-Zip version 19.00.0.0.
So I reported this issue and the author of 7-Zip quickly replied explaining why the usage of -- results in searching for a file starting with # in file name since 7-Zip version 19.00.0.0:
We need some way to add #file and -file names from command line.
So -- stops # and - parsing, and 7-Zip searches exact names.
It's more safe to use -i#listfile instead.
So I updated the batch file code and specify the list file with option -i which is the most safe method to specify a list file.
The following code is completely untested, so please be careful when executing:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "ROOT=Directory-Parent" & rem /* (set this to `%~dp0.` to specify the parent directory of the
rem batch file, or to `.` to for current working directory) */
set "YEAR=2019" & rem // (set the year just as a constant as it is unclear where to get it from)
set "MOVA=" & rem // (set this to `-sdel` if you want the files to be moved into the archive)
rem // Interate through the current working directory:
for /D %%d in ("%ROOT%\*.*") do (
rem // Clear exclusion parameter for `7z`, reset flag that indicates if there are files left:
set "EXCL=" & set "FLAG="
rem /* Iterate through all files in the currently iterated directory, sorted from
rem oldest to newest (`/O:D`), regarding the last modification date/time (`/T:W`);
rem the `findstr` part is to exclude the archive file itself if already present: */
for /F "delims= eol=|" %%f in ('
dir /B /A:-D /O:D /T:W "%%~d\*.*" ^| findstr /V /I /X /C:"%%~nxd%YEAR%.zip"
') do (
rem // Exclusion parameter is not yet set in first loop iteration:
if defined EXCL set "FLAG=#"
rem // Exclusion parameter becomes set at this point:
set "EXCL=-x!"%%f""
)
rem /* Flag is only set if there is one more file besides the one to exclude,
rem meaning that there are at least two files in total: */
if defined FLAG (
rem // Store folder information in variables to avoid loss of potentially occurring `!`:
set "FOLDER=%%~fd" & set "NAME=%%~nxd"
rem /* Toggle delayed expansion in order to be able to read variables that have been
rem set within the same block of parenthesised code (namely the `for` loops): */
setlocal EnableDelayedExpansion
rem // Execute the `7z` command line with dynamic parameters:
ECHO 7z a -bd %MOVA% !EXCL! -x^^!"!NAME!%YEAR%.zip" "!FOLDER!\!NAME!%YEAR%.zip" "!FOLDER!\*.*"
endlocal
)
)
endlocal
exit /B
I preceded the (potentionally dangerous) 7z command line by ECHO, just for safety purposes.
I am trying to find all the pictures on my computer and copy them all to just 1 folder. Here is the command I am using in Admin level Command Prompt.
C:>dir /s /b *.jpg | findstr /v .jpg > AllPics
For some reason I get this output: "Access is denied."
What can I do to fix this?
List the full path names of the JPG files in the current directory and all subdirectories:
dir /s /b *.jpg
Redirect the standard output stream of the dir command to the standard input stream of the findstr command. Exclude any file that contains .jpg (case sensitive) in the full path name:
| findstr /v .jpg
The result of the previous action seems to be counter-intuitive as it will negate a lot of output generated by the dir command.
Write the standard output stream of the findstr command to a file called AllPics (without a file extension) in the current directory:
> AllPics
The current directory seems to be set to the root of the C: drive. Because administrator privileges are required to save files directly to the root of the C: drive, you'll receive the "Access is denied" error message.
As pointed out by TripeHound, the "Access is denied" error might be caused because there already exists a folder named AllPics on the root of the C: drive.
One way to get the desired result is to parse each JPG file to the xcopy command:
setlocal
set "files=c:\*.jpg"
set "destDir=c:\AllPics"
for /f "delims=" %%f in ('dir "%files%" /b /s') do (
xcopy "%%f" "%destDir%\"
)
I've added another variant of the script that alters the destination name of the file to be copied which prevents potentially overwriting any possible duplicates.
setlocal enabledelayedexpansion
set "files=c:\*.jpg"
set "destDir=c:\AllPics"
for /f "delims=" %%f in ('dir "%files%" /b /s') do (
for %%d in ("%destDir%\%%~nf*") do (
set /a count+=1
)
xcopy "%%f" "%destDir%\%%~nf!count!%%~xf*"
set count=
)
Due to delayed expansion, the last variant of the script is unable to handle files that contain carets (^) within their fully qualified path name.
When a command-line contains environment variables that are expanded at execution time (like the count variable in this script), the entire command-line seems to be parsed twice. The for-loop variables (%%f and variants thereof) will be expanded during the first parse, the count variable is expanded during the second parse. Because the for-loop variables are already expanded when the second parse takes place, any singular carets present in the values of the for-loop variables are swallowed by the parser and omitted from the final result.
Here is the revision of the script that should take care of the problem described:
setlocal enabledelayedexpansion
set "type=.jpg"
set "source=c:\"
set "dest=c:\AllPics"
for /r "%source%" %%f in ("*%type%") do (
for %%d in ("%dest%\%%~nf*") do (
set /a count+=1
)
set "source=%%f"
set "dest=%dest%\%%~nf"
xcopy "!source!" "!dest!!count!%type%*"
set count=
)
I do this with WinRAR. Archive files from different folders with recursive scan, then extract in one folder (with e option, not x which restores the directory tree).
I need to analyze the results provided in a list of CSV files where I need to have the file name and its second line, this for the set of files of the result directory in a single output. I found on Stack Overflow a piece of code to get the file name and a piece of code to get the second line of a file. Frankly it is beyond my knowledge to patch them together.
This is what I have so far:
setlocal enabledelayedexpansion
#echo "filename secondline"
for /f "delims=" %%a in ('dir /b /s *.*') do (#echo %%~nxa
set filename=%%~a
echo %filename%
pause
for /f "tokens=1,* delims=:" %i% in ('findstr /n /r . %filename%') do(if %i% geq 2 if %i% leq 2 echo %j% )
rem pause
)
endlocal
How to get the file name and the second line of all CSV files in directory into another CSV file?
It is not very clear what you want. So let me add some information about what I understood.
There are some CSV files in a directory like C:\Temp which is the current directory on executing the batch file which contains for example:
C:\Temp\DataFile1.csv
first name,second name,address,country
John,Doe,"20 Baker Street, Nowhere",Fantasy Island
x,y,anywhere,anyland
C:\Temp\DataFile2.csv
first name,second name,address,country
Jane,Doe,"5 Hammer Lane, Somewhere",Happy Island
x,y,anywhere,anyland
And in same directory one more CSV file with name ExtractionResults.csv should be created containing finally for this example:
"C:\Temp\DataFile1.csv",John,Doe,"20 Baker Street, Nowhere",Fantasy Island
"C:\Temp\DataFile2.csv",Jane,Doe,"2 Hammer Lane, Somewhere",Happy Island
The file names in first column should be quoted in case of one of the CSV files have a comma in file name.
For such a task the following commented batch file could be used:
#echo off
rem Name of results file without file extension with or without path.
set "ResultsFileName=ExtractionResults"
rem Delete a perhaps already existing results file from a previous run.
del "%ResultsFileName%.csv" 2>nul
rem Delete also a perhaps already existing temporary results file from
rem a not completed previous run. A temporary file with a file extension
rem different to CSV is used for the results in case of results file is
rem created also in current directory with file extension CSV. This must
rem be done to avoid that the second line of the results file is included
rem in the results, too.
del "%ResultsFileName%.tmp" 2>nul
rem Call for each CSV file in current directory the subroutine
rem GetSecondLine with full name of the CSV file.
for %%I in (*.csv) do call :GetSecondLine "%%~fI"
rem Use command MOVE instead of RENAME to rename the file in case of results
rem file name is specified at top with an absolute or relative path as the
rem command RENAME does not allow as second parameter a file name with path.
move /Y "%ResultsFileName%.tmp" "%ResultsFileName%.csv"
rem Exit this batch file and return to parent batch file or command processor.
goto :EOF
rem This is a subroutine. It prints to the temporary results file
rem just the second line or nothing if the file contains just 1 line.
rem The execution of goto :EOF results here in exiting the subroutine.
:GetSecondLine
for /F "usebackq skip=1 delims=" %%L in ("%~1") do (
echo "%~1",%%L>>"%ResultsFileName%.tmp"
goto :EOF
)
goto :EOF
Well, the code above contains more comment lines than commands. But for an even better understanding of the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
del /?
for /?
goto /?
move /?
rem /?
And read also the Microsoft article Using command redirection operators for an explanation of >> and 2>nul.