{"id":702,"date":"2016-02-21T22:01:27","date_gmt":"2016-02-21T22:01:27","guid":{"rendered":"http:\/\/blog.paranoidprofessor.com\/?p=702"},"modified":"2016-07-06T14:02:21","modified_gmt":"2016-07-06T14:02:21","slug":"command-line-fun-windows-flow-control","status":"publish","type":"post","link":"https:\/\/blog.paranoidprofessor.com\/index.php\/2016\/02\/21\/command-line-fun-windows-flow-control\/","title":{"rendered":"command line fun &#8211; windows flow control"},"content":{"rendered":"<p>Windows batch files are not nearly as rich as some languages (perl or python) and certainly not as rich as the shell scripting.<\/p>\n<p>Not all of the familiar control structures exist but it is possible to create some as necessary and there are definitely enough to do write some batch files.<\/p>\n<h2>if \/ then \/ else<\/h2>\n<p>The most basic element that most developers use in their batch files is the if\/then statement. \u00a0With this, you can compare strings or numbers and execute blocks of code or goto a different part of the script.<\/p>\n<p>Just like C, the syntax of the if then actually drops the entire &#8220;then&#8221; from the statement.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\nset a=4\r\n\r\nif %a% equ 4 (\r\necho a=4\r\n)<\/code><\/pre>\n<\/div>\n<p>As the name implies, it is also possible to have an else statement added to our if clause.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\nset \/a a=4\r\n\r\nif %a% equ 4 (\r\necho a=4\r\n) else (\r\necho a is not equal 4\r\n)<\/code><\/pre>\n<\/div>\n<p>It should be obvious that left and right parenthesis are used to create the block of code to be executed. \u00a0The only thing not obvious about this statement is that the actual\u00a0structure of the statement must be exactly as seen above.<\/p>\n<blockquote>\n<h3>&#8220;) else (&#8220;<\/h3>\n<\/blockquote>\n<p>The batch interpreter is very limited and does not allow you to add more white space, in the form of new lines, around the else statement. \u00a0This may be frustrating for someone who likes to format their code in a very specific manner but once you are aware of this short coming it is easy to work around.<\/p>\n<p>There are six\u00a0comparison verbs that can be used in the if\/then\/else tests.<\/p>\n<table>\n<tbody>\n<tr>\n<td>EQU<\/td>\n<td>equal<\/td>\n<\/tr>\n<tr>\n<td>NEQ<\/td>\n<td>not equal<\/td>\n<\/tr>\n<tr>\n<td>LSS<\/td>\n<td>less than<\/td>\n<\/tr>\n<tr>\n<td>LEQ<\/td>\n<td>less than or equal<\/td>\n<\/tr>\n<tr>\n<td>GTR<\/td>\n<td>greater than<\/td>\n<\/tr>\n<tr>\n<td>GEQ<\/td>\n<td>greater than or equal<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2><\/h2>\n<h2>small gotchas<\/h2>\n<p>Not every script necessarily does math, the numbers may not be important at all for what you do. \u00a0If you do not indicate that you are doing numeric calculations, then the batch interpreter thinks that you are doing string addition not numeric calculations.<\/p>\n<div class=\"sbody-code\">\n<pre><code>set a=4\r\nset a=%a%+1\r\necho a=%a%\r\n&gt; a=4+1<\/code><\/pre>\n<\/div>\n<p>However, if you plan on doing math, you have to make sure that you add the &#8220;\/a&#8221; to the set command.<\/p>\n<div class=\"sbody-code\">\n<pre><code>set a=4\r\nset \/a a=%a%+1\r\necho a=%a%\r\n&gt; a=5<\/code><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>other verbs<\/h2>\n<p>The batch interpreter, just like the bash shell, has some additional support for checking that files do or do not exist.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\nIF EXIST \"temp.txt\" (\r\n    ECHO found\r\n) ELSE (\r\n    ECHO not found\r\n)<\/code><\/pre>\n<\/div>\n<p>To negate the test, simply add the key word NOT in front of exist.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\ncd \/d c:\\temp\r\nif <strong>NOT<\/strong> exist \"%1\" echo file %1 exists<\/code><\/pre>\n<\/div>\n<h2><\/h2>\n<h2>for loop &#8211; processing files<\/h2>\n<p>There are a number of different types of actions that are supported with the for loop. \u00a0The for loop doesn&#8217;t seem quite as flexible as the for loop in Linux but powerful enough to gather up a list of all files in a directory to be processed.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\nSET count=1\r\nFOR \/f %%G IN ('dir \/b *.png') DO (call :forloopfunct\"%%G\")\r\necho here\r\nGOTO :eof\r\n\r\n:forloopfunct\r\necho %count%:%1\r\nset \/a count+=1\r\nGOTO :eof\r\n\r\necho i am now here<\/code><\/pre>\n<\/div>\n<p>This example will loop through all files in the current directory that have the extension of png. \u00a0The syntax for windows batch files is somewhat different than in Linux. \u00a0For loops in windows batch files do not have a block of commands associated with the for loop itself. \u00a0If you want to execute a number of commands as part of the for loop, you need to have a similar construct, where the block of commands are put into a function that is called.<\/p>\n<p>This script is a complete script despite what looks to be missing labels. It appears that the eof label in the subroutine is essentially a return statement. \u00a0The same is true earlier in the script, the first &#8220;goto :eof&#8221; appears to also be a return statement. \u00a0The final echo statement in the script is never executed.<\/p>\n<p>There are a number of qualifiers that you can use in a for loop.<\/p>\n<table class=\"w3-table-all\">\n<tbody>\n<tr>\n<th>qualifier<\/th>\n<th>Description<\/th>\n<\/tr>\n<tr>\n<td>\/F<\/td>\n<td>List of all files in current directory.<\/td>\n<\/tr>\n<tr>\n<td>\/R<\/td>\n<td>Recursive search through all sub-directories<\/td>\n<\/tr>\n<tr>\n<td>\/D<\/td>\n<td>List of directories<\/td>\n<\/tr>\n<tr>\n<td>\/L<\/td>\n<td>For loop over a range of numbers<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2><\/h2>\n<h2>for loop &#8211;\u00a0over a range of numbers<\/h2>\n<p>It is possible to do a more standard for loop, from a starting number stepping up to a final value.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\n FOR \/L %%i IN (0 2 100) DO (\r\n echo %%i\r\n echo hiya\r\n )<\/code><\/pre>\n<\/div>\n<p>This small example starts at zero and counts up by two until equal one hundred.<\/p>\n<p>The syntax is slightly different than the other for loops described. \u00a0It is also possible to call a subroutine for each element but in this type of a loop it is possible to have a block of commands to be executed with iteration.<\/p>\n<p>&nbsp;<\/p>\n<h2>pseudo case statement<\/h2>\n<p>There is no switch statement in windows, but it is possible to create one using a goto statement and clever use of labels to create a switch statement.<\/p>\n<div class=\"sbody-code\">\n<pre><code>@echo off\r\nSET I=1\r\n\r\nGOTO LABEL_%I%\r\n:LABEL_0\r\nECHO i equals 0\r\nGOTO END_SWITCH\r\n\r\n:LABEL_1\r\nECHO i equals 1\r\nGOTO END_CASE\r\n:END_CASE\r\necho program finished<\/code><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>functions<\/h2>\n<p>The best way to keep your code clean and easy to understand is to modularize it into functions.\u00a0 Windows also supports this by allowing you to create subroutines.<\/p>\n<p>It seems to be an odd to me, but Microsoft implemented this much like basic from years ago.\u00a0 To call a subroutine you have to actually say &#8220;call&#8221; and the name of the subroutine.<\/p>\n<pre><code>@ECHO OFF\r\n\r\n:: script global variables\r\nSET day=23 \r\nSET month=11\r\nSET year=2015\r\n\r\n::main\r\ncall displaydate %day% %month% %year%\r\ngoto :eoj\r\n\r\n:displaydate\r\necho %year%%month%%day%\r\ngoto :eof\r\n<\/code><\/pre>\n<p>&nbsp;<\/p>\n<h2>Other tricks<\/h2>\n<p>It is possible to run the normal dos commands and have the output assigned to a variable. Simply surround the command with percentage symbols and treat it like a variable and the output from the command will be expanded and assigned like a variable.<\/p>\n<pre><code>@echo off\r\nset currentdirectory=%cd%\r\necho the current directory is %currentdirectory%\r\n<\/code><\/pre>\n<p>It is possible to save the current working directory in the manner described above.\u00a0 This allows the script to change directories and easily find its way back to where it started.\u00a0 However, there is an even nicer way to do that particular trick.<\/p>\n<p>Microsoft has two commands that will save the current working directory while changing to a new directory.\u00a0 This is implemented as a LIFO stack, so it is possible to always return to the last directory that you were in.<\/p>\n<pre><code>@echo off\r\necho starting script\r\n\r\necho amount of space used in temp directory\r\npushd c:\\temp\r\ndu -h .\r\n\r\necho \" \"\r\necho list of users who had logged into this machine\r\npushd c:\\users\r\necho now i am in %cd%\r\ndir \/b \/q *.\r\n\r\necho \" \"\r\necho information about disk in general\r\nif exist \"c:\\program files\\windows media player\" (\r\necho found it\r\ndir \"c:\\program files\\windows media player\\wmplayer.exe\"\r\n) else (\r\necho cannot find windows media player\r\n)\r\n\r\n:: pull directories off stack\r\npopd\r\necho now i am in %cd%\r\npopd\r\necho now i am in %cd%\r\n<\/code><\/pre>\n<p>It is possible enhance your windows machine by downloading or writing comand line utilities. \u00a0One that might be interesting is the windows du, similar to the unix du but runs on windows.<\/p>\n<p>windows utility du<br \/>\n<a href=\"https:\/\/technet.microsoft.com\/en-us\/sysinternals\/du.aspx\" target=\"_blank\">https:\/\/technet.microsoft.com\/en-us\/sysinternals\/du.aspx<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Windows batch files are not nearly as rich as some languages (perl or python) and certainly not as rich as the shell scripting. Not all of the familiar control structures exist but it is possible to create some as necessary &hellip; <a href=\"https:\/\/blog.paranoidprofessor.com\/index.php\/2016\/02\/21\/command-line-fun-windows-flow-control\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2,20],"tags":[18,39],"_links":{"self":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/702"}],"collection":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/comments?post=702"}],"version-history":[{"count":14,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/702\/revisions"}],"predecessor-version":[{"id":749,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/702\/revisions\/749"}],"wp:attachment":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/media?parent=702"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/categories?post=702"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/tags?post=702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}