I'm writing a batch to kill several processes if they are running and subsequently delete the files whether they were running or not. I'm very new to this so please bear with the horrible script.
#echo off
echo deleting files...
tasklist /FI "IMAGENAME eq file1.exe" | find /I /N "file1.exe"> nul 2>&1
if errorlevel 1 (
echo file1.exe is not running
goto :delete
) else (
taskkill /F /IM file1.exe> nul 2>&1
if errorlevel 1 (
echo Killing process file1.exe... Failed!
) else (
goto :delete
)
)
:delete
ren c:\file1.exe c:\tmp.tmp> nul 2>&1
if errorlevel 1 (
echo Deleting file1.exe... Access Denied!
) else (
del /q /f "C:\tmp.tmp"> nul 2>&1
echo Deleting file1.exe... Success!
)
rather than doing this for all 8 files, i'd like to use two lists for filenames and filepaths and run them both through a for loop at the same time. unfortunately i can't find much info online on how to loop through 2 lists in tandem and the following script would run into obvious problems:
for %%f in (file1 file2 file3) do
for %%p in (path1 path2 path3) do (
taskkill %f etc
del %p etc
)
some help would be appreciated!
You only need a single FOR loop with the full paths, and then use the %~nx modifiers to get the name only.
Here is the pseudo code:
for %%F in ("path1\file1" "path2\file2" "path3\file3") do (
taskkill %%~nxF
del %%F
)
For more information about the modifiers, use help for or for /? from the command line, and look toward the bottom of the help.
But there are times when you want to process lists of paired values. This can be done easily enough with two loops. The first loop iterates delimited pairs, and the 2nd FOR /F loop parses out each value from the pair. You just need to choose a delimiter that never appears in a value.
Using space delimiters:
for %%A in ("val1a val1b" "val2a val2b" "val3a val3b") do (
for /f "tokens=1,2" %%B in ("%%~A") do (
echo value1 = %%B
echo value2 = %%C
echo(
)
)
Using pipe delimiters: Note how you can span multiple lines for improved readability
for %%A in (
"val 1a|val 1b"
"val 2a|val 2b"
"val 3a|val 3b"
) do for /f "delims=| tokens=1,2" %%B in ("%%~A") do (
echo value1 = %%B
echo value2 = %%C
echo(
)
Related
I have a batch to check the duplicate line in TXT file (over one million line) with 13MB, that will be running over 2hr...how can I speed up that? Thank you!!
TXT file
11
22
33
44
.
.
.
44 (over one million line)
Existing Batch
setlocal
set var1=*
sort original.txt>sort.txt
for /f %%a in ('type sort.txt') do (call :run %%a)
goto :end
:run
if %1==%var1% echo %1>>duplicate.txt
set var1=%1
goto :eof
:end
This should be the fastest method using a Batch file:
#echo off
setlocal EnableDelayedExpansion
set var1=*
sort original.txt>sort.txt
(for /f %%a in (sort.txt) do (
if "%%a" == "!var1!" (
echo %%a
) else (
set "var1=%%a"
)
)) >duplicate.txt
This method use findstr command as in aschipfl's answer, but in this case each line and its duplicates are removed from the file after being revised by findstr. This method could be faster if the number of duplicates in the file is high; otherwise it will be slower because the high volume data manipulated in each turn. Just a test may confirm this point...
#echo off
setlocal EnableDelayedExpansion
del duplicate.txt 2>NUL
copy /Y original.txt input.txt > NUL
:nextTurn
for %%a in (input.txt) do if %%~Za equ 0 goto end
< input.txt (
set /P "line="
findstr /X /C:"!line!"
find /V "!line!" > output.txt
) >> duplicate.txt
move /Y output.txt input.txt > NUL
goto nextTurn
:end
#echo off
setlocal enabledelayedexpansion
set var1=*
(
for /f %%a in ('sort q42574625.txt') do (
if "%%a"=="!var1!" echo %%a
set "var1=%%a"
)
)>"u:\q42574625_2.txt"
GOTO :EOF
This may be faster - I don't have your file to test against
I used a file named q42574625.txt containing some dummy data for my testing.
It's not clear whether you want only one instance of a duplicate line or not. Your code would produce 5 "duplicate" lines if there were 6 identical lines in the source file.
Here's a version which will report each duplicated line only once:
#echo off
setlocal enabledelayedexpansion
set var1=*
set var2=*
(
for /f %%a in ('sort q42574625.txt') do (
if "%%a"=="!var1!" IF "!var2!" neq "%%a" echo %%a&SET "var2=%%a"
set "var1=%%a"
)
)>"u:\q42574625.txt"
GOTO :EOF
Supposing you provide the text file as the first command line argument, you could try the following:
#echo off
for /F "usebackq delims=" %%L in ("%~1") do (
for /F "delims=" %%K in ('
findstr /X /C:"%%L" "%~1" ^| find /C /V ""
') do (
if %%K GTR 1 echo %%L
)
)
This returns all duplicate lines, but multiple times each, namely as often as each occurs in the file.
So I am using a batch to go through a text file line by line. The reason why I can't do a regular search is because I need to see what is written on each line and then determine how I want to process the next line. Anyway, my basic code is:
for /f "usebackq delims=" %%a in (%SourceLicenseFile%) do (
Set LineofFile=%%a
echo !LineofFile! | find /i "TIMESTAMP" >nul
if !errorlevel! EQU 0 (
FOR %%b IN (!LineofFile!) DO SET LogDate=%%b
)
echo %%a | find /i "(LOGTIME) IN" >nul
if !errorlevel! EQU 0 (
FOR %%d IN (!LineofFile!) DO SET Username=%%d
FOR /f "tokens=1" %%c IN ("!LineofFile!") DO (
SET Logtime=%%c
)
echo !LogDate! !LogTime! !Username!
>> !ExportLicenseLog! echo !LogDate! !LogTime! !Username!
)
)
I believe the echo is slowing down this processing. I have a file with thousands of lines and it would take me over a minute to process. Is there another method I can use to go through each line quicker?
Yes, the echo ... | find ... slowdown the process, not because the echo, but for the pipe...
You have not clearly explained the purpose of your program. However, to check if !LineofFile! variable have the "TIMESTAMP" string, you may use this code:
if "!LineofFile:TIMESTAMP=!" neq "!LineofFile!" (
echo TIMESTAMP string found in LineofFile variable
)
This code means: "Try to remove TIMESTAMP string from LineofFile variable. If the string was found, it was removed, so the replaced value is different than the original".
You don't need the echo:
find /i "SOMETHING"<%SourceLicenseFile%
Escape thus ^< inside a for parentheses.
OK. I got it. Using substitution is MUCH faster
for /f "usebackq delims=" %%a in (%SourceLicenseFile%) do (
Set LineofFile=%%a
if not "x!LineofFile:TIMESTAMP=!" EQU "x!LineofFile!" (
FOR %%b IN (!LineofFile!) DO SET LogDate=%%b
)
if not "x!LineofFile:IN:=!" EQU "x!LineofFile!" (
FOR /f "tokens=1,5" %%c IN ("!LineofFile!") DO (
SET Logtime=%%c
SET Username=%%d
)
if "!LogDate!" NEQ "DATE NOT FOUND" (
echo !LogDate! !LogTime! !Username!
>> !ExportLicenseLog! echo !LogDate! !LogTime! !Username!
)
)
Set /A LineNumber=!LineNumber!+1
Set /A PercentDone=!LineNumber!/%TotalLines%
)
I have the following batch file which outputs limited info. How do I suppress all output from this batch file? What I'd like to see is after I enter the name of the batch file and hit enter, the next thing that shows up on screen is "C:>".
#ECHO OFF
SETLOCAL EnableDelayedExpansion
(for /f "tokens=1 delims=;" %%A in (C:\ALL.txt) do (
#echo %%A | find /i "\"
if errorlevel 1 (
DEL "D:\!mypath!%%A" >> C:\ALL-OUT.txt 2>&1
) ELSE (
set mypath=%%A
)))
#endlocal
I think it all boils down to this line which I use to test whether %%A contains backslash:
#echo %%A | find /i "\"
I tried adding " 1>null" to the end of the line. It worked to suppress all output. However, it also created a file named "null".
Since "For /f" parses files line by line, I wonder if there is a way to incorporate the echo command in "For /f"?
The NUL device is referenced with nul, not null. >null creates a file named null.
for your second question: you can redirect the output of a command block with a single redirection (in fact, this is way faster)
#ECHO OFF
SETLOCAL EnableDelayedExpansion
(
for /f "delims=;" %%A in (C:\ALL.txt) do (
echo %%A | find "\" >nul
if errorlevel 1 (
DEL "D:\!mypath!%%A"
) ELSE (
set mypath=%%A
)
)
) > C:\ALL-OUT.txt 2>&1
endlocal
I am trying to have this script go to the next part if the error level of a ping to a computer does not equal 0, but I cannot get it to work. The output says the syntax is not correct. Thank you.
#echo
setlocal EnableDelayedExpansion
for /f %%a in (main.txt) do (
ping -n 1 %%a > NUL
IF %ERRORLEVEL%==0 (GOTO :COPY) ELSE GOTO :SKIP
:COPY
ROBOCOPY C:\Blah C:\Bloh
ECHO FILE COPIED
:SKIP
ECHO FILE NOT COPIED
)
You should try this:
#echo
setlocal EnableDelayedExpansion
for /f %%a in (main.txt) do (
ping -n 1 %%a >NUL
IF "!ERRORLEVEL!"=="0" (
ROBOCOPY "C:\Blah" "C:\Bloh"
ECHO FILE COPIED
) ELSE (
ECHO FILE NOT COPIED
)
)
PAUSE
There are a couple of things wrong with your code. First of all, you enable Delayed Expansion, but don't actually use it, only variables inside ! get expanded delayed. I also put quotes around your filepaths, to protect them against paths with spaces and stuff. Finally, goto and labels don't work inside for loops, so you need to replace them with if else logic
goto :Label inside a parenthesised block of code like for loops breaks the block/loop context, so the code at the label is executed as if it were outside of the block/loop. Therefore you need to work around that.
Dennis van Gils points out a way how to do it -- using if/else logic (his method as well as the following slightly modified snippet (applying numeric comparison) both require delayed expansion):
setlocal EnableDelayedExpansion
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
if !ErrorLevel! EQU 0 (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
) else (
echo FILE NOT COPIED
)
)
endlocal
Or like this, avoiding the necessity of delayed expansion:
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
if ErrorLevel 1 (
echo FILE NOT COPIED
) else (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
)
)
To check the ErrorLevel against (non-)zero, you can also use the && and || operators:
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A || (
echo FILE NOT COPIED
) && (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
)
)
Finally, if you do want to keep the goto :Label structure, you need to use a sub-routine in order to move this part of the code outside of the () block (you also do not need delayed expansion here):
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
call :SUB "C:\Blah" "C:\Bloh"
)
exit /B
:SUB
if %ErrorLevel% NEQ 0 goto :SKIP
robocopy "%~1" "%~2"
echo FILE COPIED
:SKIP
goto :EOF
Script:
pushd "\\server1\share\Data\"
for %%p in (*.pdf) do if /i ".pdf"=="%%~xp" for /f "tokens=1 delims=_" %%n in ("%%~np") do (
copy "%%~fp" ""\\server2share\data\%%~n\%%~nxp" dir >> \\server\share\logfile.txt
)
I want to log the output everytime this command runs. The script copies pdf's based on name. But when i run the script. No log file is created.
EDITED to adapt to comments
pushd "\\server1\share\Data\"
set "logFile=\\server\share\logfile.txt"
for %%p in (*.pdf) do if /i ".pdf"=="%%~xp" for /f "tokens=1 delims=_" %%n in ("%%~np") do (
if not exist ""\\server2share\data\%%~n\" (
>>"%logFile%" echo SKIPPED : "%%~nxp"
) else (
copy "%%~fp" "\\server2share\data\%%~n\%%~nxp"
if errorlevel 1 (
>>"%logFile%" echo FAILED : "%%~nxp"
) else (
>>"%logFile%" echo COPIED : "%%~nxp"
)
)
)
popd
You have a dir command in a strange place, changed to echo. And, i'm not sure all the paths are right.
pushd "\\server1\share\Data\"
for %%p in (*.pdf) do if /i ".pdf"=="%%~xp" for /f "tokens=1 delims=_" %%n in ("%%~np") do (
md "\\server2share\data\%%~n" 2>nul
copy "%%~fp" "\\server2share\data\%%~n\%%~nxp"
dir >> \\server\share\logfile.txt
)
(untested)
I'm assuming the way your scrip is arranged from your original post.
If you want to execute a sequence of separate commands, they need to be separated by & or be on separate lines.
You had an extra " in your copy command
Inserted a md command with error-message-suppression to ensure the destination directory exists.
This will create a log of what is shown on the cmd screen while it is running, but you will not see any output on the screen. You can use a tee filter if you also need to see the screen output.
mybatch.bat>file.log