{"id":6138,"date":"2018-04-11T20:40:43","date_gmt":"2018-04-11T20:40:43","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=6138"},"modified":"2018-04-11T20:40:43","modified_gmt":"2018-04-11T20:40:43","slug":"shell-scripting-linux","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/shell-scripting-linux\/","title":{"rendered":"Shell scripting (Linux)"},"content":{"rendered":"<p><strong>The shell script file<\/strong><\/p>\n<p>By default we name a script file with the .sh extension and the first line is usually (although not strictly required) to be one of the following<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n#!\/bin\/sh\r\n\r\nOR\r\n\r\n#!\/bin\/bash\r\n<\/pre>\n<p>The use of <em>sh<\/em> tells Linux we want to run the script with the default shell script . Note that this might be dash, bash, bourne or any other shell available, hence when using <em>sh<\/em> the developer of the script needs to be aware that they cannot expect bash (for example) capabilities to exist and therefore if bash specific code exists within the script the <em>#!\/bin\/bash<\/em> line should be used.<\/p>\n<p><em>Note: #! is known as the sha-bang<\/em><\/p>\n<p><strong>What shell am I running?<\/strong><\/p>\n<p>You can use <em>$SHELL<\/em> in your scripts or from the command line, for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\necho $SHELL\r\n<\/pre>\n<p><strong>Making the script executable<\/strong><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nchmod 777 myscript.sh\r\n<\/pre>\n<p><strong>Comments<\/strong><\/p>\n<p>Comments are denoted by #. Anything after the # until a new line, will be seen as a comment, i.e.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\necho &quot;Some text&quot; # write to stdout &quot;Some text&quot;\r\n<\/pre>\n<p><strong>Variables<\/strong><\/p>\n<p>We can create variables, which are case-sensitive, like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nVARIABLE1=&quot;Hello&quot;\r\nvariable2=&quot;World&quot;\r\n\r\necho $VARIABLE1 $variable2\r\n<\/pre>\n<p><em>Note: You should not have spaces between the = operator or the command may not found. So for example this will fail VARIABLE1 = &#8220;Hello&#8221;<\/em><\/p>\n<p>Whilst we can use variables that are not strings, underneath they&#8217;re stored as strings and only converted to numerical values when used with numerical functions etc.<\/p>\n<p>So for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\ni=0\r\n$i=$i+1\r\n<\/pre>\n<p>will fail with <em>0=0+1: command not found<\/em>. To increment a variable (for example) we need to use the following syntax<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nlet &quot;i=i+1&quot;\r\n#OR\r\ni=$((i+1))\r\n<\/pre>\n<p>we can also use postfix operators, i.e. ++ or += such as <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nlet &quot;i++&quot;\r\n#OR\r\n((i++))\r\n#OR\r\nlet &quot;i+=1&quot;\r\n#OR\r\n((i+=1))\r\n<\/pre>\n<p>We can also create arrays using the following syntax<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\na=(&quot;a&quot; &quot;b&quot; &quot;c&quot;)\r\n<\/pre>\n<p>and an example of indexing into this array is as follows<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\necho &quot;Array element at index 1 is ${array&#x5B;1]}&quot;\r\n# outputs Array element at index 1 is b\r\n<\/pre>\n<p>We can also remove or <em>unset<\/em> a variables like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nunset i\r\n<\/pre>\n<p><strong>Logic operations<\/strong><\/p>\n<p>IF, THEN, ELSE, ELIF&#8230;<\/p>\n<p>As our scripts become more capable\/complex it&#8217;s likely we&#8217;ll want to use some logic and branching code, i.e. IF, THEN, ELSE, ELIF code. Let&#8217;s look at an example of IF, THEN syntax<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nif &#x5B; $i = 6 ] \r\nthen \r\n   echo &quot;i is correctly set to 6&quot; \r\nfi\r\n<\/pre>\n<p><em>Note: after the space after the [ and before ] without this the script will error with command not found.<\/em><\/p>\n<p>The [ ] syntax is the way you&#8217;ll often see this type of operation, from my understanding this is actual an alternate syntax to <em>test i=6<\/em>, so for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\ntest i=6; echo &quot;i is correctly set to 6&quot;\r\n<\/pre>\n<p><em>Note: the example above shows the test on a single line, in this case the ; is used to denote the end of the line.<\/em><\/p>\n<p>We can use = or <em>-eq<\/em> along with less than, greater than etc. however these standard operators are to be set to use a string comparisons, i.e. we do not use <, instead we use <em>-lt<\/em> for non-strings, like wise = will do a string comparisons whereas <em>-eq<\/em> will handle numerical comparisons. <\/p>\n<p>We can also use ELSE for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nif &#x5B; ! -d &quot;BAK&quot; ]\r\nthen\r\n   echo &quot;BAK does not exist&quot;\r\nelse   \r\n   echo &quot;BAK exists&quot;\r\nfi\r\n<\/pre>\n<p>and finally ELIF<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nif &#x5B; -d &quot;BAK&quot; ]\r\nthen\r\n   echo &quot;BAK exists&quot;\r\nelif &#x5B; -d &quot;BACK&quot; ]\r\n   echo &quot;BACK exists&quot;\r\nfi\r\n<\/pre>\n<p>Checkout <a href=\"https:\/\/ryanstutorials.net\/bash-scripting-tutorial\/bash-if-statements.php\" rel=\"noopener\" target=\"_blank\">If Statements!<\/a> which has a list of the operators in more depth.<\/p>\n<p><strong>[[ ]] vs [ ]<\/strong><\/p>\n<p>The [ ] is actually just an alias for <em>test<\/em> as mentioned above. BASH and some other shells also support [[ ]] syntax which is more powerful. <a href=\"http:\/\/mywiki.wooledge.org\/BashFAQ\/031\" rel=\"noopener\" target=\"_blank\">See What is the difference between test, [ and [[ ?<\/a> for more information.<\/p>\n<p><strong>Case (switch)<\/strong><\/p>\n<p>Extending the IF, THEN, ELSE, ELIF we also have a switch style comparison capability, for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\ncase $response in\r\n   y|Y) echo &quot;Executing script&quot; ;;\r\n   *) exit ;;\r\nesac\r\n<\/pre>\n<p>The syntax for <em>y|Y)<\/em> is pattern matching and ) terminates the pattern. This is followed by one or more statements to be executed followed by the <em>;;<\/em> terminator. The <em>*)<\/em> means match against anything else (or default condition). We then terminate the case block with <em>esac<\/em>. So in this example we&#8217;ll output &#8220;Executing script&#8221; if the <em>response<\/em> variable is either <em>y<\/em> or <em>Y<\/em>.<\/p>\n<p><strong>Loops<\/strong><\/p>\n<p>We can run commands in loops such as <em>for<\/em>, <em>while<\/em> and <em>until<\/em>.<\/p>\n<p>While and Until are very similar except that while keeps looping whilst a condition is true whereas until loops, until a condition is true. Here&#8217;s a couple of simple examples<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\ni=0\r\nwhile &#x5B; $i -lt 10 ]\r\ndo\r\n   echo $i\r\n   ((i++))\r\ndone\r\n\r\nuntil &#x5B; $i -lt 0 ]\r\ndo\r\n   echo $i\r\n   ((i--))\r\ndone\r\n<\/pre>\n<p><em>for<\/em> loops using a similar syntax again, except they use the <em>in<\/em> keyword, for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\narray=(&quot;a&quot; &quot;b&quot; &quot;c&quot;)\r\nfor item in ${array&#x5B;@]}\r\ndo\r\n  echo $item\r\ndone\r\n<\/pre>\n<p>This example demonstrates looping through an array, but we can also loop through items returned by shell commands, for example<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nfor item in $(ls -a)\r\ndo\r\n   echo $item\r\ndone\r\n<\/pre>\n<p>In this example we&#8217;re looping through the results of the command <em>ls -a<\/em>. Although a better solution to this might be<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nfor item in ${PWD}\/*\r\ndo\r\n   echo $item\r\ndone\r\n<\/pre>\n<p>The <em>ls<\/em> version returns multiple items for a file name with spaces, so not too useful if we want each file name including spaces.<\/p>\n<p>Here&#8217;s a final example using using the back tick (`) which can be used to enclose commands, for example in this instance we execute the command <em>seq 1 10<\/em><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nfor item in `seq 1 10`;\r\ndo\r\n   echo $item\r\ndone   \r\n<\/pre>\n<p><strong>Passing arguments to your shell script<\/strong><\/p>\n<p>Arguments are passed into your script via the command line as you&#8217;d normal do, i.e. in this example my shell script (myscript.sh) takes two arguments <em>Hello<\/em> and <em>World<\/em><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n.\/myscript.sh Hello World \r\n<\/pre>\n<p>To reference the arguments in the script we simply use <em>$1<\/em> and <em>$2<\/em>. i.e.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\necho $1 # Should be Hello\r\necho $2 # Should be World\r\n<\/pre>\n<p>There also there&#8217;s also the $@ which denotes all arguments, i.e. <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\necho &quot;$@&quot; \r\n<\/pre>\n<p>Will output all the arguments passed into the script or function.<\/p>\n<p><strong>Functions<\/strong><\/p>\n<p>We can create functions inside our shell scripts and\/or include other script files which have functions etc. within.<\/p>\n<p>You need to declare the function before usage and writing a function is pretty simple, i.e.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nsay_hello()\r\n{\r\n    echo &quot;say_hello called&quot;\r\n}\r\n\r\nsay_hello\r\n<\/pre>\n<p>To include arguments\/parameters we use the same system as passing arguments via the command line, so for example<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nsay_something()\r\n{\r\n    echo &quot;say_something says $1 $2&quot;\r\n}\r\n\r\nsay_something Hello World\r\n# outputs say_something says Hello World\r\n<\/pre>\n<p>here we see the arguments are turned into the $1 and $2 variables, but of course local to our function.<\/p>\n<p><strong>STDIN\/STDOUT\/STDERR<\/strong><\/p>\n<p>We&#8217;ve already seen that <em>echo<\/em> is the equivalent of output to STDOUT in it&#8217;s default usage, although in can be used to output to STDERR, see <a href=\"http:\/\/wiki.bash-hackers.org\/howto\/redirection_tutorial\" rel=\"noopener\" target=\"_blank\">Illustrated Redirection Tutorial<\/a>.<\/p>\n<p>We can use <eam><a href=\"https:\/\/ss64.com\/bash\/read.html\" rel=\"noopener\" target=\"_blank\">read<\/a><\/em> to read input from the user\/command line via STDIN. <\/p>\n<p>In it&#8217;s most basic use we can write the following<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nread input \r\n<\/pre>\n<p>Where <em>input<\/em> is a variable name.<\/p>\n<p>We can also use it in slightly more powerful ways, such as <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nread -n1 -p &quot;Are you sure you wish to continue (y\/n)?&quot; input\r\n<\/pre>\n<p>In this case we read a single character (<em>-n1<\/em>) with the prompt (<em>-p<\/em>) &#8220;Are you sure you wish to continue (y\/n)?&#8221; into the variable named <em>input<\/em>.<\/p>\n<p>The <em>read<\/em> function can also be used to read data from a file by using a file descriptor and the argument <em>-u<\/em>.<\/p>\n<p><strong>References<\/strong><\/p>\n<p><a href=\"http:\/\/tldp.org\/HOWTO\/Bash-Prog-Intro-HOWTO-7.html\" rel=\"noopener\" target=\"_blank\">Loops for, while and until<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The shell script file By default we name a script file with the .sh extension and the first line is usually (although not strictly required) to be one of the following #!\/bin\/sh OR #!\/bin\/bash The use of sh tells Linux we want to run the script with the default shell script . Note that this [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[212],"tags":[],"class_list":["post-6138","post","type-post","status-publish","format-standard","hentry","category-shell-script"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=6138"}],"version-history":[{"count":23,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6138\/revisions"}],"predecessor-version":[{"id":6165,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/6138\/revisions\/6165"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=6138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=6138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=6138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}