Handling File-Path Spaces in Batch Parameters - batch-file

I am writing a Win 7 batch script for copying files from various source paths to a single location. The full path names of the files being copied are listed in a text file.
The following script works when the source paths do not include spaces. I can handle spaces if path names are included into the script as constants with a combination of quotations and %~1. How do I emulate this combination for paths being passed as parameters?
Transfer2.bat:
set SOURCELIST=c:\Temp\List1.txt
set DEST=c:\Temp\To
for /f %%A in (%SOURCELIST%) do (forfiles /p %%~dpA /s /m %%~nxA /c "cmd /c copy /y #path %DEST%\#file" 2>>log.txt)
for /f %b in (log.txt) do (echo.%~b)>>log.txt`
del log.txt
List1.txt:
C:\temp\From\Test_This Space.txt
C:\temp\From\Test.txt
Results:
Transfer is successful for C:\temp\From\Test.txt.
Log returns ERROR: Files of type "Test_This" not found. for C:\temp\From\Test_This Space.txt.

Is forfiles command required for your script? If not, I think this is good enough:
#echo off
set SOURCELIST=C:\Temp\List1.txt
set DEST=C:\Temp\To
for /f "delims=" %%A in (%SOURCELIST%) do (
copy /y "%%~fA" "%DEST%\%%~nxA" >>Log.txt 2>&1
)
type Log.txt
del /q Log.txt
pause
exit /b

Related

Forfiles with 7z zip ONLY last modified file

I am trying to zip only last modified file from a folder to help my workflow with bat file
but its giving an error
ERROR: No files found with the specified search criteria.
Here is my complete code
#ECHO ON
SET "SourceDir=C:\Users\user1\Documents\Work"
SET "ZipName=testing.zip"
SET "DestDir=C:\Users\user1\Documents\Work\result"
SET "now=%date:~4%"
CD /D "%DestDir%"
FORFILES /D %now% /m *.csv /c "cmd /c 7z.exe a -aoa -tzip %ZipName% %SourceDir% "
I am pretty sure there is file last modified today. I assume its didn't recognise the sourcedir? Am I missing in the quote?
I suggest not using command FORFILES, but use instead the commands FOR and DIR.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /A-D /B /O-D 2^>nul') do 7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I" & goto Done
:Done
DIR searches in specified source directory with wildcard pattern * because of /A-D (attribute not directory) only for files and outputs them because of /B (bare format) with file name only ordered by last modification date in reverse order because of /O-D which means newest file is output first.
FOR process this output by DIR line by line. For the first line 7z.exe is called to compress the file into the ZIP archive file.
Then goto :Done is executed to exit the FOR loop as all other files found and output by DIR are of no interest.
I suggest to specify 7z.exe with full path in the batch file.
2^>nul redirects the error message output by DIR if no file is found in source directory to device NUL to suppress it. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on Windows command interpreter parses the entire FOR command line. The escape character ^ is already removed later on execution of DIR command line in a separate command process opened by FOR in background.
Another version processing only files with archive attribute set and clear the archive attribute for each file compressed into the ZIP archive file.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /AA-D /B 2^>nul') do (
7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I"
%SystemRoot%\System32\attrib.exe -a "%SourceDir%\%%I"
)
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.
attrib /?
dir /?
echo /?
for /?
goto /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.

How to clear but not delete all files in all subfolders with exception of the batch file?

I have already this batch code:
#echo off
setlocal
:PROMPT
SET /P AREYOUSURE=Are you sure (Y/[N])?
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
#echo off
pushd %*
for %%j in (*) do if /I not "%%j"=="%~nx0" type nul > "%%j"
popd
I want to create a 0 byte backup of all files in all subfolders. So if I lose them I would know what to re-download. The batch file itself should not be cleared.
What must be changed on this code to run on all files in all subfolders?
FORFILES is your friend! The syntax is:
forfiles [/p <Path>] [/m <SearchMask>] [/s] [/c "<Command>"] [/d [{+|-}][{<Date>|<Days>}]]
The /s option will make your script look into subfolders. This should work:
#echo off
setlocal
:PROMPT
SET /P AREYOUSURE=Are you sure (Y/[N])?
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
FORFILES /S /C "CMD /C IF #ISDIR==FALSE IF NOT #FILE==\"%~nx0\" type nul > #PATH"
Possible variables in FORFILES construct are:
#FILE: File name.
#FNAME: File name without extension.
#EXT: File name extension.
#PATH: Full path of the file.
#RELPATH: Relative path of the file.
#ISDIR: Evaluates to TRUE if a file type is a directory. Otherwise, this variable evaluates to FALSE.
#FSIZE: File size, in bytes.
#FDATE: Last modified date stamp on the file.
#FTIME: Last modified time stamp on the file.
For more information check https://technet.microsoft.com/en-us/library/cc753551.aspx.
EDIT: Added skip if folder

findstr for filename in win7 batch file

I'm kind of struggling with the following search.
I need to look for files which are misplaced in wrong folders. I have the following testing structure (in reality it is hudreds of folders):
C:\test2\John\John_phone.txt
C:\test2\Mary\John_address.txt
C:\test2\Mary\Mary_address.txt
C:\test2\Mary\Mary_phone.txt
C:\test2\Mary\Peter_address.txt
The files John_address.txt and Peter_address.txt are misplaced in Mary's folder. I want to check Mary's folder for any misplaced files and list them in a separate log file. So for the example above the log would contain the names (paths) of the two misplaced files, The deciding identifier is the person's name. I have this piece of code:
#echo off
cls
set /p name="Specify the name: "
::forfiles /p "%CD%\%name%" /s /m *.* /c "cmd /c echo #path">>log.txt
forfiles /p "%CD%\%name%" /s /m "| findstr /i /v "\*%name%*"" /c "cmd /c echo #path">>log.txt
pause
The commented line for forfiles works (lists all files in the folder), so I have an issue with findstr: ERROR: Files of type "| findstr /i /v *Mary*" not found.
The /v switch with findstr should find all files that do not contain the specified name, but obviously I'm doing something wrong while using it as input for forfiles.
I don't want to use the dir command since it lists additional information and I need to integrate the output into larger log file (I need to get only the path of the misplaced file).
Any help is appreciated.
Thanks.
Edit: Would it be easier to write the code if the correct file name would be fixed like this?
All_data_%NAME%_new.txt
The stuff before and after the name would be fixed and this format of the file name would be the only correct option, so anything else would have to be reported.
For a simple solution
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=c:\test2"
( for /d %%z in ("%rootFolder%\*"
) do for %%y in ("%%~fz\*"
) do for /f "tokens=1 delims=_" %%a in ("%%~ny"
) do if /i not "%%~nxz"=="%%a" echo %%~fy
) > log.txt
This will iterate the files under each of the folders testing if their name starts with the same string that the folder name.
edited the original proposed solution does not work as intended, so, removed
edited - as the name of the file has not a fixed format, and the name of the folder can be in any place, this can be used
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=c:\test2"
rem create a temporary file to hold the patterns to match against the list
rem of files to determine if it is correctly placed
set "patterns=%temp%\%~nx0.%random%.tmp"
> "%patterns%" (
for /d %%a in ("%rootFolder%\*") do echo(\\%%~nxa\\[^^\\]*%%~nxa[^^\\]*
)
rem Get the list of files, and filter to only get those that do not match
rem the generated patterns
dir /s /b /a-d "%rootFolder%\*" ^
| findstr /r /i /c:"%rootFolder:\=\\%\\[^\\]*\\." ^
| findstr /r /i /e /v /g:"%patterns%" ^
> log.txt
rem Patterns file is no longer needed
del "%patterns%" >nul 2>nul
this should help provided that comparison is case sensitive
for /f "delims=.'_\ tokens=2,3,*" %%a in ('forfiles /s /m *.txt /c "cmd /c echo #relpath"') do if NOT "%%a"=="%%b" #echo "%%a\%%b_%%c

How to specify multiple wildcards in a folder directory in CMD

I found this post in regards to wildcards in directories. However, my problem is that I have multiple varying directory names between my static directories. For example:
O:\123456 Client Name\Spring\Shoot 1 12345\01 MHP 01\PlCache\GreenScreen\
O:\121212 Someone Else\Spring\Shoot 1 21212\01 MHP 02\PlCache\GreenScreen\
The above link only allows for one wildcard directory instead of muliples.
Within these GreenScreen folders, I have .png files I wish to delete. How would I write a .bat file that deletes *.png within O:\ *\GreenScreen\ ?
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:"
FOR /f "tokens=1*delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*.png" '
) DO (
SET "targetpath=%%~pa"
IF "!targetpath:~-13!"=="\GreenScreen\" ECHO DEL "%%a"
)
GOTO :EOF
The required DEL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO DEL to DEL to actually delete the files.
I've changed to starting directory to U: to suit my system.
Here's a simpler option - it also echos the del commands to the screen until you remove the echo keyword.
#echo off
for /d /r "o:\" %%a in (GreenScreen*) do if /i "%%~nxa"=="GreenScreen" echo del "%%a\*.png"

How to write a list of directory trees to a text file?

I want to create a batch file. When it is invoked as batch.bat MyProject or batch.bat MyProject/ it will produce the following list. Note that Dir is a sub directory of MyProject. I am using Windows 7.
Dir
Dir/SubDir1
Dir/SubDir1/SubSubDir1
Dir/SubDir1/SubSubDir2
Dir/SubDir2
Dir/SubDir2/SubSubDir1
Dir/SubDir2/SubSubDir2
Dir/SubDir2/SubSubDir3
Dir/SubDir3
Dir/SubDir4
How to write a list of directory trees to a text file?
File names must be excluded.
FORFILES provides a simple solution, but it is SLOW. The command works equally well from within a batch file or on the command line:
forfiles /s /p "c:\MyProject" /m * /c "cmd /v:on /c if #isdir==TRUE (set f=#relpath&echo !f:~3,-1!)" >listing.txt
If you run the command with MyProject as your current directory then you can drop the /p "c:\MyProject" option from the command.
If you don't mind your relative paths being enclosed in quotes with .\ in the front of each path, then the solution is even simpler:
forfiles /s /p "c:\MyProject" /m * /c "cmd /c if #isdir==TRUE echo #relpath" >listing.txt
Ok - this should do it. It takes one argument (the root folder).
#ECHO OFF
SET root=%1
REM Get the length of the root, to make the path relative later.
REM See http://stackoverflow.com/questions/5837418/how-do-you-get-the-string-length-in-a-batch-file.
ECHO %root%>x&FOR %%? IN (x) DO SET /A rootlength=%%~z? - 1&del x
for /F "tokens=*" %%G in ('DIR %1 /AD /S /B') do (
CALL :PrintDirectory "%%G" %rootlength%
)
GOTO :eof
:PrintDirectory
REM %1 Path to the folder
REM %2 Length of root string.
REM See http://www.dostips.com/DtTipsStringManipulation.php#Snippets.LeftString for
REM information on the string manipulation.
#ECHO OFF
SET start=%2
SET absPath=%1
REM Remove the path root by taking the right-hand side of the string.
CALL SET relPath=%%absPath:~%start%,-1%%
ECHO.%relPath%
You can execute it by redirecting the results to a batch file:
PrintDirectoryStructure.bat c:\MyProject > out.txt

Resources