I am using robocopy to copy from one directory to another.
I have tested the code using miscellaneous source directories but I get an error when executing one particular directory:
set "source=C:\Program Files (x86)\Phoresis\Backup"
I get the error:
Invalid paramter 3 "(x86)\Phoresis\Backup"
Have tried using single quotes and have wrapped the variable assignments in "" as there are spaces in the directory paths.
Code:
set "newDirectory=F:\Cap2 Flex Backup"
REM Timesatmp a new folder
set "DirName=%date:~-4,4%.%date:~-7,2%.%date:~0,2%.%time:~0,2%.%time:~3,2%
MD \%newDirectory%"
set "source=C:\Program Files (x86)\Phoresis\Backup"
robocopy %source% %DirName% /e /z /Mir
Struggling to get my head around spaces/special characters in vb scripts/batch so any input appreciated.
Cheers
The main issue in your code is, that there are no quotes "" around the source and destination directories in the robocopy command line. Since they contain spaces, such are interpreted as argument separators; so %source%, which is expanded to the value C:\Program Files (x86)\Phoresis\Backup, will be interpreted as three arguments C:\Program, Files and (x86)\Phoresis\Backup. To avoid that, put "" around the path arguments like "%source%".
Here is the fixed code:
set "newDirectory=F:\Cap2 Flex Backup"
md "%newDirectory%"
rem Timesatmp a new folder
set "DirName=%newDirectory%\%date:~-4,4%.%date:~-7,2%.%date:~0,2%.%time:~0,2%.%time:~3,2%"
set "source=C:\Program Files (x86)\Phoresis\Backup"
robocopy "%source%" "%DirName%" /e /z /Mir
Additional issues/notes:
although you used quotes in your set command lines, which avoid troubles with some special characters (&, ^, (, ), SPACE, etc.), the "" are not part of the values stored in the variables; so when expanding (reading) the variables, you need to take care of such special characters once again, by surrounding the read variable by "";
the md command has been fixed (there was a leading \, but no opening ") and moved up;
variable DirName contains now also the parent (root) destination directory F:\Cap2 Flex Backup, which is stored in variable newDirectory, to avoid relative paths for robocopy; since source contains an absolute path too, the script can be located and executed anywhere;
regard that the timestamp retrieved by %date% and %time% depend on the locale and region settings of the system; therefore this script is not quite portable; see this post to overcome that;
Related
I have the following batch file to make git diff invoke spreadsheet compare UI in windows. So I'm trying to pass the git diff's 2nd (old file) and 5th (new file) arguments to spreadsheet compare in order to make it compare the file using git diff.
So now, this batch file only successfully handles files with NO spaces in the file names, it CANNOT handle files with spaces in the file names.
What code should I add to this script to make this batch code handles file with spaces:
#ECHO OFF
set path2=%5
set path2=%path2:/=\%
ECHO %2 > tmp.txt
dir %path2% /B /S >> tmp.txt
C:/"Program Files"/"Microsoft Office"/root/vfs/ProgramFilesX86/"Microsoft Office"/Office16/DCF/SPREADSHEETCOMPARE.EXE tmp.txt
It currently throw errors like this:
Unhandled Exception: System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.GetFileName(String path)
at ProdianceExcelCompare.Form1.StatusReady()
at ProdianceExcelCompare.Form1.Init()
at ProdianceExcelCompare.Form1..ctor(String instructionFile)
at ProdianceExcelCompare.Program.Main(String[] args)
fatal: external diff died, stopping at London comparison.xlsx
See the following answers on Stack Overflow:
How to set environment variables with spaces?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
They explain the recommended syntax set "VariableName=variable value" to define an environment variable and the reasons recommending this syntax.
Why does ECHO command print some extra trailing space into the file?
It explains why the space character left to redirection operator > on an ECHO command line is also written into the file as trailing space and how to avoid this safely on variable text written into the file.
See also Microsoft documentation about Using command redirection operators.
On other command lines than ECHO a space left to > is usually no problem.
It is in general wrong to use multiple times " within an argument string like a file or folder path. There should be just one " at beginning and one " at end. This is explained by help of Windows command processor output on last help page on running in a command prompt window cmd /?.
The Microsoft documentation about Naming Files, Paths, and Namespaces explains that the directory separator on Windows is \ and not / and therefore / should not be used in batch files on Windows in file/folder paths.
The help output on running in a command prompt window call /? explains how the arguments of a batch file can be referenced with which modifiers.
The code rewritten according to information posted above and on the referenced pages:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
>"tmp.txt" echo %2
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
The first line in tmp.txt contains the second argument as passed to the batch file, i.e. without or with surrounding double quotes.
The following code is necessary to write the second argument safely always without " into file tmp.txt even on second argument passed to the batch file is "Hello & welcome!":
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
set "Argument2=%~2"
setlocal EnableDelayedExpansion
echo !Argument2!>"tmp.txt"
endlocal
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
>tmp.txt echo %~2 cannot be used as not working for something like "Hello & welcome!". Windows command processor would interpret the first string separated by normal space, horizontal tab, comma, equal sign, or no-break space (in OEM code pages) delimited string after & as command or application to execute as described by single line with multiple commands using Windows batch file.
"tmp.txt" could be written everywhere in both batch files also with just tmp.txt. But it is never wrong to enclose the complete file/folder argument string in double quotes even on not being really necessary because of the string does not contain a space or one of these characters &()[]{}^=;!'+,`~. So it is good practice to always enclose a complete file/folder argument string in double quotes. For example running a replace on both batch files searching for tmp.txt and using as replace string %TEMP%\%~n0.tmp would result in using instead of tmp.txt in current directory a temporary file with name of batch file as file name and file extension .tmp in directory for temporary files independent on what is the name of the batch file and what is the path of the directory for temporary files.
The last suggestion is reading this answer for details about the commands SETLOCAL and ENDLOCAL.
The temporary file should be also deleted finally before reaching an exit point for batch file execution.
You can use quotes as below:
It treats the string in quotes as a title of the new command window. So, you may do the following:
start "" "yourpath"
Found it in the below link :
https://ccm.net/forum/affich-16973-open-a-file-with-spaces-from-batch-file
I have the following code to copy files from a list. When the path of the files which the folder name has no space, it works perfectly. But the folder names could have space sometimes, how can I improve the code to handle the folder name with space
FOR /F %%a in (find_file_list.txt) DO COPY "%%a" "C:\test\%%~nxa"
Basically, in this find_file_list.txt, there list all files with path
c:\abc\def\12345.txt
c:\abc\def\12346.txt
c:\abc\def\12347.txt
the above code copy all these three files into folder of test and works fine.
Now when find_file_list.txt change, actually the real folder name has space in it, like
c:\ab c\de f\12345.txt
c:\ab c\de f\12346.txt
c:\ab c\de f\12347.txt
the above code not working anymore...
any thoughts?
You forgot to select the delims you want to split on:
FOR /F "delims=" %%a in (find_file_list.txt) DO COPY "%%a" "C:\test\%%~nxa"
Default delimeters are whitespace, if your file contains it, it will split on the whitepace.
Simply add "delims=" to change it to take the full string.
To output each non empty line in the file, you should ensure that you stipulate either all tokens or no delimiters, (you may also need, depending upon your task, to prevent the exclusion of lines beginning with a specific character, the default For behavior is to ignore all lines which begin with a semicolon, ;).My preference in this instance is to stipulate all tokens; this, unlike stipulating nodelimiters, will remove all leading whitespace from every line, (this would prevent files carrying accidental leading spaces from being picked up).
You cannot copy a file which does not exist, you could supress any error when trying to do so by using 2>Nul, but I would consider it better practice to see if the file exists first.
When you copy a file you need provide only the destination, (you only need to provide the file name if you're changing it).
Instead of using the Copy command you could instead use the XCopy command, this has the benefit of creating the destination directory, (subject to permissions), if it doesn't already exist.
Here therefore is a batch file example:
#For /F UseBackTokens^=*EOL^= %%A In ("find_file_list.txt") Do #If Exist "%%A" XCopy "%%A" "C:\test\">Nul
…and a very slightly modified version to be run from the Command Prompt:
For /F UseBackTokens^=*EOL^= %A In ("find_file_list.txt") Do #If Exist "%A" XCopy "%A" "C:\test\">Nul
so i'm trying to take one file at a time out of a directory that contains 2000 files and going up and move it to a different directory to be worked on by the rest of my script. the script is below. Right now i know the gswin64 line works when it is alone and i specify it a filename but not i'm sure with the variable yet. But when i run this it will copy all the files in directory input to directory working before it runs the rest of the script. How do i make it do one at a time then process the script before copying the rest of the files?
for /F "delims=" %%I in ('dir "H:\documents\gs\input\*.*" /A-d /B /O:-D') do (move "H:\documents\gs\input\%%I" "H:\documents\gs\working"&goto filemoved)
:filemoved
Your original code would attempt to execute move "H:\documents\gs\input\*.*" "H:\documents\gs\working" which is why all of th files were moved. What you need to do is execute a directory list command with the switch parameters and supply that to the for /f. This form of dir will show names only. so you need to include the source directory name in the move command. You would also need to have the "delims=" option to ensure that filenames containing separators are processed correctly, and the /a-d directory switch to ensure that directory names are not included. Since you are sorting in reverse-date order, the newest file will be selected first. After the first file is moved, you need to abort the for loop otherwise it will continue processing the entire list, transferring every file. The easy way here is to simply goto a label on the next line.
You've also used a *.* filemask, which will process all files, regardless of extension. Since you appear to want to process only .pdf files, you should probably change that filemask to suit.
for /F "delims=" %%x in ('dir H:\documents\gs\working\*.pdf /b') do set "FileName=%%x"
Again, you need to execute a dir command if you are using a for /f. There's no apparent reason why you wouldn't use the far simpler
for %%x in (H:\documents\gs\working\*.pdf) do set "FileName=%%x"
In either case, you probably want only the name part of the file, so FileName should be set to %%~nx, not %%x.
"C:\program files\gs\gs9.20\bin\gswin64" -o H:\documents\gs\output\"%FileName%" -sDevice=pdfwrite -dFitPage -dFIXEDMEDIA H:\documents\gs\working\"%FileName%"
Unbalanced quotes - the full pathname to the executable needs to be quoted since it contains a separator. Stray spaces after \ will probably need to be removed.
It would be better imho to quote the entire filename, including drive and path rather than filename only.
del /q H:\documents\gs\working\*.*
rm is not a batch command. Note that this command will delete ALL files in H:\documents\gs\working - not just the .pdf files that you appear to be processing.
goto start
The space is required. gotostart is not an inbuilt command.
I want to create a program that can loop through multiple pdf files and have the user rename each file a unique name like so:
234324.pdf to Batch150.pdf
32154687.pdf to AdvancedPayment.pdf
and so on...
Here is my code:
setlocal EnableDelayedExpansion
echo rename pdf files
FOR %%F IN (*.pdf) DO (
set /p x=Enter:
move %%F !x!
)
endlocal
This seems to work for the first file and then when I try to rename the second one it says: The syntax of the command is incorrect..
I have tried using the rename command and haven't had much luck with it.
FOR %%F IN (*.pdf) DO (
SET "x=%%F"
set /p "x=%%F Enter: "
IF /i "!x!.pdf" neq "%%F" ren "%%F" "!x!.pdf"
)
Your code worked fine for me. Since you don't indicate what the "to" and "from" names you used were, we're reduced to guessing.
I developed the above code to perform the rename in the manner you originated. Note that it works as I expect. Using ren the "to" filename must be a filename within the directory where the "from" file resides [ie. it simply renames the file]. If you use "move" then the file can be moved to another directory if you specify that in the "to" name.
The first fix is purely cosmetic. By enclosing the variablename and prompt in the set /p in quotes, you can include a terminal space in the prompt (which I prefer), and including the %%F in the prompt shows you which file is about to be renamed.
The next fix is to quote the arguments to the ren or move. This ensures the syntax remains properly constructed in the case of eithr "to" or "from" name containing a space.
The next is to initialise x with the "from" filename. It's enclosed in quotes so any invisible trailing spaces are not included in the value assigned to x. Note that set /p does not alter the variable if Enter alone is keyed, so setting x ensures that if a file is not to be renamed, all you need do is press Enter
The next is to detect whether the "to" and "from" names are equal. ren will generate an error report if you attempt to rename a file to itself; equally, you can't move a file to itself. Hence, /i=ignore case, and only attempt the operation if the names are different.
Finally, add the .pdf to each usage of !x! in order that you don't need to key it in. Naturally, you could omit this change if you want to alter extensions or you could put .pdf into another variable and use that variable in place of the constant .pdf so that the extension being selected can be easily varied by being changed in one plaace rather than using a mass-edit. You could even use a set /p to assign the extension being processed dynamically at the start of the routine.
Note that if you rename say one.pdf to yellow.pdf then this construct is very likely to propose yellow.pdf for a rename later on. This is because the next-filename logic locates the next filename currently in the directory,then processes the loop, then locates the next filename currently in the directory, and so on.
You would need
For /f "delims=" %%F in ('dir /b/a-d "*.pdf" ') do (
to ensure that each filename is only presented once. This mechanism performs a directory scan of filenames-only in basic form, and stores the list in memory, then processes the list item-by-item and since that list is created and then processed, any subsequent alterations to the directory do not affect the list.
I'm having trouble trying to copy and rename a file using only dos commands. I have a file of the format myfile20130218 and want to copy and rename it to some_other_file_20130218.
I know I can use copy source dest but I'm having trouble with how to isolate the date and preserve it. I cannot guarantee that he date will be today's date so that is ruled out, the source file will always be the same name.
I can run either a series of commands or a batch script, but thing that that I am currently having trouble with, is after I find a match that I need to copy, using myfile????????, how can I now get those file names to pull the dates off them?
EDIT: for clarification I will be looking at files in a known directory, as above, I will know the format of the file name, and will only be checking a specific directory for it. The process that checks the directory is a ConnectDirect file watcher, so when a file is found matching myfile20130218 I can fire off some commands, but don't know how to check the directory and get the name of the file present.
Something like this should work:
%oldname:~-8% extracts the last 8 characters from %oldname% which are then appended to the new filename.
Update: If you can identify the file with an external program and then call the batch script with the file name
copyfile.cmd C:\path\to\myfile20130218
you could do something like this:
set oldname=%~nx1
set newname=%~dp1some_other_file_%oldname:~-8%
copy "%~f1" "%newname%"
Update 2: If you know folder and the format you could call the script with the folder
copyfile.cmd C:\folder
and do something like this:
#echo off
setlocal EnableDelayedExpansion
for /f %%f in (
'dir /b "%~f1" ^| findstr /r "myfile[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$"'
) do (
set oldname=%~f1\%%f
set newname=%~f1\my_other_name_!oldname:~-8!
copy "!oldname!" "!newname!"
)
endlocal
Edit: Script breakdown.
setlocal EnableDelayedExpansion enables variable expansion inside loops and conditionals.
for /f %%f in ('...') executes the command between the single quotes and then loops over the output of that command.
dir /b "%~f1" lists the content of the given directory (%~f1 expands to the full path of the first argument passed to the script) in simple mode (no header, no summary).
findstr /r "myfile[0-9]...[0-9]$" filters the input for strings that end with the substring "myfile" followed by 8 digits. The circumflex before the pipe (^|) escapes the pipe, because otherwise it would take precedence over the for command, which would effectively split the for command in half, resulting in an invalid command-line.
set oldname=%~f1\%%f assign the full path to a matching file to the variable oldname.
set newname=%~f1\my_other_name_!oldname:~-8! assign the full path to the new filename ("my_other_name_" followed by the trailing 8 digits from oldname) to the variable newname.
copy "!oldname!" "!newname!" I don't need to explain this, do I?