The function of this command is to input the port to find the corresponding pid, but I don't understand what the ^ symbol is used for, can someone explain it?
for /f "tokens=5" %a in ('netstat -aon ^| find ":3306" ^| find "LISTENING"') do echo %a
From https://ss64.com/nt/syntax-redirection.html
Escape Character
^ Escape character.
Adding the escape character before a command symbol allows it to be treated as ordinary text. These characters which normally have a special meaning can be escaped and then treated like regular characters : & \ < > ^ |
e.g. Echo THIS ^& THAT
Echo Heading1 ^| heading2 ^| heading3
Echo The Escape character looks like this ^^
Related
I'm writing a subroutine in Batch that will extract text in the middle of a string, and can accept two sets of characters (like a word or phrase), rather than individual delimiters, as its arguments. In addition, I'd like to get the index position of the first character of the lookup value. The way I'm going to do this is by looping through characters and eliminating it one by one from both sides until the lookup string sets match the beginning and end of the surviving string.
Character elimination is done using variable offset/index like in this one: !_str:~%_idx%!, where _str is the string to search, and _idx is the offset count, then pipe it to FINDSTR /B to see if the lookup string matches the beginning characters of the surviving string from the loop. So far, no problem. But when I do the process for the second lookup string to the right side of the string being searched, and piped it to FINDSTR /E to see if the second lookup string matches the end of the surviving string from the loop, it doesn't seem to work.
From my understanding from these sources,
Command Prompt > FINDSTR /?
FINDSTR
FINDSTR switches /B and /E match lookup strings that are at the beginning and end of a line, respectively.
So, out of desperation, I created some tests with different variations even though I know that these variations are not the issue, but I still did it, anyway. Here's what I've tried so far:
title FINDSTR_TEST
echo off
cls
setlocal EnableDelayedExpansion
set "_str=Hello World"
echo String to search: %_str%
echo:
echo Matches pattern if at the BEGINNING of a line.
echo 1: & echo %_str% | findstr /b "Hello"
echo 2: & echo %_str% | findstr /b /l "Hello"
echo 3: & echo %_str% | findstr /b /C:"Hello"
echo:
echo:
echo Matches pattern if at the END of a line.
echo 1: & echo %_str% | findstr /e "World"
echo 2: & echo %_str% | findstr /e /l "World"
echo 3: & echo %_str% | findstr /e /C:"World"
echo:
echo ERRORLEVEL: %errorlevel%
pause
endlocal
exit
Here's the actual result:
String to search: Hello World
Matches pattern if at the BEGINNING of a line.
1:
Hello World
2:
Hello World
3:
Hello World
Matches pattern if at the END of a line.
1:
2:
3:
ERRORLEVEL: 1
Press any key to continue . . .
But this is what I was expecting:
String to search: Hello World
Matches pattern if at the BEGINNING of a line.
1:
Hello World
2:
Hello World
3:
Hello World
Matches pattern if at the END of a line.
1:
Hello World
2:
Hello World
3:
Hello World
ERRORLEVEL: 1
Press any key to continue . . .
Two quick questions here:
Is there any problem with my code especially where /E switch is being used?
Aren't these /L and /C:string switches redundant? It appears to me that they do the same thing.
Any clarifications on these matter will be appreciated.
Thank you all very much.
As a follow up of my comment, you should be able to see exactly what is happening, if you create a three line batch file, exactly like this:
Echo Hello World | FindStr /B "Hello"
(Echo Hello World) | FindStr /E "World"
#Pause
The output will show whitespace, where you didn't specifically add it:
C:\Users\SpaghettiCode>Echo Hello World | FindStr /B "Hello"
Hello World
C:\Users\SpaghettiCode>(Echo Hello World ) | FindStr /E "World"
Press any key to continue . . .
My preferred solution, is to use Set /P instead of Echo, because the output can be specifically terminated using doublequotes, and redirection. For example:
#Echo Off
SetLocal EnableExtensions
Title FINDSTR_TEST
ClS
Set "_str=Hello World"
Echo String to search: %_str%
Echo(
Echo Matches pattern if at the BEGINNING of a line.
Echo 1:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /R "Hello"
Echo 2:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /L "Hello"
Echo 3:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /B /I /R /C:"Hello"
Echo 4:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "^Hello"
Echo 5:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "^Hello\>"
Echo(
Echo(
Echo Matches pattern if at the END of a line.
Echo 1:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /R "World"
Echo 2:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /L "World"
Echo 3:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /E /I /R /C:"World"
Echo 4:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "World$"
Echo 5:& Set /P "=%_str%" 0< NUL | %SystemRoot%\System32\findstr.exe /I /R "\<World$"
Echo(
Echo ERRORLEVEL: %ErrorLevel%
Pause
Exit /B
As you can see, I added a couple of extra, options to each of the examples, which for me, are probably more useful for your provided example string. You'll also note that I moved your ampersands, after the test numbers, to show you that you were printing number colon space, not number colon.
As others already pointed out, the SPACE in front of the pipe is output as well and therefore included in the string processed by findstr.
However, to safely pass a string over a pipe in general, you should use the following syntax, given that delayed variable expansion is disabled (which is the default setting) and the string is stored in variable _str:
cmd /V /D /C echo(!_str!| findstr /E /I "world"
This enables delayed expansion in the child cmd instance (/V), so variables are expanded as late as possible, so no special characters can harm. The harmful SPACE is of course left out here.
The echo command would cause the pipe to initiate a new cmd instance anyway since echo is a cmd-internal command, so the overall performance is not degraded.
Passing multiple strings by echo over a pipe becomes a little bit tricky, because something like:
(echo abc&echo def) | …
or:
(
echo abc
echo def
) | …
introduces additional SPACEs, which result from the conversion of such command blocks to single command lines and therefore also by replacing line-breaks by ampersands. For example, for the former example, the command echo looks like this:
(echo abc & echo def ) | …
However, there is a way, namely to include escaped ampersands, which are taken literally:
(echo abc^& rem/ & echo def^& rem/) | …
or:
(
echo abc^& rem/
echo def^& rem/
) | …
The rem/ command is just a harmless and ignored remark, and the / ensures that subsequent commands are not treated as remarks but are executed as expected.
Of course all this can be combined with cmd /V /D /C as shown above.
I am trying to get the name of a file containing a particular string. The following command does that.
dir /a:-D /b | findstr /i "fileName.jar"
I'm trying to run it through a bat file using the following code.
for /F "delims=" %%a in ('dir /a:-D /b | findstr /i "fileName.jar"') do set "batToolDir=%%a"
But I am getting the below error.
| was unexpected at this time.
I need to get the name of the file containing a certain string. How can I achieve this? Any help would be much appreciated.
"below error" ??
What you need is to escape the | to tell cmd that the pipe is part of the command to be executed, not of the for. You need to do this with all redirectors.
The escape character is ^, so substitute ^| for | within the parentheses. ANy such awkwardness, try inserting ^ before the character causing the problem...
After trawling through S.O. I've managed to piece together my function so it works, but I don't understand something about it. I'm basically trying to ensure that a file I want to use doesn't have double quotes in it. I've used findstr with the /m option which is returning the filename.
When I run the command from the cmd line it works with this:
findstr /V /L /m "\"" filename.txt
When filename has no double quotes it returns the filename, if it does have double quote it returns blank / null /whatever. Exactly what I want.
So I wanted to capture this result in a variable, using a solution on this website. I've discovered this works:
setlocal enabledelayedexpansion
set test=
for /F %%a in ('findstr /V /L /m ^"^\^"^" filename.txt') do (#set test=!test! %%a)
echo %test%
So my question: My search string needs to be escaped so goes from:
"\""
and becomes:
^"^\^"^"
but I don't understand why I have to do that. Can anybody explain?
To answer your question, the reason why your search string needs to be escaped (^ escaped) is ... none. In your case you search string does not need to be escaped.
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "delims=" %%a in ('
findstr /l /m /v "\"" *.txt
') do echo %%a
You need the \" escape because the findstr argument handling (more here) but the ^" scaping is not required.
But there are some cases where the ^ quote scaping is needed. The reason for the escaping in those cases is that the command inside the for /f is executed in a separate cmd instance. This started instance could (or not) include its own set of quotes
cmd /c " ...... "
and the quotes in your command could interfere in the cmd parsing of the command to execute.
But if you escape the quotes (cmd escaping, that is ^"), they will not be parsed as closing/opening quotes, but as a literal without a special meaning for the cmd parser, so they could be hadled later.
This for loop (reduced minimal example);
#echo off
for %%a in (help -help --help /help ? /?) do (
echo %%a
)
chokes on the 2 elements with a '?' character. It outputs
C:\Temp>test.bat
help
-help
--help
/help
C:\Temp>
So it just quits the loop when it hits the first '?'.
What is the proper escape sequence for this set? Tried a bunch of stuff, double quotes, carets, backslash, etc. but nothing seems to work.
Another option is to use linefeeds within a FOR /F string. FOR /F will treat each line as an independent string. Below I show four ways to do the same thing.
#echo off
setlocal enableDelayedExpansion
:: Define LF to contain a linefeed character
set ^"LF=^
^" The above empty line is critical. DO NOT REMOVE
:: Option 1
:: Embed linefeeds directly in the string literal
for /f %%A in ("help!LF!-help!LF!--help!LF!/help!LF!?!LF!/?") do (
echo(%%A
)
echo(
:: Option 2
:: Define a variable with spaces and use search and replace
:: to substitue linefeeds
set "help=help -help --help /help ? /?"
for %%L in ("!LF!") do for /f %%A in ("!help: =%%~L!") do (
echo(%%A
)
echo(
:: Option 3
:: Embed linefeed directly in string without LF variable
for /f %%A in (^"help^
-help^
--help^
/help^
?^
/?^") do (
echo(%%A
)
echo(
:: Option 4
:: Embed linefeed directly in search and replace without LF variable
for /f %%A in (^"!help:^ ^=^
!^") do (
echo(%%A
)
I prefer option 2. I find it to be the easiest to read, yet still be compact.
Note that MC ND and I both use echo(%%A. This is necessary to prevent echo /? from displaying the help for the ECHO command.
Nothing seems to work because nothing will work.
In its simplest form (for %%x in (set) do ...), when the for command iterates over the elements in the set, it will test if the element contains a * or a ?. In this case, it is considered a file wildcard and will search for files matching the indicated expression. You can test it in your case placing a file with a single character name and no extension in the folder containing the batch file, and the ? will match it and you will see it in the output.
And as far as i know there is no way to avoid it. This is the way for command is intended to work.
You can construct something similar to what you are trying but will need another approach
#echo off
setlocal
set "opt.a=help"
set "opt.b=-help"
set "opt.c=--help"
set "opt.d=/help"
set "opt.e=?"
set "opt.f=/?"
for /f "tokens=2 delims==" %%a in ('set opt.') do (
echo(%%a
)
endlocal
In this sample each value is in a environment variable and the set is retrieved via a set command and output processed with the options of for command. It is just one option. You need the values as line separated strings to be processed with a for /f.
While I personally think dbenham has provided the best answer, I want to add that in some cases FOR /F loop should be provided with options:
tokens=* - this would disable tokenization of lines (or, in case you need it, you could set delims to whatever you want), allowing you to have spaces in strings;
usebackq - this would allow you to have double quotes in strings. However, in this case, single quotes need to be escaped with caret - ^', and surrounding double quotes should be replaced with single quotes:
(set RN=^
%= \r\n =%
)
for /f "usebackq tokens=*" %%A in ('^'quotes^'!RN!"double quotes"!RN!`backquotes`') do (
echo:%%A
)
As for the original question, there are few other options available. Alex was onto something with his answer, but it didn't cover how to actually iterate through the list. To do it you need to chain echo commands. You start with echo: and use ^&echo: to echo all subsequent strings/variables:
set "var=line1"
for /F "usebackq delims=" %%G in (`
echo:%var%^&
echo: line2 * ? ^^^^ ^^^& ^^^< ^^^> ^^^| ^^^" ' ^` ^) ^&
echo: ^ ^ line3 ^ ^ ^&echo:li
ne4^&echo ^&echo: ^&echo:/?
`) do (
echo "%%G"
)
This will give you:
"line1"
" line2 * ? ^ & < > | " ' ` ) "
" line3 "
"li ne4"
"ECHO is on." # System language specific
" "
"/? "
As shown, you can break lines in any way, as long as you keep ^& and echo: intact (be wary of spaces).
Using colon instead of space after echo will sanitize values like ON, OFF or /?. You can also use some other characters, like (, but i find colon more readable.
Line-breaks are allowed, but all successive whitespaces (spaces and line-breaks) are replaced with a single space (additional spaces can be enforced by escaping them with single caret ^). echo ^& will count as echo with no parameters and will display current echo setting, echo:^& will give an empty line (FOR /F ignores empty lines), and echo: ^& will give you .
^ & < > | " need to be escaped with three carets. ` ) need to be escaped with a single caret.
Without usebackq option you don't have to escape `, but you'll need to escape ' with three carets. You'll also need to use single quotes instead of surrounding backquotes.
You can avoid excessive escaping if you put the expression inside double quotes like this:
for /f "usebackq delims=" %%G in (`"echo:%var%&echo: line2 * ? ^^ ^& ^< ^> ^| ' ` "abc" ^) &echo &echo: &echo:/?"`) do (
echo "%%G"
)
This will give you:
"line1"
" line2 * ? ^ & < > | ' ` "abc" ) "
"ECHO is on." # System language specific
" "
"/?"
To chain echo commands you use &echo: (note, no caret).
Line-breaks are not allowed. Spaces are preserved.
" cannot be escaped, but could be used if there is an even number of them. You don't need to escape ' and `.
Again, without usebackq option you'll need to use single quotes instead of surrounding backquotes.
If you use a for /f loop it works without escaping the ? characters, although the loop doesn't work the same way:
C:\Users\Alex\Downloads\test>for /f "tokens=* delims=" %a in ('echo help -help --help /help ? /?') do echo %a
C:\Users\Alex\Downloads\test>echo help -help --help /help ? /?
help -help --help /help ? /?
for /f "delims=" %%a in ('"%systemRoot%\system32\find.exe" /?') do #echo %%a
Yes, the previous line works. Not much useful but works. But trying write a batch file to answer another question, i faced something like
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" ^< "c:\something.txt"') do #echo %%a
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" "c:\something.txt"') do #echo %%a
Both of the previous lines return The filename, directory name, or volume label syntax is incorrect
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" ^< c:\something.txt' ) do #echo %%a
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" c:\something.txt' ) do #echo %%a
Both of the previous lines return The system cannot find the file specified
I've been unable to make it work, neither scaping the quotes, doubling them, preceding with backslashes, changing to single quotes to backquotes and setting the corresponding option in for command, all the combinations that i tried failed.
If the command to run is quoted and it takes quoted arguments it fails.
And yes, i know the quotes surounding the find are not needed, and if removed, any of the previous four lines will work (ignoring the output, delims, tokens)
But in the case where the quotes surounding the command are really needed (and i know systems where 8dot3name behaviour is disabled), is there any way to make it work? what am i missing here?
Here are two solutions.
1) has surrounding double quotes and removed ^ escape character.
2) uses find as it is on the path.
for /f %%a in ('""%systemRoot%\system32\find.exe" /c /v "" < "c:\something.txt""') do #echo %%a
for /f %%a in (' find.exe /c /v "" ^< "c:\something.txt"') do #echo %%a
It's to do with launching an extra cmd process to run the command-line inside the for command.
Curiously, these three commands fail differently in an even simpler context.
for /f %%a in (' "c:\windows\system32\find.exe" /c /v "" something.txt ') do #echo %%a
The system cannot find the path specified.
for /f %%a in (' "c:\windows\system32\findstr.exe" /n "." something.txt ') do #echo %%a
The directory name is invalid.
for /f %%a in (' "c:\windows\notepad" "something.txt" ') do #echo %%a
'c:\windows\notepad" "something.txt' is not recognized as an internal or external command, operable program or batch file.
This last one gives a clue that the outer quotes are being stripped.
Windows 8.1 32 bit
I think the quote issue is described here in cmd /? when a child process is invoked:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
It is somewhat easier to put the first token from the instruction of the for-loop into a token without quotes.
for /f "delims=" %%a in (
' if defined OS "C:\my folder with spaces\consoleapp.exe" /param1:"value" '
)do #echo %%a