Find and replace text between certain characters with filename, have about 100 files that require this so I'm thinking it needs a occurrence or something.
Original file name: test1.txt
Inside file replace the following two lines with the file name (inside each file the below strings might not be right after each other):
location000:/computer/[project]/name/123.php,32,1,2,512,0,,txt
newlocation000:/computer/[project]/name/123.php,32,1,2,512,0,,txt
Output in file test1.txt
location000:/computer/[project]/name/test1.php,32,1,2,512,0,,txt
newlocation000:/computer/[project]/name/test1.php,32,1,2,512,0,,txt
This is an easy to achieve task with using JREPL.BAT written by Dave Benham which is a batch file / JScript hybrid to run a regular expression replace on a file using JScript.
#echo off
if not exist "%~dp0jrepl.bat" (
echo ERROR: JREPL.BAT missing in directory "%~dp0".
echo/
pause
goto :EOF
)
for %%I in ("C:\Temp\*.txt") do call "%~dp0jrepl.bat" "^((?:new)?location000:/.+/).*(\.[^.,]+,)" "$1%%~nI$2" /F "%%I" /O -
This batch file works only on NTFS drives. It can result in an endless running loop on FAT16, FAT32 or ExFAT drives or skipping some text files. For a working solution independent on file system replace the last command line by:
for /F "eol=| delims=" %%I in ('dir "C:\Temp\*.txt" /A-D-H /B /ON 2^>nul') do call "%~dp0jrepl.bat" "^((?:new)?location000:/.+/).*(\.[^.,]+,)" "$1%%~nI$2" /F "C:\Temp\%%I" /O -
The batch file JREPL.BAT must be stored in same directory as the batch file with the code above. For that reason the batch file checks first if JREPL.BAT really exists in directory of the batch file and if this is not the case, outputs an error message, halts script execution to make it possible for a user to read that error message and then exits. See Where does GOTO :EOF return to?
The command FOR searches in specified directory C:\Temp for non hidden files matching the wildcard pattern *.txt and calls for each found text file the batch file JREPL.BAT to replace the file name between last / and first string starting with ., having one or more characters not being a dot or a comma with next character being a , (= file extension and comma) on lines starting case-sensitive with location000:/ or newlocation000:/ by the file name of the current *.txt file without file extension. So a file name in existing file can contain also one or more . in file name before file extension.
The solution working also on FAT drives uses command DIR to get a captured list of *.txt files with just file name and file extension without path and FOR processes this file names list line by line, i.e. file name by file name. So the list of *.txt files to process does not change on running FOR calling JREPL.BAT as it would be the case on using FOR directly to find the *.txt files on FAT drives.
NTFS returns a list of directory entries matching a wildcard pattern sorted alphabetically and so the list of *.txt files does not modify during FOR iterations in this case. But all FAT file systems return the list of directory entries matching a wildcard pattern according to last modification in directory with last modified file at end of the list. So while FOR gets one file name after the other on using for %%I in ("C:\Temp\*.txt") do from file system and processes the file with calling jrepl.bat which modifies the file, the file list changes on FAT drives and next directory entry returned to FOR on its search for *.txt is either the file just modified (= endless loop) or another file after skipping a file which should be also modified because of file list changed since last directory access by FOR.
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 also %~dp0 ... drive and path of argument 0 being the batch file itself.
dir /?
echo /?
for /?
goto /?
if /?
pause /?
jrepl.bat /?
Related
I am creating a batch file to be run later which will be used to copy files from one location to another while renaming the files, skipping any existing files, and without prompting the user. Examples of files to be copied:
00021001.txt
00021001.xyz
00021001.abc
00021001001.jpg
Copied files will have the names:
00022001.txt
00022001.xyz
00022001.abc
00022001001.jpg
Things I have tried:
xcopy C:\Testing\1000012\21\00021*.* C:\Testing\1000013\22\00022*.* /D
This almost does it. It copies all the files starting with "00021" in the first location into the second location while properly renaming them to start with "00022". It skips all the files with the same name and date stamp, but ends up prompting to copy any files from the source which are newer than the target.
robocopy C:\Testing\1000012\21\ C:\Testing\1000013\22\ 00021*.* /xo /xn /xc
I was hoping that by excluding older, newer, and same date files it would work (even if it doesn't rename - I would just do that in a separate step.) Unfortunately, this just ends up overwriting newer source files over existing target files if they are a different filesize.
I have even tried the Copy-Item command in PowerShell. But it doesn't do the renaming like Xcopy, and it doesn't skip existing files (although I can get it to confirm and say "No to All".)
Copy-Item -Path "C:\CWUImageCompare\Testing\1000012\CWU\chemistry\129\21\00021*.*" -Destination "C:\CWUImageCompare\Testing\1000013\CWU\chemistry\129\20\" -Confirm
If xcopy had the "Skip if existing" flag I'd be all set, but it doesn't.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory & destination directory are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
FOR /f "skip=1delims=" %%b IN ('xcopy /L /Y "%sourcedir%\00021*.*" "%destdir%\00022*.*" ^|sort') DO (
SET "oname=%%~nxb"
IF EXIST "%destdir%\00022!oname:~5!" (ECHO "%%b" skipped) ELSE (ECHO COPY /y "%%b" "%destdir%\00022!oname:~5!")
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Seems a little complicated, but essentially, execute the xcopy (I omitted the /D for testing) with /L /Y to simply produce a list.
Since the list has a last line that begins with a numeric, whereas the other lines start with a drive-letter, sort the list and skip the first line.
This would implement the date-requirement.
Then grab the part after the first 5 characters of the name+extension, test whether the new name exists and either report or copy as appropriate (The copy command is disarmed for testing)
I have 30 different folders which I need to iterate thru, within each one there’s a Log folder and inside that, are the text files. I’m after the latest one, which I need to copy to the new location with the preferred name (E.G. 2020-03-28.txt.FolderServerName1, where appended variable FolderServerName1, identifies from which server it came from)
set source="\\ServerName\LogFolders"
set target=" C:\Data\CopiedLogFiles"
FolderServerName1
Log
2020-03-26.txt
2020-03-27.txt
**2020-03-28.txt**
FolderServerName2
Log
2020-03-26.txt
2020-03-27.txt
**2020-03-28.txt**
FolderServerName3
Log
2020-03-26.txt
2020-03-27.txt
**2020-03-28.txt**
https://devblogs.microsoft.com/oldnewthing/20120801-00/?p=6993
The post above is very useful, but I think I need another nested loop within, which I'm struggling with syntactically.
Thank You so much!
This file copying task can be done with:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /D %%I in ("\\ServerName\LogFolders\*") do (
set "CopyDone="
for /F "delims=" %%J in ('dir "%%I\Log\20??-??-??.txt" /A-D-H /B /O-N 2^>nul') do if not defined CopyDone (
copy /Y "%%I\Log\%%J" "C:\Data\CopiedLogFiles\%%~nJ_%%~nxI%%~xJ" >nul
set "CopyDone=1"
)
)
endlocal
For each non-hidden subdirectory in \\ServerName\LogFolders the outer FOR loop first deletes the environment variable CopyDone and runs one more FOR loop.
The inner FOR loop starts in background one more command process using %ComSpec% /c and the command line enclosed in ' as additional commands. So executed with Windows installed into C:\Windows is in background for example:
C:\Windows\System32\cmd.exe /c dir "\\ServerName\LogFolders\FolderServerName1\Log\20??-??-??.txt" /A-D /B /O-N 2>nul
The command DIR searches in specified directory
only for non-hidden files because of option /A-D-H (attribute not directory and not hidden)
with a file name matching the wildcard pattern 20??-??-??.txt
and outputs in bare format because of option /B just each file name with extension without path
ordered reverse by name because of option /O-N
to handle STDOUT (standard output) of the background command process.
The reverse output sorted alphabetically by name results for the log file names that 2020-03-28.txt is output on first line, 2020-03-27.txt on second line and 2020-03-26.txt on third line.
It could be that the subdirectory Log does not exist at all or does not contain any file matching the wildcard pattern. In this case command DIR outputs an error message to handle STDERR (standard error) which is suppressed by redirecting it to device NUL with 2>nul.
Read 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.
The command process processing the batch file captures everything written to handle STDOUT of background command process and FOR processes this captured output line by line after started cmd.exe terminated itself.
FOR ignores empty lines which do not occur here.
FOR would split up by default each line into substrings using normal space and horizontal tab character as string delimiters, would next look if first substring starts with default end of line character ; in which case the line would be also ignored and otherwise would assign just first space/tab delimited string to specified loop variable. It would be possible here to use this default line processing behavior as the file names do not contain a space character. But it is nevertheless better to disable line splitting behavior by using delims= to define an empty list of string delimiters.
So the inner FOR assigns on first loop iteration the file name of newest file according to international formatted date in file name to loop variable J and runs the command IF.
On first loop iteration of the inner FOR loop the environment variable CopyDone is always not defined as made sure on the command line above and so the IF condition is true.
For that reason the file is copied which means for first folder FolderServerName1 that the executed COPY command is:
copy /Y "\\ServerName\LogFolders\FolderServerName1\Log\2020-03-28.txt" "C:\Data\CopiedLogFiles\2020-03-28_FolderServerName1.txt" >nul
The target file name is modified from requested 2020-03-28.txt.FolderServerName1 to 2020-03-28_FolderServerName1.txt. It is in general better to use a dot in the name of a file just once as separator between file name and file extension and keep the file extension at end of the name of the file to be able to open the file with a double click.
The environment variable CopyDone is defined with a value after the file copying is done without verification on success. The string value assigned to environment variable CopyDone does not matter in this case.
The inner FOR continues processing the captured lines by assigning one file name after the other to loop variable J and running the IF condition. But this condition is not true for any other file name than the first file name.
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.
copy /?
dir /?
echo /?
endlocal /?
for /?
if /?
set /?
setlocal /?
It's annoying to manually always search in the CMD and xcopy the hidden file, can someone whos good in scipting help me out?
I use these 2 commands:
Firstly i open CMD in the FOLDER2 and entering this command to find the hidden file in the hidden random sub dir:
dir /s /b | find "robotknow"
(robotknow is not the fullname of the file, only part of it.)
And then when it find the hidden file within the random made subdir i copy the whole path including the whole filename with the ending.
Xcopy /h *The whole path including the filename and ending* C:\hello
My folders:
$sourceDir = 'C:\Users\USER\AppData\Local\Packages\FOLDER1\FOLDER2'
$targetDir = 'C:\hello'
So i wish to create a batch that could search that string "robotknow" and copy the fullname of the file to my tagetdir.
Is it possible?
Im trying to learn commands but batching is harder, if i was unclear on anything please ask me thank you!
Edit:
I found few commands that could be useful but I dont know how to use them so that it works.
$searchStrings = For it to search after the string above i mentioned: "robotknow"
And
Copy-Item $_.FullName $targetpath
An example would be:
The filename has this in it's name "robotknow" and i want to copy it.
Copy the file im searching after to copy thats within the sub folder of the FOLDER2 which is an hidden random folder that i cannot se:
%LocalAppData%\Packages\FOLDER1\FOLDER2\THE-hidden-RANDOM-made-sub-DIR.
Copy it to it's final directory c:\hello
The final directory, simply just: c:\hello.
By hidden i mean that i cannot see in file explorer, windows GUI and neither if i put this simple command in CMD dir to show the hidden random folder where the file is located in, they are not showing.
The file only appears in CMD if i enter this command dir /s /b | find "robotknow" when im in the FOLDER2.
Only after that i can se the hidden random made dir/folder and the full hidden path to it (the file).
I suggest following batch file code for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=%LocalAppData%\Packages\FOLDER1\FOLDER2"
set "TargetFolder=C:\hello"
for /F "delims=" %%I in ('dir "%SourceFolder%\*robotknow*" /A-D /B /S 2^>nul') do %SystemRoot%\System32\xcopy.exe "%%~dpI*" "%TargetFolder%\" /C /E /H /K /Q /R /Y >nul
endlocal
The command FOR with option /F starts a separate command process with cmd.exe /C (more precisely %ComSpec% /C) in background to run the command line:
dir "C:\Users\{username}\AppData\Local\Packages\FOLDER1\FOLDER2\*robotknow*" /A-D /B /S 2>nul
DIR outputs to handle STDOUT of background command process
just the names of all files matching the wildcard pattern *robotknow* because of option /A-D (attribute not directory)
even on file having hidden attribute set because of using option /A and not excluding attribute hidden
in bare format because of option /B
with full qualified path because of option /S
found in specified directory or any subdirectory also because of option /S.
It is possible that DIR does not find any file system entry matching these criteria in which case it outputs an error message to handle STDERR. This error message is suppressed by redirecting it to device NUL.
Read 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 captures all lines output to handle STDOUT of started command process and processes them line by line after started cmd.exe terminated itself.
FOR ignores empty lines which do not occur here. FOR ignores by default also all lines starting with a semicolon because of eol=; is the default for end of line character option. But a full qualified file name consisting of full file path, file name and file extension cannot start with ; and so default end of line option can be kept in this case. FOR splits up the lines by default into substrings with using normal space and horizontal tab character as string delimiters and assigns just first space/tab separated substring to specified loop variable. This line splitting behavior is not wanted here because of file path could contain a space character. For that reason option delims= is used to define an empty list of delimiters which disables the line splitting behavior.
So FOR assigns to specified and case-sensitive interpreted loop variable I the full qualified file name found and output by DIR and runs the command XCOPY.
XCOPY is executed with source being the full qualified path of found file referenced with %%~dpI always ending with a backslash concatenated with wildcard * and destination directory being specified target folder C:\hello.
The appended backslash at end of destination directory path makes it 100% clear for XCOPY that the destination is a directory and not a file which prevents the prompt if destination means a directory or a file. \ at end makes also usage of option /I unnecessary and XCOPY creates the entire destination directory structure if necessary.
The other XCOPY options are for really copying all files including files with hidden attribute set in directory containing the file matching the wildcard pattern *robotknow* with all subdirectories including empty subdirectories to destination directory with keeping attributes including read-only attribute.
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.
dir /?
echo /?
endlocal /?
set /?
setlocal /?
xcopy /?
See also the list of predefined Windows Environment Variables.
I need to write a .bat or .cmd script that will find all instances of file type .log in the directory it is run from, and for each of those search it for "searchstring", counting how many times it appears. Then I need to rename the file (original name: "[name].log") to "name.log". This is to enable me to get a very quick visual count of the number of errors in a file (which is part of what the log contains).
I've already got the for loop that locates all *.log files, but how do I count instances of a particular string?
try this:
for /f "tokens=2delims=:" %a in ('find /c "string" *.log') do #set /a count+=%a
echo %count%
Code is for shell prompt. For shell file replace %a with %%a.
I have a daily process which generates some zip files out of files that are being created by other processes. I need to create a daily log file which indicates the timestamps the contents of one specific file of each zip file that is found.
I created the following batch script which seemed to work yesterday on my test system, but not anymore today, no idea why...
set VersionDirectory=C:\Test\VersionX\
set ResultOutputFile=C:\Test\LogFile.txt
for /f %%f in ('dir /b %VersionDirectory%\Installable\Packages\pattern*.zip') do (
mkdir %temp%\%%f\
unzip -extract -dir %VersionDirectory%\Installable\Packages\%%f %temp%\%%f\ > nul
for %%a in (%temp%\%%f\InstallScript.xml) do set InstallScriptXMLDate=%%~ta
rmdir /s /q %temp%\%%f\
echo %%f [package from %InstallScriptXMLDate%] >> %ResultOutputFile%
)
Short summary of what this file is supposed to do:
Loop through each pattern*.zip file in C:\Test\VersionX\ directory
unzip this file to the %temp%\%%f directory (where %%f is the filename)
Get the timestamp of the %temp%\%%f\InstallScript.xml and put it in the %InstallScriptXMLDate% variable
Delete the %temp%\%%f directory
Echo the filename (%%f) and timestamp (%InstallScriptXMLDate%) into the log file
As of now the log file just contains the filenames, followed by the string '[package from ]' string, but missing the actual date timestamp
The unzipping and removing of the zip files is working flawlessly, it's just the timestamp that's not being set.
You are setting a variable and using it in the same block. This cannot work in cmd because environment variables are expanded when a statement is parsed not when it's executed. So when the loop is run all variables have already been replaced with the values they had before the loop.
Put
setlocal enabledelayedexpansion
at the start of your batch and use !InstallScriptXmlDate! instead of %InstallScriptXmlDate%.
Another note: for is perfectly capable of iterating over files by itself, you almost never need to iterate over dir /b output with for /f. In fact, it can introduce problems that can be avoided with
for %%f in (%VersionDirectory%\Installable\Packages\pattern*.zip)