{"id":184,"date":"2018-10-20T12:00:00","date_gmt":"2018-10-20T04:00:00","guid":{"rendered":"https:\/\/yeslq.com\/201810184.html"},"modified":"2019-05-07T10:43:38","modified_gmt":"2019-05-07T02:43:38","slug":"the-linux-command-line-positiona","status":"publish","type":"post","link":"https:\/\/yeslq.com\/?p=184","title":{"rendered":"The Linux Command Line&#8212;Positional Parameters"},"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;\">\nWhen we last left our script, it looked something like this:<\/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;\">#!\/bin\/bash\n\n# sysinfo_page - A script to produce a system information HTML file\n\n##### Constants\n\nTITLE=\"System Information for $HOSTNAME\"\nRIGHT_NOW=$(date +\"%x %r %Z\")\nTIME_STAMP=\"Updated on $RIGHT_NOW by $USER\"\n\n##### Functions\n\nsystem_info()\n{\n    echo \"&lt;h2&gt;System release info&lt;\/h2&gt;\"\n    echo \"&lt;p&gt;Function not yet implemented&lt;\/p&gt;\"\n\n}   # end of system_info\n\n\nshow_uptime()\n{\n    echo \"&lt;h2&gt;System uptime&lt;\/h2&gt;\"\n    echo \"&lt;pre&gt;\"\n    uptime\n    echo \"&lt;\/pre&gt;\"\n\n}   # end of show_uptime\n\n\ndrive_space()\n{\n    echo \"&lt;h2&gt;Filesystem space&lt;\/h2&gt;\"\n    echo \"&lt;pre&gt;\"\n    df\n    echo \"&lt;\/pre&gt;\"\n\n}   # end of drive_space\n\n\nhome_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\n\n##### Main\n\ncat &lt;&lt;- _EOF_\n  &lt;html&gt;\n  &lt;head&gt;\n      &lt;title&gt;$TITLE&lt;\/title&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n      &lt;h1&gt;$TITLE&lt;\/h1&gt;\n      &lt;p&gt;$TIME_STAMP&lt;\/p&gt;\n      $(system_info)\n      $(show_uptime)\n      $(drive_space)\n      $(home_space)\n  &lt;\/body&gt;\n  &lt;\/html&gt;\n_EOF_\n\n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWe have most things working, but there are several more features I want to add:<\/div>\n<ol style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\n<li>I want to specify the name of the output file on the command line, as well as set a default output file name if no name is specified.<\/li>\n<li>I want to offer an interactive mode that will prompt for a file name and warn the user if the file exists and prompt the user to overwrite it.<\/li>\n<li>Naturally, we want to have a help option that will display a usage message.<\/li>\n<\/ol>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nAll of these features involve using command line options and arguments. To handle options on the command line, we use a facility in the shell called&nbsp;<i>positional parameters<\/i>. Positional parameters are a series of special variables ($0&nbsp;through&nbsp;$9) that contain the contents of the command line.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nLet&#8217;s imagine the following command line:<\/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;some_program word1 word2 word3<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nIf&nbsp;some_program&nbsp;were a bash shell script, we could read each item on the command line because the positional parameters contain the following:<\/div>\n<ul style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\n<li>$0 would contain &#8220;some_program&#8221;<\/li>\n<li>$1 would contain &#8220;word1&#8221;<\/li>\n<li>$2 would contain &#8220;word2&#8221;<\/li>\n<li>$3 would contain &#8220;word3&#8221;<\/li>\n<\/ul>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nHere is a script you can use to try this out:<\/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;\">#!\/bin\/bash\n\necho \"Positional Parameters\"\necho '$0 = ' $0\necho '$1 = ' $1\necho '$2 = ' $2\necho '$3 = ' $3\n\n<\/pre>\n<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nDetecting Command Line Arguments<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nOften, you will want to check to see if you have arguments on which to act. There are a couple of ways to do this. First, you could simply check to see if&nbsp;$1contains anything 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;\">#!\/bin\/bash\n\nif [ \"$1\" != \"\" ]; then\n    echo \"Positional parameter 1 contains something\"\nelse\n    echo \"Positional parameter 1 is empty\"\nfi\n\n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nSecond, the shell maintains a variable called&nbsp;$#&nbsp;that contains the number of items on the command line in addition to the name of the command ($0).<\/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;\">#!\/bin\/bash\n\nif [ $# -gt 0 ]; then\n    echo \"Your command line contains $# arguments\"\nelse\n    echo \"Your command line contains no arguments\"\nfi\n\n<\/pre>\n<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nCommand Line Options<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nAs we discussed before, many programs, particularly ones from&nbsp;<a href=\"http:\/\/www.gnu.org\/\" style=\"color: #002740;\">the GNU Project<\/a>, support both short and long command line options. For example, to display a help message for many of these programs, you may use either the &#8220;-h&#8221; option or the longer &#8220;&#8211;help&#8221; option. Long option names are typically preceded by a double dash. We will adopt this convention for our scripts.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nHere is the code we will use to process our command line:<\/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;\">interactive=\nfilename=~\/sysinfo_page.html\n\nwhile [ \"$1\" != \"\" ]; do\n    case $1 in\n        -f | --file )           shift\n                                filename=$1\n                                ;;\n        -i | --interactive )    interactive=1\n                                ;;\n        -h | --help )           usage\n                                exit\n                                ;;\n        * )                     usage\n                                exit 1\n    esac\n    shift\ndone\n\n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThis code is a little tricky, so bear with me as I attempt to explain it.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe first two lines are pretty easy. We set the variable&nbsp;interactive&nbsp;to be empty. This will indicate that the interactive mode has not been requested. Then we set the variable&nbsp;filename&nbsp;to contain a default file name. If nothing else is specified on the command line, this file name will be used.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nAfter these two variables are set, we have default settings, in case the user does not specify any options.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nNext, we construct a&nbsp;while&nbsp;loop that will cycle through all the items on the command line and process each one with&nbsp;case. The&nbsp;case&nbsp;will detect each possible option and process it accordingly.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nNow the tricky part. How does that loop work? It relies on the magic of&nbsp;shift.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nshift&nbsp;is a shell builtin that operates on the positional parameters. Each time you invoke&nbsp;shift, it &#8220;shifts&#8221; all the positional parameters down by one.&nbsp;$2becomes&nbsp;$1,&nbsp;$3&nbsp;becomes&nbsp;$2,&nbsp;$4&nbsp;becomes&nbsp;$3, and so on. Try this:<\/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;\">#!\/bin\/bash\n\necho \"You start with $# positional parameters\"\n\n# Loop until all parameters are used up\nwhile [ \"$1\" != \"\" ]; do\n    echo \"Parameter 1 equals $1\"\n    echo \"You now have $# positional parameters\"\n\n    # Shift all the parameters down by one\n    shift\n\ndone\n\n<\/pre>\n<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nGetting An Option&#8217;s Argument<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nOur &#8220;-f&#8221; option requires a valid file name as an argument. We use&nbsp;shift&nbsp;again to get the next item from the command line and assign it to&nbsp;filename. Later we will have to check the content of&nbsp;filename&nbsp;to make sure it is valid.<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nIntegrating The Command Line Processor Into The Script<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWe will have to move a few things around and add a usage function to get this new routine integrated into our script. We&#8217;ll also add some test code to verify that the command line processor is working correctly. Our script now looks like this:<\/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;\">#!\/bin\/bash\n\n# sysinfo_page - A script to produce a system information HTML file\n\n##### Constants\n\nTITLE=\"System Information for $HOSTNAME\"\nRIGHT_NOW=$(date +\"%x %r %Z\")\nTIME_STAMP=\"Updated on $RIGHT_NOW by $USER\"\n\n##### Functions\n\nsystem_info()\n{\n    echo \"&lt;h2&gt;System release info&lt;\/h2&gt;\"\n    echo \"&lt;p&gt;Function not yet implemented&lt;\/p&gt;\"\n\n}   # end of system_info\n\n\nshow_uptime()\n{\n    echo \"&lt;h2&gt;System uptime&lt;\/h2&gt;\"\n    echo \"&lt;pre&gt;\"\n    uptime\n    echo \"&lt;\/pre&gt;\"\n\n}   # end of show_uptime\n\n\ndrive_space()\n{\n    echo \"&lt;h2&gt;Filesystem space&lt;\/h2&gt;\"\n    echo \"&lt;pre&gt;\"\n    df\n    echo \"&lt;\/pre&gt;\"\n\n}   # end of drive_space\n\n\nhome_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\nwrite_page()\n{\n    cat &lt;&lt;- _EOF_\n    &lt;html&gt;\n        &lt;head&gt;\n        &lt;title&gt;$TITLE&lt;\/title&gt;\n        &lt;\/head&gt;\n        &lt;body&gt;\n        &lt;h1&gt;$TITLE&lt;\/h1&gt;\n        &lt;p&gt;$TIME_STAMP&lt;\/p&gt;\n        $(system_info)\n        $(show_uptime)\n        $(drive_space)\n        $(home_space)\n        &lt;\/body&gt;\n    &lt;\/html&gt;\n_EOF_\n\n}\n\nusage()\n{\n    echo \"usage: sysinfo_page [[[-f file ] [-i]] | [-h]]\"\n}\n\n\n##### Main\n\ninteractive=\nfilename=~\/sysinfo_page.html\n\nwhile [ \"$1\" != \"\" ]; do\n    case $1 in\n        -f | --file )           shift\n                                filename=$1\n                                ;;\n        -i | --interactive )    interactive=1\n                                ;;\n        -h | --help )           usage\n                                exit\n                                ;;\n        * )                     usage\n                                exit 1\n    esac\n    shift\ndone\n\n\n# Test code to verify command line processing\n\nif [ \"$interactive\" = \"1\" ]; then\n echo \"interactive is on\"\nelse\n echo \"interactive is off\"\nfi\necho \"output file = $filename\"\n\n\n# Write page (comment out until testing is complete)\n\n# write_page &gt; $filename\n\n<\/pre>\n<\/div>\n<h2 style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-weight: normal;\">\nAdding Interactive Mode<\/h2>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nThe interactive mode is implemented with the following code:<\/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 [ \"$interactive\" = \"1\" ]; then\n\n    response=\n\n    echo -n \"Enter name of output file [$filename] &gt; \"\n    read response\n    if [ -n \"$response\" ]; then\n        filename=$response\n    fi\n\n    if [ -f $filename ]; then\n        echo -n \"Output file exists. Overwrite? (y\/n) &gt; \"\n        read response\n        if [ \"$response\" != \"y\" ]; then\n            echo \"Exiting program.\"\n            exit 1\n        fi\n    fi\nfi\n\n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nFirst, we check if the interactive mode is on, otherwise we don&#8217;t have anything to do. Next, we ask the user for the file name. Notice the way the prompt is worded:<\/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;\">echo -n \"Enter name of output file [$filename] &gt; \"\n\n<\/pre>\n<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nWe display the current value of&nbsp;filename&nbsp;since, the way this routine is coded, if the user just presses the enter key, the default value of&nbsp;filename&nbsp;will be used. This is accomplished in the next two lines where the value of&nbsp;response&nbsp;is checked. If&nbsp;response&nbsp;is not empty, then&nbsp;filename&nbsp;is assigned the value ofresponse. Otherwise,&nbsp;filename&nbsp;is left unchanged, preserving its default value.<\/div>\n<div style=\"background-color: white; font-family: verdana, arial, helvetica, sans-serif;\">\nAfter we have the name of the output file, we check if it already exists. If it does, we prompt the user. If the user response is not &#8220;y,&#8221; we give up and exit, otherwise we can proceed.<\/div>\n<p><\/span><\/div>\n","protected":false},"excerpt":{"rendered":"<p>The Linux Command Line&nbsp;by William Shotts When we l &#8230; <a title=\"The Linux Command Line&#8212;Positional Parameters\" class=\"read-more\" href=\"https:\/\/yeslq.com\/?p=184\" aria-label=\"\u9605\u8bfb The Linux Command Line&#8212;Positional Parameters\">\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-184","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\/184","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=184"}],"version-history":[{"count":1,"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts\/184\/revisions"}],"predecessor-version":[{"id":320,"href":"https:\/\/yeslq.com\/index.php?rest_route=\/wp\/v2\/posts\/184\/revisions\/320"}],"wp:attachment":[{"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=184"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=184"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yeslq.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=184"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}