{"id":188,"date":"2018-10-18T12:00:00","date_gmt":"2018-10-18T04:00:00","guid":{"rendered":"https:\/\/yeslq.com\/201810188.html"},"modified":"2019-05-07T10:43:33","modified_gmt":"2019-05-07T02:43:33","slug":"the-linux-command-line-flow-contro","status":"publish","type":"post","link":"https:\/\/yeslq.com\/?p=188","title":{"rendered":"The Linux Command Line&#8212;Flow Control &#8211; Part 1"},"content":{"rendered":"<h1 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\n<i style=\"font-size: x-small;\"><a href=\"http:\/\/linuxcommand.org\/tlcl.php\" style=\"color: #002740;\">The Linux Command Line&nbsp;<\/a><\/i><span style=\"font-size: xx-small;\">by William Shotts<\/span><\/h1>\n<div>\n<span style=\"font-size: xx-small;\"><br \/><\/span><\/div>\n<div>\n<span style=\"font-size: xx-small;\"><\/p>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn this lesson, we will look at how to add intelligence to our scripts. So far, our project script has only consisted of a sequence of commands that starts at the first line and continues line by line until it reaches the end. Most programs do much more than this. They make decisions and perform different actions depending on conditions.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe shell provides several commands that we can use to control the flow of execution in our program. In this lesson, we will look at the following:<\/div>\n<ul style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\n<li><a href=\"http:\/\/linuxcommand.org\/lc3_man_pages\/ifh.html\" style=\"color: #002740;\">if<\/a><\/li>\n<li><a href=\"http:\/\/linuxcommand.org\/lc3_man_pages\/testh.html\" style=\"color: #002740;\">test<\/a><\/li>\n<li><a href=\"http:\/\/linuxcommand.org\/lc3_man_pages\/exith.html\" style=\"color: #002740;\">exit<\/a><\/li>\n<\/ul>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nif<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe first command we will look at is&nbsp;if. The&nbsp;if&nbsp;command is fairly simple on the surface; it makes a decision based on the&nbsp;<i>exit status<\/i>&nbsp;of a command. The&nbsp;ifcommand&#8217;s syntax looks like this:<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe if statement has the following syntax:<\/div>\n<pre style=\"background-color: white; font-family: courier, lucidatypewriter, monospace;\">if commands; then\ncommands\n[elif commands; then\ncommands...]\n[else\ncommands]\nfi<\/pre>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nwhere&nbsp;<i>commands<\/i>&nbsp;is a list of commands. This is a little confusing at first glance. But before we can clear this up, we have to look at how the shell evaluates the success or failure of a command.<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nExit Status<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nCommands (including the scripts and shell functions we write) issue a value to the system when they terminate, called an exit status. This value, which is an integer in the range of 0 to 255, indicates the success or failure of the command\u2019s execution. By convention, a value of zero indicates success and any other value indicates failure. The shell provides a parameter that we can use to examine the exit status. Here we see it in action:<\/div>\n<div class=\"display\" style=\"background-color: black; color: lime; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n[me@linuxbox ~]$&nbsp;ls -d \/usr\/bin<br \/>\/usr\/bin<br \/>[me@linuxbox ~]$&nbsp;echo $?<br \/>0<br \/>[me@linuxbox ~]$&nbsp;ls -d \/bin\/usr<br \/>ls: cannot access \/bin\/usr: No such file or directory<br \/>[me@linuxbox ~]$&nbsp;echo $?<br \/>2<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn this example, we execute the&nbsp;ls&nbsp;command twice. The first time, the command executes successfully. If we display the value of the parameter&nbsp;$?, we see that it is zero. We execute the ls command a second time, producing an error and examine the parameter&nbsp;$?&nbsp;again. This time it contains a 2, indicating that the command encountered an error. Some commands use different exit status values to provide diagnostics for errors, while many commands simply exit with a value of one when they fail. Man pages often include a section entitled \u201cExit Status,\u201d describing what codes are used. However, a zero always indicates success.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe shell provides two extremely simple builtin commands that do nothing except terminate with either a zero or one exit status. The&nbsp;true&nbsp;command always executes successfully and the&nbsp;false&nbsp;command always executes unsuccessfully:<\/div>\n<div class=\"display\" style=\"background-color: black; color: lime; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n[me@linuxbox~]$&nbsp;true<br \/>[me@linuxbox~]$&nbsp;echo $?<br \/>0<br \/>[me@linuxbox~]$&nbsp;false<br \/>[me@linuxbox~]$&nbsp;echo $?<br \/>1<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWe can use these commands to see how the&nbsp;if&nbsp;statement works. What the&nbsp;if&nbsp;statement really does is evaluate the success or failure of commands:<\/div>\n<div class=\"display\" style=\"background-color: black; color: lime; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n[me@linuxbox ~]$&nbsp;if true; then echo &#8220;It&#8217;s true.&#8221;; fi<br \/>It&#8217;s true.<br \/>[me@linuxbox ~]$&nbsp;if false; then echo &#8220;It&#8217;s true.&#8221;; fi<br \/>[me@linuxbox ~]$<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe command&nbsp;echo &#8220;It&#8217;s true.&#8221;&nbsp;is executed when the command following&nbsp;if&nbsp;executes successfully, and is not executed when the command following&nbsp;ifdoes not execute successfully.<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\ntest<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe&nbsp;test&nbsp;command is used most often with the&nbsp;if&nbsp;command to perform true\/false decisions. The command is unusual in that it has two different syntactic forms:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\"># First form\n\ntest <i>expression<\/i>\n\n# Second form\n\n[ <i>expression<\/i> ]\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe&nbsp;test&nbsp;command works simply. If the given expression is true,&nbsp;test&nbsp;exits with a status of zero; otherwise it exits with a status of 1.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe neat feature of&nbsp;test&nbsp;is the variety of expressions you can create. Here is an example:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">if [ -f .bash_profile ]; then\n    echo \"You have a .bash_profile. Things are fine.\"\nelse\n    echo \"Yikes! You have no .bash_profile!\"\nfi\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn this example, we use the expression &#8221;&nbsp;-f .bash_profile&nbsp;&#8220;. This expression asks, &#8220;Is .bash_profile a file?&#8221; If the expression is true, then&nbsp;test&nbsp;exits with a zero (indicating true) and the&nbsp;if&nbsp;command executes the command(s) following the word&nbsp;then. If the expression is false, then&nbsp;test&nbsp;exits with a status of one and the&nbsp;if&nbsp;command executes the command(s) following the word&nbsp;else.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nHere is a partial list of the conditions that&nbsp;test&nbsp;can evaluate. Since&nbsp;test&nbsp;is a shell builtin, use &#8220;help test&#8221; to see a complete list.<\/div>\n<table border=\"\" cellpadding=\"8\" style=\"background-color: white; color: black; font-family: verdana, arial, helvetica, sans-serif;\">\n<tbody>\n<tr>\n<td valign=\"top\"><strong>Expression<\/strong><\/td>\n<td valign=\"top\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-d&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;is a directory.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-e&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;exists.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-f&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;exists and is a regular file.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-L&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;is a symbolic link.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-r&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;is a file readable by you.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-w&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;is a file writable by you.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-x&nbsp;<i>file<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file<\/i>&nbsp;is a file executable by you.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\"><i>file1<\/i>&nbsp;-nt&nbsp;<i>file2<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file1<\/i>&nbsp;is newer than (according to modification time)&nbsp;<i>file2<\/i><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\"><i>file1<\/i>&nbsp;-ot&nbsp;<i>file2<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>file1<\/i>&nbsp;is older than&nbsp;<i>file2<\/i><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-z&nbsp;<i>string<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>string<\/i>&nbsp;is empty.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">-n&nbsp;<i>string<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>string<\/i>&nbsp;is not empty.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\"><i>string1<\/i>&nbsp;=&nbsp;<i>string2<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>string1<\/i>&nbsp;equals&nbsp;<i>string2.<\/i><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\"><i>string1<\/i>&nbsp;!=&nbsp;<i>string2<\/i><\/td>\n<td valign=\"top\">True if&nbsp;<i>string1<\/i>&nbsp;does not equal&nbsp;<i>string2.<\/i><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nBefore we go on, I want to explain the rest of the example above, since it also reveals more important ideas.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn the first line of the script, we see the&nbsp;if&nbsp;command followed by the&nbsp;test&nbsp;command, followed by a semicolon, and finally the word&nbsp;then. I chose to use the&nbsp;[&nbsp;<i>expression<\/i>&nbsp;]&nbsp;form of the&nbsp;test&nbsp;command since most people think it&#8217;s easier to read. Notice that the spaces required between the &#8220;[&#8221; and the beginning of the expression are required. Likewise, the space between the end of the expression and the trailing &#8220;]&#8221;.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe semicolon is a command separator. Using it allows you to put more than one command on a line. For example:<\/div>\n<div class=\"display\" style=\"background-color: black; color: lime; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n[me@linuxbox me]$&nbsp;clear; ls<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nwill clear the screen and execute the ls command.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nI use the semicolon as I did to allow me to put the word&nbsp;then&nbsp;on the same line as the&nbsp;if&nbsp;command, because I think it is easier to read that way.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nOn the second line, there is our old friend&nbsp;echo. The only thing of note on this line is the indentation. Again for the benefit of readability, it is traditional to indent all blocks of conditional code; that is, any code that will only be executed if certain conditions are met. The shell does not require this; it is done to make the code easier to read.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn other words, we could write the following and get the same results:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\"># Alternate form\n\nif [ -f .bash_profile ]\nthen\n    echo \"You have a .bash_profile. Things are fine.\"\nelse\n    echo \"Yikes! You have no .bash_profile!\"\nfi\n\n# Another alternate form\n\nif [ -f .bash_profile ]\nthen echo \"You have a .bash_profile. Things are fine.\"\nelse echo \"Yikes! You have no .bash_profile!\"\nfi\n       \n<\/pre>\n<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nexit<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn order to be good script writers, we must set the exit status when our scripts finish. To do this, use the&nbsp;exit&nbsp;command. The&nbsp;exit&nbsp;command causes the script to terminate immediately and set the exit status to whatever value is given as an argument. For example:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">exit 0\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nexits your script and sets the exit status to 0 (success), whereas<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">exit 1\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nexits your script and sets the exit status to 1 (failure).<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nTesting For Root<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWhen we last left our script, we required that it be run with superuser privileges. This is because the&nbsp;home_space&nbsp;function needs to examine the size of each user&#8217;s home directory, and only the superuser is allowed to do that.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nBut what happens if a regular user runs our script? It produces a lot of ugly error messages. What if we could put something in the script to stop it if a regular user attempts to run it?<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe&nbsp;<a href=\"http:\/\/linuxcommand.org\/lc3_man_pages\/id1.html\" style=\"color: #002740;\">id<\/a>&nbsp;command can tell us who the current user is. When executed with the &#8220;-u&#8221; option, it prints the numeric user id of the current user.<\/div>\n<div class=\"display\" style=\"background-color: black; color: lime; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n[me@linuxbox me]$&nbsp;id -u<br \/>501<br \/>[me@linuxbox me]$&nbsp;su<br \/>Password:<br \/>[root@linuxbox me]#&nbsp;id -u<br \/>0<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIf the superuser executes&nbsp;id -u, the command will output &#8220;0.&#8221; This fact can be the basis of our test:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">if [ $(id -u) = \"0\" ]; then\n    echo \"superuser\"\nfi\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIn this example, if the output of the command&nbsp;id -u&nbsp;is equal to the string &#8220;0&#8221;, then print the string &#8220;superuser.&#8221;<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWhile this code will detect if the user is the superuser, it does not really solve the problem yet. We want to stop the script if the user is not the superuser, so we will code it like so:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">if [ $(id -u) != \"0\" ]; then\n    echo \"You must be the superuser to run this script\" &gt;&amp;2\n    exit 1\nfi\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWith this code, if the output of the&nbsp;id -u&nbsp;command is not equal to &#8220;0&#8221;, then the script prints a descriptive error message, exits, and sets the exit status to 1, indicating to the operating system that the script executed unsuccessfully.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nNotice the &#8220;&gt;&amp;2&#8221; at the end of the&nbsp;echo&nbsp;command. This is another form of I\/O direction. You will often notice this in routines that display error messages. If this redirection were not done, the error message would go to standard output. With this redirection, the message is sent to standard error. Since we are executing our script and redirecting its standard output to a file, we want the error messages separated from the normal output.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWe could put this routine near the beginning of our script so it has a chance to detect a possible error before things get under way, but in order to run this script as an ordinary user, we will use the same idea and modify the&nbsp;home_space&nbsp;function to test for proper privileges instead, like so:<\/div>\n<div class=\"codeexample\" style=\"background-color: #e0e0e0; font-family: verdana, arial, helvetica, sans-serif; padding: 0.5em;\">\n<pre style=\"font-family: courier, lucidatypewriter, monospace;\">function home_space\n{\n    # Only the superuser can get this information\n\n    if [ \"$(id -u)\" = \"0\" ]; then\n        echo \"&lt;h2&gt;Home directory space by user&lt;\/h2&gt;\"\n        echo \"&lt;pre&gt;\"\n        echo \"Bytes Directory\"\n            du -s \/home\/* | sort -nr\n        echo \"&lt;\/pre&gt;\"\n    fi\n\n}   # end of home_space\n       \n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThis way, if an ordinary user runs the script, the troublesome code will be passed over, rather than executed and the problem will be solved.<\/div>\n<p><\/span><\/div>\n","protected":false},"excerpt":{"rendered":"<p>The Linux Command Line&nbsp;by William Shotts In this l &#8230; <a title=\"The Linux Command Line&#8212;Flow Control &#8211; Part 1\" class=\"read-more\" href=\"https:\/\/yeslq.com\/?p=188\" aria-label=\"\u9605\u8bfb The Linux Command Line&#8212;Flow Control &#8211; Part 1\">\u9605\u8bfb\u66f4\u591a<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[51,52,53],"class_list":["post-188","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-linux","tag-shell","tag-the-linux-command-line"],"_links":{"self":[{"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts\/188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=188"}],"version-history":[{"count":1,"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts\/188\/revisions"}],"predecessor-version":[{"id":316,"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts\/188\/revisions\/316"}],"wp:attachment":[{"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}