My network changes rather dynamically and unfortunately I am forced to run Windows.
This script works because I have installed GNU tools for Windows and can use grep.
I would like to be able to run this script on any windows machine without having to install anything (grep etc). I used findstr in this at first but could not get it to show only what matches the regex string.
#echo off
set %IPLIST% = nul
Echo.
Echo "Pinging all local Gateways"
ipconfig | findstr /i "Gateway" | grep -o "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" > %IPLIST%
For /F "Usebackq Delims=" %%# in ("%IPLIST%")
do (
Echo+
Echo [+] Pinging: %%#
Ping -n 1 "%%#" 1>nul && (
Echo [OK]) || (
Echo [FAILED])
)
Echo.
Echo.
Echo "now testing your internet connection"
Echo .
Echo ...
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if %errorlevel% == 1 (
echo ....all is lost
)
)
Echo.
You have a number of problems with the script.
set %IPLIST% = nul
This would yield a syntax error because iplist is likely undefined, and you are attempting to set the variable contents of iplist to "nul"
The resolution of this would be
set = nul
Further, spaces on either side of the = are included in the variable/value set, so removing the %s would set the value of iplistSpace to Spacenul
Had iplist indeed been set up to nul then your ipconfig command would have simply dumped its eventual output into the bit-bucket as it would have been sent to nul.
For /F "Usebackq Delims=" %%# in ("%IPLIST%")
The do ( must be on the same physical line as the "for"
<opinion>Using non-alphas as metavariables is not a good idea as it is not officially supported <\opinion>
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if %errorlevel% == 1 (
echo ....all is lost
)
)
Because of the delayed expansion trap (all %var% in a block (parenthesised sequence of statements) are replaced by their value at parse-time) the innermost %errorlevel% here would be replaced by whatever errorlevel was set to when the outermost if was encountered. To interpret the ping output, you'd need to either invoke delayedexpansion (many, many SO items on this subject) or use the old original if errorlevel n... construct, where the if condition is true if the current errorlevel is n or greater than n.
So - reconstructing using batch features,
#ECHO OFF
SETLOCAL
Echo.
Echo "Pinging all local Gateways"
For /F "tokens=2 Delims=:" %%a in ('ipconfig ^| findstr /i "Gateway"') DO IF "%%a" neq " " (
Echo+
Echo [+] Pinging: %%a
Ping -n 1 %%a 1>nul && (
Echo [OK]) || (
Echo [FAILED])
)
Echo.
Echo.
Echo "now testing your internet connection"
Echo .
Echo ...
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
echo ....all is lost
)
)
Echo.
GOTO :EOF
The 'for /ftokenises the output of the command in single-quotes using:as a delimiter and picking the second token to apply to%%a`.
The | needs to be escaped by a caret to tell cmd that it is part of the command to be executed, not part of the for.
The for processes the output of ipconfig... so %%a has the form Spacexxx.xxx.xxx.xxx
On my machine, xxx... was missing on one line, so I filtered out the single-space response.
Pinging %%a without the quotes adds an extra space into the ping line, which is harmless. With the quotes, it didn't like it.
Then the appendix...
I'm not sure what you're really attempting here. Perhaps it was a frustrated debug attempt.
errorlevel will be set to whatever the last ping result was. This is logically unpredictable.
I've shown a correct method of interpreting the findstr errorlevel result. I'm not sure that your regex is correct here...but the all is lost message would only be shown if findstr sets errorlevel to 1.
Related
I have made a Windows batch file based on some examples I have found elsewhere.
What it does is it parses a folder for a specific file type (.mkv) and then runs mkvmerge.exe from the MKVToolNix folder.
The command produces an output, listing the different tracks in the container.
The core of the file is
set rootfolder="Z:\Movies"
for /r %rootfolder% %%a in (*.mkv) do (
for /f %%b in ('mkvmerge -i "%%a" ^| find /c /i "chapters"') do (
if [%%b]==[0] (
echo "%%a" has no chapters
) else (
echo Doing some interesting stuff!
)
)
)
The above example is just part of the file, rootfolder is set to the folder I want parsed, of course, and upon finding a file with chapters in it, it will run additional commands.
It all works beautifully but I also want to check for subtitles at the same time. The find command doesn't take regular expressions or I could just have added "chapters subtitles". My efforts using other commands, like findstr, haven't really worked.
How do I go about using RegEx here?
This is an example output, running mkvmerge.exe on an .mkv file
mkvmerge.exe -i "Snow White and the Seven Dwarfs (1937) [tt0029583].mkv"
File 'Snow White and the Seven Dwarfs (1937) [tt0029583].mkv': container: Matroska
Track ID 0: video (MPEG-4p10/AVC/h.264)
Track ID 1: audio (DTS)
Track ID 2: audio (AC-3)
Track ID 3: subtitles (HDMV PGS)
Track ID 4: subtitles (HDMV PGS)
Chapters: 26 entries
This example has both subtitle and chapter tracks and the batch file will find the keyword "chapters" (it's set to ignore case). I also want to catch the files that contain the keyword "subtitles" even when there are no chapters.
To clarify my intent here, I want the code to:
Parse through the given folder
For all .mkv files, do mkvmerge /i which will output (as text) the streams in that file
Look at that output and if it contains the word(s) "chapters" and/or "subtitles" trigger some action.
Since you appear to make no distinction between whether one string or the other (or both) is detected, then
#Echo off
set rootfolder="Z:\Movies"
for /r %rootfolder% %%a in (*.mkv) do (
mkvmerge -i "%%a" | findstr /i "^Chapters subtitles" >nul
if errorlevel 1 (
echo Neither Chapters nor subs found in "%%a"
) else (
echo Chapters or subs found in "%%a"
)
)
would likely be easier.
Thanks LotPings for your effort. I learned something about tokens that will be very useful. Your script also got me on the right track (learning a few more commands on the way.
Your script ended up looking like this:
:: Q:\Test\2018\05\27\SO_50555308.cmd
#Echo off
set rootfolder="Z:\Movies"
for /r %rootfolder% %%a in (*.mkv) do (
set "found="
for /f "tokens=1-4* delims=: " %%b in (
'mkvmerge -i "%%a" ^| findstr /i "^Chapters subtitles"'
) do (
if /i "%%b"=="Chapters" set found=1
if /i "%%e"=="subtitles" set found=1
)
if defined found (
echo Chapters or subs found in "%%a"
) else (
echo.
)
)
All I needed was to check whether one of my keywords were present in any of the tokens and then set a flag accordingly and after the loop do the appropriate action, resetting the flag for the next file.
Still unclear how a line with Subtitles would look like.
Presuming the values Chapters and Subtitles appear in 1st column
The for /f splits the lines at colon and space (adjacent delims count as one) into tokens 1=%%b and 2=%%c the possible unsplitted rest in token 3=%%d
The space separated (ORed) RegEx search words anchored ^ at line begin will only match chapters/subtitles.
:: Q:\Test\2018\05\27\SO_50555308.cmd
#Echo off
set rootfolder="Z:\Movies"
for /r %rootfolder% %%a in (*.mkv) do (
for /f "tokens=1-4* delims=: " %%b in (
'mkvmerge -i "%%a" ^| findstr /i "^Chapters subtitles"'
) do (
if /i "%%b"=="Chapters" if "%%c"=="0" (
echo "%%a" has no chapters
) else (
echo "%%a" has %%c chapters
echo Doing some interesting stuff!
)
if /i "%%e"=="subtitles" echo "%%a" %%b %%b %%d: %%e %%f
)
)
I have a script that extracts lines such as :
THIS_IS_A_LINE:=
THIS_IS_A_LINE2:=
and outputs all of the same kind into another .txt file as:
THIS_IS_A_LINE
THIS_IS_A_LINE2
The script is the following:
set "file=%cd%/Config.mak"
set /a i=0
set "regexp=.*:=$"
setlocal enableDelayedExpansion
IF EXIST Source_List.txt del /F Source_List.txt
for /f "usebackq delims=" %%a in ("%file%") do (
set /a i+=1
call set Feature[!i!]=%%a
)
cd .. && cd ..
rem call echo.!Feature[%i%]!
for /L %%N in (1,1,%i%) do (
echo(!Feature[%%N]!|findstr /R /C:"%regexp%" >nul && (
call echo FOUND
call set /a j+=1
call set Feature_Disabled[%j%]=!Feature[%%N]:~0,-2!
call echo.!Feature_Disabled[%j%]!>>Source_List.txt
) || (
call echo NOT FOUND
)
)
endlocal
I also have another script that extracts lines such as:
THIS_IS_ANOTHER_LINE:=true
THIS_IS_ANOTHER_LINE2:=true
...
and outputs all of the same kind into another .txt file as:
THIS_IS_ANOTHER_LINE
THIS_IS_ANOTHER_LINE2
...
The script is the following:
set "file=%cd%/Config.mak"
set /a i=0
set "regexp=.*:=true$"
setlocal enableDelayedExpansion
IF EXIST Source_List2.txt del /F Source_List2.txt
for /f "usebackq delims=" %%a in ("%file%") do (
set /a i+=1
call set Feature[!i!]=%%a
)
cd .. && cd ..
rem call echo.!Feature[%i%]!
for /L %%N in (1,1,%i%) do (
echo(!Feature[%%N]!|findstr /R /C:"%regexp%" >nul && (
call echo FOUND
call set /a j+=1
call set Feature_Disabled[%j%]=!Feature[%%N]:~0,-6!
call echo.!Feature_Disabled[%j%]!>>Source_List2.txt
) || (
call echo NOT FOUND
)
)
endlocal
Nevertheless, there is a third kind of lines which contain numerical numbers (also some hexadecimal values), such as:
THIS_IS_AN_UNPROCESSED_LINE:=0xA303
THIS_IS_AN_UNPROCESSED_LINE2:=1943
THIS_IS_AN_UNPROCESSED_LINE3:=HELLO_DOOD_CAN_YOU_PARSE_ME?
So I need the way to extract as well those kind of lines into another .txt file such as:
THIS_IS_AN_UNPROCESSED_LINE:=0xA303
THIS_IS_AN_UNPROCESSED_LINE2:=1943
THIS_IS_AN_UNPROCESSED_LINE3:=HELLO_DOOD_CAN_YOU_PARSE_ME?
So basically extract lines which are not of the kind:
THIS_IS_AN_UNPROCESSED_LINE:=
or
THIS_IS_AN_UNPROCESSED_LINE:=true
but keeping both the sides of the line entry.
I know there must be some trick with the regular expression but I just can't find it out.
You have made your code much more complicated than it needs to be. There is no need to create an array of every line in the file.
If there are no other : or = before the first :=, then you can use FINDSTR to print out all lines that contain a string, followed by :=. FOR /F can capture and parse each matching line into the parts before and after :=, and then IF statements can classify the three different types of lines.
I use n> to open all three output files outside the main code block for improved performance, and then I use the &n> syntax to direct each output to the appropriate, already opened file. I use high numbered file handles to avoid problems described at Why doesn't my stderr redirection end after command finishes? And how do I fix it?.
#echo off
setlocal
set "file=Config.mak"
set /a "empty=7, true=8, unprocessed=9"
%empty%>empty.txt %true%>true.txt %unprocessed%>unprocessed.txt (
for /f "delims=:= tokens=1*" %%A in ('findstr /r "^[^:=][^:=]*:=" "%file%"') do (
if "%%B" equ "" (
>&%empty% (echo %%A)
) else if "%%B" equ "true" (
>&%true% (echo %%A)
) else (
>&%unprocessed% (echo %%A:=%%B)
)
)
)
The above will ignore lines that contain : or = before :=, and it will not work properly if the first character after := is : or =. I'm assuming that should not be a problem.
It should be relatively easy to write a very efficient solution using PowerShell, VBScript, or JScript that eliminates the limitations.
You could also use JREPL.BAT - a powerful and efficient regular expression text processing command line utility. JREPL.BAT is pure script (hybrid batch/JScrpt) that runs natively on any Windows machine from XP onward, no 3rd party exe required. And JREPL is much faster than any pure batch solution, especially if the files are large.
Here is one JREPL solution
#echo off
setlocal
set repl=^
$txt=false;^
if ($2=='') stdout.WriteLine($1);^
else if ($2=='true') stderr.WriteLine($1);^
else $txt=$0;
call jrepl "^(.+):=(.*)$" "%repl%" /jmatchq^
/f Config.mak /o unprocessed.txt >empty.txt 2>true.txt
If all you have to do is classify the lines into three different files, without worrying about stripping off the :=true and := parts for the empty and true lines, then there is a very simple pure batch solution using nothing but FINDSTR.
#echo off
set "file=Config.mak"
findstr /r ".:=$" "%file%" >empty.txt
findstr /r ".:=true$" "%file%" >true.txt
findstr /r ".:=" "%file%" | findstr /r /v ":=$ :=true$" >unprocessed.txt
I have a batch file that first checks an outside file to see the source branch for the build then runs an if else if statement that runs regex to match the source branch which then determines where the build will deploy:
#echo off
setlocal enabledelayedexpansion
set SEPARATOR=/
set filecontent=
for /f "usebackqdelims=" %%a in ("BuildBranch.txt") do (
set currentline=%%a
set filecontent=!filecontent!%SEPARATOR%!currentline!
)
echo %filecontent%
If NOT "%filecontent%"=="develop(.*)" (
echo Deploying to dev DEVELOP
) else If NOT "%filecontent%"=="^.feature(.*)" (
echo Deploying to dev FEATURE
) else If NOT "%filecontent%"=="master(.*)" (
echo Deploying to integration MASTER
) else If NOT "%filecontent%"=="^.hotfix(.*)" (
echo Deploying to integration HOTFIX
)
pause
I have run each of the regex's through the regex101 site but there may still be issues with them. My main issue is that ever time I run my batch file it only runs the first of the If statements. The variable %filecontent% is feature/MyNewFeature so it should see that it doesn't match the first if statement and go on to the second statement. I don't know if this is an issue with my regex or my if statements.
The IF does not support regex matching. But you could try some workaround like the following:
echo %filecontent% | >nul findstr /i /r /c:"develop.*" || ( echo Deploying to dev DEVELOP )
echo %filecontent% | >nul findstr /i /r /c:"^.feature.*" || ( echo Deploying to dev FEATURE )
echo %filecontent% | >nul findstr /i /r /c:"master.*" || ( echo Deploying to dev MASTER )
echo %filecontent% | >nul findstr /i /r /c:"^.hotfix.*" || ( echo Deploying to dev HOTFIX )
From there you could build around the findstr command, since it can match some regex (not advanced ones thou), in conjunction with the || operator, for cases of if NOT, or the && operator, for cases of if.
Hope it helps.
I'm trying to write a script that lists every file name in a specified folder, and notifies the user if that folder is empty. So far I've got:
for /r "O:\Mail\5-Friday" %%d in (*.pdf) do (
dir /a /b "%%~fd" 2>nul | findstr "^" >nul && echo %%~nd || echo Empty: Friday
)
but I've no idea where to put the if, else operators.
And is there a way to specify a folder based on user input without rewriting every function for each folder? So instead of:
if /i {%ANS%}=={thursday} (goto :thursday)
if /i {%ANS%}=={friday} (goto :friday)
:thursday
<do stuff>
:friday
<do the same stuff as thursday, but a different directory>
etc, I could write one function with variables in place of paths, assign the directory to a variable, and easily add/remove folders in the code as necessary?
To address the first part of your question, "where to put the if, else operators"... The notation of
command | findstr >nul && echo success || echo fail
... is shorthand for
command | findstr >nul
if ERRORLEVEL 1 (
echo fail
) else (
echo success
)
The magic that happens is in the conditional execution operators, the && and ||. If findstr exits with status zero, then a match was found. Therefore, execute the stuff after &&. Otherwise, status is non-zero, no match was found, so execute the stuff after ||. See how that works?
For the second part, here's a typical way to prompt the user to provide entry based on a finite number of choices.
#echo off
setlocal
:begin
set /p "day=What day? "
for %%I in (monday tuesday wednesday thursday friday) do (
if /i "%day%" equ "%%I" goto %%I
)
goto begin
:monday
call :getdirs "O:\Mail\1-Monday"
goto :EOF
:tuesday
call :getdirs "O:\Mail\2-Tuesday"
goto :EOF
:wednesday
call :getdirs "O:\Mail\3-Wednesday"
goto :EOF
:thursday
call :getdirs "O:\Mail\4-Thursday"
goto :EOF
:friday
call :getdirs "O:\Mail\5-Friday"
goto :EOF
:getdirs <path>
setlocal enabledelayedexpansion
for /f "delims=" %%I in ('dir /b /s /ad "%~1"') do (
dir /b "%%I" 2>NUL | findstr "^" >NUL || echo %%I has no files
)
goto :EOF
Or, even hacksier, I'll do something you probably weren't expecting was possible. I'll have the script open a folder selection dialog to allow the user to select the directory to scan. It's a batch / JScript hybrid script.
If you wish, you can set the root of the folder browser to a ShellSpecialConstants folder by changing the last argument in the next-to-the-last line. Using a value of 0x11 makes the root your system's drives. No value or a value of 0x00 makes the root "Desktop". Or leave the script as-is to set the root as "O:\Mail".
#if (#a==#b) #end /*
:: fchooser2.bat
:: batch portion
#echo off
setlocal
set initialDir="O:\Mail"
for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0" "%initialDir%"') do (
call :getdirs "%%I"
)
exit /b
:getdirs <path>
setlocal enabledelayedexpansion
for /f "delims=" %%I in ('dir /b /s /ad "%~1"') do (
dir /b "%%I" 2>NUL | findstr "^" >NUL || (
rem This is where you put code to handle empty directories.
echo %%I has no files
)
)
goto :EOF
:: JScript portion */
var shl = new ActiveXObject("Shell.Application");
var hint = 'Double-click a folder to expand, and\nchoose a folder to scan for empty directories';
var folder = shl.BrowseForFolder(0, hint, 0, WSH.Arguments(0));
WSH.Echo(folder ? folder.self.path : '');
Edit Since apparently BrowseForFolder accepts an absolute directory, there's really no benefit to using PowerShell / C#. The hybrid batch / PowerShell / C# script shall henceforth be retired to the revision history.
This is fun!
i want to use my %variable% to manage the conditional clauses in a IF.. THEN.. ELSE in a batch file.
Something like the following:
set variable=%%homedrive%% EQU C:
if %variable% (
echo test ok
) else (
echo test fail
)
if i write on a cmd console:
set test=1 equ 1
if %test% echo OK
it works!
i'll use it in a for /f cicle:
this is my pseudo codethis is my pseudo code to correct
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
[..]
) > "%temp%\CSG_fs.tmp"
[..]
for /f "usebackq tokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set cond=!cond:~1!
set parm=%%b& set parm=!parm:~0,-1!
echo - cicle: "!cond!" --^> "!parm!"
call if !cond! call:CSG_sub_fs !parm!
echo - done
)
goto:eof
:CSG_sub_fs
[..]
goto:eof
--edit--
how can i use the variable !cond! to decide if execute the call to CSG_sub_fs?
call if !cond! call:CSG_sub_fs !parm!
does not work because it returns: "Can not find the batch label specified - IF"
and if i use
if !cond! call:CSG_sub_fs !parm!
it will say: "call:CSG_sub_fs not expected"
Well - there doesn't seem to be a question, so it's not that easy to answer.
You have a problem with
echo "^%COMPUTERNAME^% EQU [x];[some parameters1]"
because ^ does not escape % - % escapes % - use %%COMPUTERNAME%%...
(you should have been able to check this just by TYPEing "%temp%\CSG_fs.tmp"
Next problem is that
for /f "tokens=1-2* delims=; usebackq" %%a in (%temp%\CSG_fs.tmp) do (
may process the file %temp%\CSG_fs.tmp provided %temp%\CSG_fs.tmp contains no spaces, semicolons or commas. If it contains any of these deafult separators, or certain other characters with a special meaning, then you must enclose the filename in double-quotes "%temp%\CSG_fs.tmp"and use the usebackq option.
You've attempted to use usebackq but DELIMS must be the LAST option if it is used. Your code would set ";","","u","s","e","b","a","c","k" and "q" as delimiters.
Beyond that, perhaps if you explain what you intend to achieve, we'd be able to devise the appropriate code.
Try this:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CLS
REM I'm setting these variables for testing.
REM That isn't ususally a good idea but the SETLOCAL
REM will ensure they are restored on exit
SET computername=[x]
SET logonserver=[z]
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
) > "%temp%\CSG_fs.tmp"
for /f "usebackqtokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set "cond=IF !cond:~1! CALL :csg_sub_fs "
set parm=%%b& set parm=!parm:~0,-1!
CALL :varcmd "!cond!" "!parm!"
)
GOTO :eof
:varcmd
%~1 %~2
GOTO :eof
:csg_sub_fs
ECHO parameters supplied to csg_sub_fs were: %*
GOTO :eof
I've forced the variablenames to match the conditions you've used in order to trigger the subroutine calls. Change as you need to prove your concept.
And dont worry about imperfect English. I'm sure I wouldn't do as well in your language!