Filter elements in for - windows

I have the next command that returns the following output
kubectl get pods
Output:
NAME READY STATUS RESTARTS AGE
svc-admin-async-6d4cd4989f-8lzcq 1/1 Running 0 4d7h
svc-admin-c795b488d-kpcsn 1/1 Running 0 3d2h
svc-admin-c795b488d-m9mjg 1/1 Running 0 7d6h
svc-bpm-inbox-77fffc4d89-cx7g7 1/1 Running 0 7d6h
svc-bpm-tasks-654695689d-spvt7 1/1 Running 0 3d17h
svc-bpm-tasks-654695689d-wrclq 1/1 Running 0 3d17h
svc-claim-78b7d8db99-9m6zs 1/1 Running 0 120m
svc-claim-78b7d8db99-qvq9m 1/1 Running 0 120m
I need to list only pods that starts with a given parameter. For example, if the param is svc-bpm-tasks, only should to show:
svc-bpm-tasks-654695689d-spvt7
svc-bpm-tasks-654695689d-wrclq
I have the following script, but I dont know how to filter:
set param_to_filter=%~1
FOR /F "skip=1" %%I in ('kubectl get pods') DO (
:: if %%I starts_with param_to_filter
echo %%I
)
Thanks for your help

FOR /F %%I in ('kubectl get pods^|findstr /i /b /L /C:"%~1"') DO (
should do what you want.
The caret escapes the pipe, telling cmd that the pipe is part of the command to be executed.
findstr finds any string that /b begins with the string %~1, which is the first parameter to the batch.
The skip is no longer needed as the header line would not start with any of the target strings.
The /i is optional, making the match case-insensitive.
! Do not use :: comments in a code block (parenthesised sequence of lines) as it's actually a broken label, which confuses cmd. Use rem in code blocks.
Amended - Since any string may be used for %1, using /L to specify Literal comparison to override the default /r (regex match)
The /c:"string" match also compensates for the possibility of a space in the string %~1. If a space appears in %~1 (by supplying a quoted parameter "one two") then without the /c:, findstr would search for one OR two. With /c:, the search is for oneSpacetwo.

Related

How would I check if a named program is running in a batch script?

For some reason it says awesome even when the program is not open, and even if I put in a window name like "asdfsd" or something random. Can anyone help?
#echo off
:start
tasklist | find /I "WINDOWNAME"
if errorlevel 1 (
echo awesome
)
goto :start
At first, let me recommend not to use find just to find a certain window title in the whole output of tasklist, because the search string might occur somewhere else, like the image name, for example, which could lead to false matches.
Anyway, the tasklist command does not set the exit code (ErrorLevel) when the filter /FI does not find a match, but you could check whether the output begins with INFO:, which is the case when no match was encountered:
:start
timeout /T 1
tasklist /FI "WindowTitle eq WindowName" | findstr /B "INFO:" > nul && (echo goto :start) || (echo awesome)`.
This depends on the returned single line in case of no matches:
INFO: No tasks are running which match the specified criteria.
This text depends on the locale/region/language settings of the system. To make this even locale-independent, you could use the a trick: tasklist, with default output format (/FO TABLE), returns more than a single line when at least a match is encountered, because there is a two-line header followed by the actual matching items; if there is no match, the aforementioned line is the only one returned. So capture the output of tasklist by a for /F loop, using the option skip=1. The for /F loop will then set the exit code to 1 (not the ErrorLevel though) when it does not iterate, and to 0 when it iterates at least once. This exit code can be checked using the conditional execution operators && and ||:
:start
timeout /T 1
(for /F "skip=1" %%I in ('tasklist /FI "WindowTitle eq WindowName"') do rem/) && (echo awesome) || (goto :start)
I inserted the timeout command in order to avoid heavy CPU loads by the goto :start loop.

%errorlevel% returning 0 in loop command

Ok, I've installed Dropbox but it didn't corresponded to what I was looking for so I uninstalled it with Revo Pro.
But, when i open the taskmanager there are still processes related to it running in my computer so I decided to make a batch to look out and delete all files that are related to it.
#echo off
cd c:\
:a
set /p a=Phrase that might be realted to it
for /r %%d IN (*.*) DO (
(
findstr /i /m /c:%a% "%%d"
if "%errorlevel%"=="0" del "%%d"
echo %errorlevel%
)
)
pause
The problem is: when I run findstr using loop even when there is no match for my variable "%a%" in an analized file %errorlevel% returns as 0. But when I use findstr alone and there isn't a match %ERRORLEVEL% returns as 1 and 0 for a match.
If I use it, I'll delete all my PC files haha. What's wrong with the code?
Within a parenthesised series of statements, any %var% is replaced by the value of that variable at the time the verb controlling that statement-sequence (or block) is encountered.
Here, the block is the entire sequence of statements controlled by the for. %errorlevel% is replaced by the status of errorlevel at the time the for is encountered, so probably 0.
If you use
findstr /i /m /c:%a% "%%d"
if not errorlevel 1 del "%%d"
echo %errorlevel%
then the run-time value of errorlevel is used (ie. as it changes through the operation of the loop) and the command means "if errorlevel is not (1 or greater than 1) do this..."
The findstr will set errorlevel to 0 on found, 1 on not found and 2 for file not found(IIRC) so NOT (1 or greater than 1) selects 0 only. Note that in certain esoteric circumstances, errorlevel may become negative, but after a findstr I believe 0..2 is the allowed range.
Not sure what's wrong with the code, but you can probably skip it using the && operand.
findstr /i /m /c:%a% "%%d" && del "%%d" echo %errorlevel%
Thanks to Stephan for correcting the example.
Whenever Windows command interpreter encounters ( being interpreted as begin of a command block, it parses the entire command block up to matching ) marking end of the command block and replaces all %variable% by current value of the variable.
This means in this case that before command FOR is the first time executed, everything from ( after DO up to last ) is processed already with replacing all %variable% references by current value of the appropriate variable. Then the already preprocessed block is executed one (on command IF) or more times (on command FOR).
This behavior can be seen by debugging the batch file. For debugging a batch file first #echo off must be removed or commented out with command REM or changed to #echo on. Then a command prompt window must be opened and the batch file is executed from within this command prompt window by typing its name with full path enclosed in double quotes if path or name contains a space character. The Windows command interpreter shows now all command lines and command blocks after preprocessing before executing and of course the standard messages and the error messages output by the commands or by Windows command interpreter itself in case of a syntax error in batch file.
Opening a command prompt window means running cmd.exe with option /K to Keep window open after execution of a command or a batch script. Double clicking on a batch file starts also cmd.exe for processing the batch file, but with parameter /C to Close the window automatically after batch processing terminated independent on cause - successful finished or an error occurred.
The command prompt window opened before running the batch file remains open after batch processing finished successfully or with an error except the batch file contains command EXIT without parameter /B. So experts in batch code writing test batch files always by running them from within a command prompt window instead of double clicking on them.
Delayed variable expansion is needed for variables set or modified and referenced within same command block as explained by help of command SET output on running in a command prompt window set /?.
#echo off
setlocal EnableDelayedExpansion
cd /D C:\
:a
set /P "a=Phrase that might be realted to it: "
for /r %%d in (*) do (
%SystemRoot%\System32\findstr.exe /i /m /c:"%a%" "%%d"
if "!errorlevel!" == "0" del "%%d" >nul
)
endlocal
But for checking the exit code of a previous command there is also if errorlevel syntax as explained by Microsoft in support article Testing for a Specific Error Level in Batch Files.
#echo off
setlocal EnableDelayedExpansion
cd /D C:\
:a
set /P "a=Phrase that might be realted to it: "
for /r %%d in (*) do (
%SystemRoot%\System32\findstr.exe /i /m /c:"%a%" "%%d" >nul
if not errorlevel 1 del "%%d" >nul
)
endlocal
if errorlevel X tests if exit code of previous command or application when it modifies the errorlevel variable at all is greater or equal X. By using if not errorlevel X the check is if last exit code is lower than X which is here a test if exit code is 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.
cd /?
del /?
echo /?
for /?
if /?
set /?
And see also
Microsoft's command-line reference
SS64.com - A-Z index of the Windows CMD command line
Microsoft article about Using command redirection operators
Answer on question Single line with multiple commands using Windows batch file
How to set environment variables with spaces?

Why don't some "for" commands work when the output is piped?

As an example of the problem I'm seeing, the command
for /D %%i in (*) do #if not exist m:\home\%%i echo %%i
gives me a list of directories in the current directory that don't exist in the other directory.
However, if I want to pipe the output to another command, for example:
(for /D %%i in (*) do #if not exist m:\home\%%i echo %%i) | findstr /n .
I get this error message:
echo was unexpected at this time.
Note that I can't just leave the brackets out, because that would result in the pipe operator being processed once per iteration of the loop; I need the output of the loop piped to a single instance of an application. For example, if I leave the brackets out in this example, the line number from findstr will always be shown as 1 rather than counting the number of directories.
Does anybody know how to make this work, preferably in the general case rather than just this specific example?
Windows 7 SP1 x64.
It's a problem of the parser with special IF syntax forms like:
IF exist
IF defined
IF errorlevel
IF x EQU y
But this one works without problems
IF x == y
It can be solved with defining a variable containing a single IF.
set "_IF_=IF"
( %%_IF_%% defined path echo It's defined ) | more
( %%_IF_%% errorlevel 0 echo Errorlevel is 0 or above ) | more
This works, as the %%_IF_%% will be expanded not before the child process parses the block.
As per Eryksun's comments, this is definitely a bug. It can be worked around by explicitly creating a child process, rather than letting the batch processor do it for you:
cmd /s /c "for /D %%i in (*) do #if not exist m:\home\%%i echo %%i" | findstr /n .
Another option is to manually inject the missing space, by defining %space% to be a single space and saying:
(for /D %%i in (*) do #if not exist ^%%space^%% m:\home\%%i echo %%i) | findstr /n .

CMD return specific lines from piped input

Bored in class trying to figure this out.
On windows command prompt:
ipconfig /all return all the loopback, tunnel, etc.
if I run ipconfig /all | find /n "Internal" it will return [11]Ethernet Adapter Internal. What I want to do is substring the 11 off the beginning and then pipe this to something else which will allow me to return lines 11-19 or whatever. Can you do this in a single line similar to jquery and chaining?
It is simple to parse out the 11 using a FOR /F loop. But making use of that value is difficult in a one liner from the command line.
Here is the best I could come up with for a one liner to run from the command line.
set "stop="&for /f "delims=[]" %N in ('ipconfig /all^|find /n "Internal"') do #for /f "tokens=1* delims=:" %A in ('ipconfig /all^|findstr /n "^"') do #if %A geq %N if not defined stop echo(%B&>nul 2>nul set /a 1/(%A-%N-8)||set stop=1
The shortest one liner I could think of uses a different strategy.
set n=&for /f "delims=" %A in ('ipconfig/all') do #if defined n (set/a"1/n,n-=1">nul 2>&1&&echo %A) else echo %A|find "Internal"&&set n=8
But the above solution ignores blank lines.
If you want to preserve blank lines then the following works:
set n=&for /f "tokens=1* delims=:" %A in ('ipconfig/all^|findstr/n "^"') do #if defined n (set/a"1/n,n-=1">nul 2>&1&&echo(%B) else echo %B|find "Internal"&&set n=8
EDIT
I shortened and simplified the logic of the 2nd and 3rd solutions a bit.
I'll try to explain the 2nd option:
I first explicitly undefine a counter and then use FOR to read the output of the IPCONFIG/ALL commmand. Now begins the fun part within the DO clause.
At first the counter is undefined so the ELSE clause is executed. I pipe the current line to FIND looking for "Internal". If the string is not found then nothing happens and we progress to the next line. But if it is found then the line is printed. Then the code after && is executed since the string was found. There I set the counter to 8 because we want the next 8 lines printed.
The counter is defined for the remainder of the lines, so we now switch to the first part of the IF statement. I use SET /A to do some math. First I divide 1 by the current value of the counter. IF the counter is 0 then an error is raised and the rest of the statement is ignored. If the counter is not 0 then I next decrement the counter by 1. I redirect both stdout and stderr to nul because we don't want to see any messages from the SET /A command. If the SET command was successful, then I echo the line. Since I initially set the counter to 8 when the string was found, up to 8 lines will be printed before the counter reaches 0.

Win batch: setting variable within nested loop not working

I have a long script that I have condensed to the following lines of code to illustrate the issue I am having. I have tried some suggestion by StackOverflow users to no avail, so hopefully your feedback will help me and future users. NOTE: this code works, except for setting the pdfREP nested variable.
SETLOCAL enabledelayedexpansion
set pdfREP=false
for /f "tokens=1" %%a in ('dir /o /b \\path2document\*.rp?') do (
findstr "," \\path2log\%%a > 1.log
if not errorlevel 0 (
:: do something
)
if errorlevel 0 (
findstr /B /I "p" \\path2document\%%a > 1.log
if errorlevel == 0 (
set pdfREP=true
echo RSP File: %%a >> 2.log
)
)
)
Basically the issue is that in \path2document I have multiple files, and within each I look for a comma. If no comma is found then I want to know if there is a particular letter inside the file's text. If the text is found, the I am setting a previously defined variable to TRUE, instead of FALSE. However, the "if errorlevel == 0" can be true if different syntax (%errorlevel%==0,%errorlevel% EQU 0), and it will NOT set the variable pdfREP to TRUE. If the issue is that the variable is not set until after the loop iteration, then how can I use this variable in the rest of my code? I would like to use this variable later on, so setting it is most important. Thanks for any feedback.
Windows batch has an "interesting" way of handling nested variables. This article might help.
Personally, when my batch files get this complex, I switch to a different language. My first choice is generally Python, but if you'd like to stay inside the Microsoft ecosystem, then vbscript or PowerShell would work.
You are misusing the IF command and the errorlevel value.
IF command description indicate that you may directly use in the condition the ERRORLEVEL word followed by a number indicating a given errorlevel. This way, the following two IF commands are right:
if not errorlevel 0 (
:: do something
)
if errorlevel 0 (
However, the following command is bad written:
if errorlevel == 0 (
In this case, you must use !errorlevel! to indicate to take the current errorlevel value after executing the last line:
if !errorlevel! == 0 (
Independently of the above said, this is the way that I would do that:
if not errorlevel 0 (
echo The errorlevel is less than zero
) else if errorlevel 0 (
echo The errorlevel is greater than zero
) else (
echo The errorlevel is zero
)

Resources