I'm trying to move hl7 files older then 7 days. My script is
forfiles /p C:\TEST /m *.hl7* /s /d -30 /c "cmd /c move #file C:\New Folder"
pause
I'm getting error like
The syntax of the command is incorrect.
The syntax of the command is incorrect.
The syntax of the command is incorrect.
The syntax of the command is incorrect.
The syntax of the command is incorrect.
The syntax of the command is incorrect.
The syntax of the command is incorrect.
Any help? please.
This is because New Folder has a space in it and forfiles doesn't know how to handle that.
Normally, you'd put paths with spaces in quotes to tell cmd that everything inside of the quotes should be considered a single item. Unfortunately, the entire "cmd /c move #file C:\New Folder" is already in quotes, so adding more quotes inside of those quotes is only going to make things worse. The good news is that in forfiles /?, there's a line that reads
To include special characters in the command line, use the hexadecimal code for the character in 0xHH format (ex. 0x09 for tab). Internal CMD.exe commands should be preceded with "cmd /c".
The hexadecimal version of " is 0x22, and if you change your command to forfiles /p C:\TEST /m *.hl7 /s /d -7 /c "cmd /c move #file 0x22C:\New Folder0x22", then your script will work correctly.
Related
I want to create a batch file that loops through a folder containing xml files, then call msxsl to modify them and after modify the xml file, copying to another folder with original filename.
I tried this:
forfiles /p C:\Users\mae\Documents\Testing\MSXSL\In /m *.xml /c "cmd /c C:\Users\mae\Documents\Testing\MSXSL\msxsl.exe #file pre-process_add_filename.xsl -o C:\Users\mae\Documents\Testing\MSXSL\Out\#file"
But that gives me this error:
Error occurred while creating file 'C:\Users\mae\Documents\Testing\MSXSL\Out\"bk_OIOUBLInvoice_TEST.xml"'.
Code: 0x8007007b
The filename, directory name, or volume label syntax is incorrect.
This is because of the double quotes around the output filname. How do I get around this?
As already suggested by others in comments, you should use a standard for loop for your task rather than forfiles:
for %%I in ("%UserProfile%\Documents\Testing\MSXSL\In\*.xml") do (
"%UserProfile%\Documents\Testing\MSXSL\msxsl.exe" "%%I" "pre-process_add_filename.xsl" -o "%UserProfile%\Documents\Testing\MSXSL\Out\%%~nxI"
)
But if you do insist on forfiles you could use the following code:
forfiles /P "%UserProfile%\Documents\Testing\MSXSL\In" /M "*.xml" /C "cmd /C for %%I in (#file) do 0x22%UserProfile%\Documents\Testing\MSXSL\msxsl.exe0x22 #file 0x22pre-process_add_filename.xsl0x22 -o 0x22%UserProfile%\Documents\Testing\MSXSL\Out\%%~I0x22"
The inner for loop together with the ~-modifier is used to get rid of the additional quotation marks around the file name returned by #file. The term 0x22 is forfiles-specific and marks a literal quotation mark.
I need a CMD batch file to delete all the log files.
My company makes plugins for their product and the path is something as follows:
C:/Program Files/product/../plugins/../plugin_Path/pluginOne/audit/log
C:/Program Files/product/../plugins/../plugin_Path/pluginOne/audit/log-archive
C:/Program Files/product/../Root/plugins/../plugin_Path/pluginTwo/audit/log
C:/Program Files/product/../Root/plugins/../plugin_Path/pluginTwo/audit/log-archive
Now I need to delete all the log and log-archive folders with its contains.
Currently I wrote a samll program like this:
#echo off
color 02
for %%A in (
"C:/Program Files/product/plugins/plugin_Path/pluginOne/audit/log"
"C:/Program Files/product/plugins/plugin_Path/pluginOne/audit/log-archive"
"C:/Program Files/product/plugins/plugin_Path/pluginTwo/audit/log"
"C:/Program Files/product/plugins/plugin_Path/pluginTwo/audit/log-archive"
) do (
del /Q %%A
echo Deleted %%A
)
echo All files deleted
pause
echo Program ended
But here I need to insert all the log paths manually.
I am looking for a solution where I could point the parent folder (say Program Files/Company) and it could traverse all the files inside and will delete all the log and log-archival folders with its contains.
I am a QA person have good QA experience but no experience on batch programming and I dont have much time and support team is not present. [Need help]. There are more than 1K log files are present.
First, as explained by the Microsoft documentation Naming Files, Paths, and Namespaces, the directory separator on Windows is \ and not / as on Linux/Mac. / is used on Windows for options as you can see on your code for example on /Q. So use in future \ in file/folder paths. The Windows file system accessing kernel functions automatically replace all forward slashes by backslashes before accessing the file systems, but writing code depending on automatic error correction is never a good idea.
The task to delete all folders with name log or log-archive in a specified folder and all its subfolders can be done with a single command line.
#for /F "delims=" %%I in ('dir "%ProgramFiles%\product\plugins\plugin_Path\log*" /AD /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /R "\\log \\log-archive"') do #rd /Q /S "%%I" 2>nul
FOR with option /F runs in a separate command process started with cmd.exe /C (more precise with %ComSpec% /C) in background the command line in '... ' which is here:
dir "C:\Program Files\product\plugins\plugin_Path\log*" /AD /B /S 2>nul | C:\Windows\System32\findstr.exe /E /I /R "\\log \\log-archive"
The command DIR outputs to handle STDOUT
in bare format because of option /B
just directories because of option /AD (attribute directory)
directory names matching the wildcard pattern log*
in specified directory C:\Program Files\product\plugins\plugin_Path
and all its subdirectories because of option /S
with full path also because of option /S.
It could be that DIR does not find any file system entry matching these criteria. In this case an error message is output by DIR to handle STDERR. This error output is redirected with 2>nul to device NUL to suppress it.
The standard output of DIR is redirected with | to handle STDIN of FINDSTR which runs
because of option /I a case-insensitive
regular expression find explicitly requested with option /R
for string \log or \log-archive (space is interpreted as OR)
which must be found at end of a line because of option /E.
All lines matching these search criteria are output by FINDSTR to handle STDOUT of background command process. This filtering of output of DIR with FINDSTR is necessary to avoid the deletion of a directory which is named for example LogToKeep also found and output by DIR.
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.
FOR with option /F captures output to handle STDOUT of started command process and processes this output line by line after started cmd.exe terminated itself. Empty lines are always ignored by FOR which do not occur here. Lines starting with a semicolon are also ignored by default because of eol=; is the default definition for end of line option. But a full qualified folder path cannot contain a semicolon at beginning because the folder path starts either with a drive letter or with a backslash in case of a UNC path. So default end of line option can be kept in this case. FOR would split up by default every line into substrings with using normal space and horizontal tab as string delimiters and would assign just first space/tab separated string to specified loop variable. This line splitting behavior is not wanted here as the folder path contains definitely a space character and the entire folder path is needed and not just the string up to first space. For that reason delims= is used to specify an empty list of delimiters which disables line splitting behavior.
FOR executes for every directory output by DIR passing FINDSTR filter with full path the command RD to remove the directory quietly because of option /Q and with all files and subdirectories because of /S.
The deletion of the directory could fail because of missing NTFS permissions, or the directory to delete or one of its subdirectories is current directory of a running process, or a file in the directory to delete is currently opened by a running process in a manner which denies deletion of the file while being opened, or the directory to delete does not exist anymore because it was deleted already before in FOR loop. The error message output by command RD to handle STDERR is in this case redirected to device NUL to suppress it.
Please note that command RD deletes all log and log-archives directories and not just the files and subdirectories in these directories. It is unclear from your question what exactly should be deleted by the batch file.
It is of course also possible to replace rd /Q /S "%%I" by del /A /F /Q "%%I\*" to delete just all files including hidden and read-only files quietly in the directory assigned with full path to loop variable I.
# left to command FOR and command RD just suppress the output of those commands before execution by Windows command processor cmd.exe. Both # are not needed if this single command line is used in a batch file containing before #echo off.
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 /?
findstr /?
for /?
rd /?
If you're wanting to remove the contents of the log and log-archive directories. This means the easiest solution would probably be FORFILES.
This will delete all the files under log and log-archive directories found within any subfolder of "C:\Program Files\product\plugins". The folders MUST be named exactly log or log-archive. It will not remove directories.
FORFILES /P "C:\Program Files\product\plugins" /M log /C "cmd /c if #isdir==TRUE DEL /s /q #path\*"
FORFILES /P "C:\Program Files\product\plugins" /M log-archive /C "cmd /c if #isdir==TRUE DEL /s /q #path\*"
You could also add a /D switch to only delete applicable files if they are older than a specific number of days. This will delete all the log and log-archive files under "C:\Program Files\product\plugins" that are older than 90 days:
FORFILES /D -90 /P "C:\Program Files\product\plugins" /M log /C "cmd /c if #isdir==TRUE DEL /s /q #path\*"
FORFILES /D -90 /P "C:\Program Files\product\plugins" /M log-archive /C "cmd /c if #isdir==TRUE DEL /s /q #path\*"
I've inherited a batch file, and in it, I've got the following command -
forfiles /s /c "cmd /c IF #ISDIR==TRUE rmdir #FILE /q" >> C:\Apps\%dt%\%dt%.log 2>&1
In the log, I get the following error:
ERROR: The system cannot find the file specified.
How can I put an else condition so that it outputs the name of the file not found, instead the Error Message?
Ther error comes from forfiles when it is executed in a directory with no content (no files and no directories). Remember that forfiles searches the current working directory if no path is specified explicitly by the /P switch, and the search mask defaults to * if switch /M is not given, hence matching all items. So the error you encounter can only occur with an empty working directory.
The error has got nothing to do with the if #isdir==TRUE query.
If you want a specific message to appear in your log, you could check the ErrorLevel state after forfiles has been executed, which is 1 in case no items match the search criteria, and 0 if at least one item matches:
forfiles /S /C "cmd /C if #isdir==TRUE rmdir #file" || echo "%CD%" is empty. >> "C:\Apps\%dt%\%dt%.log" 2> nul
This writes the message "%CD%" is empty into the log with %CD% replaced by the current directory.
The 2> nul suppresses the error message ERROR: The system cannot find the file specified..
The || operator is conditionally concatenates commands and lets the right one execute only if the left one has been completed successfully, meaning that ErrorLevel is 0.
Using the forfiles batch command, sometimes the #path variable and the #file variable are the same, and sometimes they are different. This looks like a bug to me.
To illustrate - setup:
md test_subfolder
echo Hello>test_subfolder\test.txt
Now #path and #file are different, like you would expect:
forfiles /p test_subfolder /c "cmd /c echo CD: [%cd%] PATH: [#path] FILE: [#file]"
That yields:
CD: [D:\] PATH: ["D:\test_subfolder\test.txt"] FILE: ["test.txt"]
Now, try overwriting the file using #path. This does what you would expect.
forfiles /p test_subfolder /c "cmd /c echo Goodbye>#path"
type test_subfolder\test.txt
Result:
Goodbye
Trying the same thing using #file instead of #path:
forfiles /p test_subfolder /c "cmd /c echo Farewell>#file"
This should create a new file in the root, and leave the file in the subfolder unchanged. But instead, it behaves the same way that the #path does.
Checking for the file in the root folder:
dir test.txt
Result:
Volume in drive D is Recovery
Volume Serial Number is AE9D-4134
Directory of D:\
File Not Found
Looking in the subfolder:
type test_subfolder\test.txt
Result:
Farewell
This is using Windows 7 Professional - I don't know how it might work in other versions.
How can I get #file to behave the way I expect?
This is not a bug. The real problem is the point where the parser expands %CD%, it is done immediately, so you see the current directory of the cmd instance you are working in.
The cmd instance opened by forfiles receives the path provided at /p as the current directory. To see this, change the command line to:
forfiles /p test_subfolder /c "cmd /c echo CD: [0x25cd0x25] PATH: [#path] FILE: [#file]"
0x25 represents the hex. code of the % sign, so expansion of %cd% is not done immediately, but transferred to the "inner" cmd instance.
This will show you that the echo command is actually executed in D:\test_subfolder and so the #file variable expansion of forfiles behaves correctly. Hence the output will be:
CD: [D:\test_subfolder] PATH: ["D:\test_subfolder\test.txt"] FILE: ["test.txt"]
This explains why your line of code forfiles /p test_subfolder /c "cmd /c echo Farewell>#file", when executed in D:\, (over-)writes the file D:\test_subfolder\test.txt rather than creating a new file D:\test.txt.
Hm ... this works! It's a mystery to me why, though.
forfiles /p test_subfolder /c "cmd /c echo So Long>%CD%#file"
type test.txt
Result:
So Long
forfiles /p test_subfolder /c "cmd /c echo So Long>%CD%\#file" command is working for me,[please note that i have used "\" after %CD%] , you need write to a file in the sub directory , you are trying to execute the above command outside the sub folder , probabaly that might me the reason you are feeling the difference between #path and #file
I want to delete *.sql files older than 90 days using batch file and I wrote following command.
forfiles /M *.sql /d -90 /c "cmd /c del #file
I am not sure above command is valid? and if not need suggestions.
forfiles /M *.sql /d -90 /c "cmd /c del #file
SYNTAX (FOR WIN XP FORFILES RESOURCE KIT)
FORFILES [-p Path] [-m Mask] [-s] [-c Command] [-d [+ | -] {dd/MM/yyyy | dd}]
You haven't specified a path, so it will default to your current directory. Also, you didn't close out the quotes at the end of your command. For the sake of safety, I would specify your path.
forfiles -p"C:\Path\To\sqlfiles" -m *.sql -d-90 -c"cmd /c del #FILE"
For your example, not specifying a path:
forfiles -m *.sql -d-90 /c"cmd /c del #FILE"
EDIT: Edited my command as using / instead of - for the switch symbols doesn't work. Removed the link as well because it stated otherwise. Please note: do not insert spaces between the switch and inputs as it will fail. Also, your # parameter must be in all caps. Also to note, the online documentation on ss64.com is incorrect for the usage of #PATH