In windows I have a batch file, named the same as a folder in its current directory.
I am trying to recursively launch a specific .exe file that is a few folders deep in the above mentioned folder.
I am trying:
set "NAME=DRAGON QUEST XI S.exe"
for /R "%~n0\" %%I in ("%NAME%") do if exist "%%I" start "" /WAIT "%%I"
But that is trying to launch DRAGON.exe, then QUEST.exe, then XI.exe then S.exe and I don't understand why.
I think it will have something to do with quotes, but have tried adding/removing them from everywhere I could see and no luck.
Adding a wildcard to ("%NAME%*") works, but could be troublesome if there is more than one .exe that starts with DRAGON.
What you have encountered is caused by something that I consider a terrible design flaw of the for /R loop and expansion of its meta-variable together with the ~-modifiers.
Create the following batch file and execute it:
#for /R "%~dp0." %%I in (foo bar "foo bar" "foo bar?") do #(
echo/
echo Modifier '~nx': %%~nxI
echo No modifiers : %%I
echo Modifier '~' : %%~I
echo Modifier '~f' : %%~fI
echo '~' and quoted: "%%~I"
)
The output will be this, given that there are two files foo bar and foo barS available in the directory of the batch file:
Modifier '~nx': foo
No modifiers : D:\test dir\foo
Modifier '~' : D:\test dir\foo
Modifier '~f' : D:\test dir\foo
'~' and quoted: "D:\test dir\foo"
Modifier '~nx': bar
No modifiers : D:\test dir\bar
Modifier '~' : D:\test dir\bar
Modifier '~f' : D:\test dir\bar
'~' and quoted: "D:\test dir\bar"
Modifier '~nx': "foo bar"
No modifiers : D:\test dir\"foo bar"
Modifier '~' : D:\test dir\"foo bar"
Modifier '~f' : D:\test dir\"foo bar"
'~' and quoted: "D:\test dir\"foo bar""
Modifier '~nx': foo bar
No modifiers : D:\test dir\foo bar
Modifier '~' : D:\test dir\foo bar
Modifier '~f' : D:\test dir\foo bar
'~' and quoted: "D:\test dir\foo bar"
Modifier '~nx': foo barS
No modifiers : D:\test dir\foo barS
Modifier '~' : D:\test dir\foo barS
Modifier '~f' : D:\test dir\foo barS
'~' and quoted: "D:\test dir\foo barS"
It seems that the ~-modifiers (which remove potential surrounding quotation marks) are applied too late, namely after preceding an iterated item with the absolute root path. A standard for loop does not precede anything, so the problem cannot arise and the ~-modifiers may see a quoted string (remove /R "%~dp0." from the batch file, run it again from its parent directory and check quotation in the output).
The line that reflects our situation is the one '~' and quoted: "D:\test dir\"foo bar""; due to its wrong quotation, the command parser unintentionally recognises two different tokens "D:\test dir\"foo and bar"" in the expanded value of "%%~I".
To return to your code, there are the following options to work around the bad behaviour of for /R:
Append a wildcard (best to use ? since it matches just a single character and therefore reduces the chance of matching unwanted items) and then recheck the name of the iterated item:
set "NAME=DRAGON QUEST XI S.exe"
for /R "%~n0" %%I in ("%NAME%?") do (
if /I "%%~nxI"=="%NAME%" (
if exist "%%I" (
ECHO start "" /WAIT "%%I"
)
)
)
Let dir /S return the matching file(s) and use for /F to process its output:
set "NAME=DRAGON QUEST XI S.exe"
for /F "delims=" %%I in ('dir /S /B /A:-D-H-S "%~n0\%NAME%"') do (
if exist "%%I" (
ECHO start "" /WAIT "%%I"
)
)
Related
I've got the following pattern :
[AAAAAA] Title - 1234 (AAAAAA)[Something that changes].mkv
I'd like to only keep :
Title - 1234
The AAAAAA parts are always the same : 10 letters for the first set, and 4 numbers + 1 letter for the second set.
The Title - 1234 part changes constantly.
The [Something that changes] part changes constantly.
Is there a way to remove what's before ] and after (, so that I only keep the Title and the Episode n° ?
I don't mind making multiple "rename" commands (I do that in batch anyway)
Any way to do that ?
Thanks !
use this string substitute:
This find the first "]" and trim everything from beginning
Then trim all after the first "("
#echo off
setlocal enabledelayedexpansion
for %%F in (*.mkv) do (
set "f=%%~F"
set "f=!f:*]=!"
call :trim
echo ren "%%~F" "!f!%%~xF"
)
pause
goto :eof
:trim
SET f=%f:(=&rem.%
goto :eof
output:
C:\Users\fposc\AppData\Local\Temp>ren1
ren "[AAAAAA] Title - 1234 (AAAAAA)[Something that changes].mkv" " Title - 1234 .mkv"
Premere un tasto per continuare . . .
If you want to remove leading and trailing spaces you can include them in the code like this:
#echo off
setlocal enabledelayedexpansion
for %%F in (*.mkv) do (
set "f=%%~F"
set "f=!f:*] =!"
call :trim
echo ren "%%~F" "!f!%%~xF"
)
pause
goto :eof
:trim
SET f=%f: (=&rem.%
goto :eof
output:
C:\Users\fposc\AppData\Local\Temp>ren1
ren "[AAAAAA] Title - 1234 (AAAAAA)[Something that changes].mkv" "Title - 1234.mkv"
Premere un tasto per continuare . . .
Test this and when is ok you can remove the "echo" and left "ren" command or copy the output in a file and then execute.
Use the -replace regex operator:
Get-ChildItem -Filter *.mkv |Rename-Item -NewName {"$($_.BaseName -replace '^\[\p{L}{10}\]\s*([^\(]+).*$','$1').mkv"}
The pattern used
^\[\p{L}{10}\]\s*([^\(]+).*$
... matches:
^ # Start of string
\[ # Literal `[`
\p{L}{10} # 10 consecutive letters
\] # Literal `]`
\s* # Any whitespace
([^\(]+) # Capture the longest possible sequence on non-`(` chars
.* # the rest of the string (eg. `(ABCD1) something something.mkv`)
$ # End of string
We then replace the whole thing with everything we captured in between the ] and (.
Tool zur Imageverwaltung für die Bereitstellung
Version: 10.0.17763.1
Abbildversion: 10.0.17763.253
Funktionsliste:
Funktionsidentität : Browser.InternetExplorer~~~~0.0.11.0
Status : Nicht vorhanden
Funktionsidentität : Hello.Face.17658~~~~0.0.1.0
Status : Installiert
Funktionsidentität : Hello.Face.Migration.17658~~~~0.0.1.0
Status : Installiert
Funktionsidentität : Language.Basic~~~af-ZA~0.0.1.0
Status : Nicht vorhanden
I want to output the lines where the next line contains Status: Installiert.
I know how to find the lines containing the string Installiert, but don't know how to include the whole line before the match.
This command line written into a batch file can be used for this task:
#for /F "usebackq delims= eol=" %%I in ("TextFile.txt") do #for /F "tokens=2 eol= delims=: " %%J in ("%%~I") do #if "%%~J" == "Installiert" (call echo(%%Line%%) else set "Line=%%I"
The outer FOR interprets " as end of line character. So lines starting with " would be ignored by outer FOR.
The inner FOR interprets a space character as end of line character which does not matter here because the space character is also a delimiter. The line splitting is done first by FOR resulting in removing all spaces and colons from beginning of line and so space as end of line character is no problem here.
Thanks goes to aschipfl for these additional information on how the two FOR above with the specified options process the lines in specified text file.
Better would be:
#for /F usebackq^ delims^=^ eol^= %%I in ("TextFile.txt") do #for /F "tokens=2 delims=: eol=" %%J in ("%%~I") do #if "%%~J" == " Installiert" (call echo(%%Line%%) else set "Line=%%I"
The outer FOR is run with an empty list of string delimiters and no end of line character. The inner FOR is run also with no end of line character, but with just colon as string delimiter which is the reason for the space character at beginning of the string to compare.
Both command lines output on execution with file TextFile.txt in current directory containing the posted lines:
Funktionsidentität : Hello.Face.17658~~~~0.0.1.0
Funktionsidentität : Hello.Face.Migration.17658~~~~0.0.1.0
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 /?
echo /?
for /?
if /?
set /?
I'm trying to loop a specific file and see if any line contains a certain word or text and I want to replace the whole line. I am not sure how I am suppose to do it.
Right now this what I have:
#echo off
setlocal enabledelayedexpansion
FOR /F "usebackq delims=" %%G IN ("C:\folder\myfile.properties") DO (
Set Line="transaction.sic.lettreEnvironnementBackend"
IF %%G == %Line% (
replace that line with new text
)
)
pause
endlocal
#echo off
setlocal enabledelayedexpansion
Set "Line=transaction.sic.lettreEnvironnementBackend"
(
FOR /F "usebackq delims=" %%G IN ("C:\folder\myfile.properties") DO (
IF "%%G"=="%Line%" (
echo replacement line
) else (echo %%G)
)
)>replacement_filename
pause
endlocal
Note that the replacement filename should not be the source filename. Once tested, move the replacement file to the original filename if required.
Note also that the instruction will exactly match the contents of line - there's no allowance for any other characters on the line.
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
Also easy in PowerShell.
Get-Content .\OutputFile.txt |
% { if ($_ -eq 'Warning message') { 'NEW WARNING' } else { $_ } }
How to search for the exact match of string(s) using the windows findstr command?
For example: I need to find only the exact match the string store but not
stored, storeday, etc.
The below command returns all strings, store, stored and storeday:
findstr /l /s /i /m /c:"store" "c:\test\*.txt"
Complete script:
set "manifest_folder=C:\Calc_scripts*.*"
set "file_list=C:\Search_results\Search_Input.txt"
set "outputfile=C:\Search_results\Search_results.txt"
(for /f "usebackq delims=" %%a in ("%file_list%") do (
set "found="
for /f "delims=" %%b in ('findstr /r /s /i /m /c:"%%a" "%manifest_folder%"') do (
echo %%a is found in %%~nxb
set "found=1"
)
if not defined found (
echo %%a is not found
)
))> "%outputFile%"
According to the findstr /? help, \< and \> denote word boundaries -- see the following excerpt:
Regular expression quick reference:
. Wildcard: any character
* Repeat: zero or more occurrences of previous character or class
^ Line position: beginning of line
$ Line position: end of line
[class] Character class: any one character in set
[^class] Inverse class: any one character not in set
[x-y] Range: any characters within the specified range
\x Escape: literal use of metacharacter x
\<xyz Word position: beginning of word
xyz\> Word position: end of word
Hence you need to change your findstr command line like this:
findstr /r /s /i /m /c:"\<store\>" "c:\test\*.txt"
So in your complete script it should look like this:
findstr /r /s /i /m /c:"\<%%a\>" "%manifest_folder%"
I have a lot of text files that I need to append the name of the file at the end. I have just DOS commands available. I managed to append the name at the beginning using:
findstr "^" *.txt >new.dat.
Unfortunately I cannot append to the end using findstr "$" *.txt new1.dat.
I cannot understand why the $ (which should be [line position : end of line') is not working.
The second thing I'm trying to replace : (colon character) inside the file with the | (pipe). I use the script:
#echo off setLocal EnableDelayedExpansion
for /f "tokens=* delims= : %%a in (new1.dat) do ( echo "%%a| >>new2.dat ).
The file looks like this:
batch-2016-03-14-08-50-05.txt:6530635|GB|150316|6530635.png
batch-2016-03-14-08-50-08.txt:6530636|GB|150316|6530636.png
I just want to replace the : with the pipe (|)