{"id":964,"date":"2019-03-19T09:56:00","date_gmt":"2019-03-19T09:56:00","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=964"},"modified":"2019-07-30T10:16:01","modified_gmt":"2019-07-30T10:16:01","slug":"best-practices-for-writing-a-shell-script-2","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2019\/03\/19\/best-practices-for-writing-a-shell-script-2\/","title":{"rendered":"Best Practices for Writing a Shell Script"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2019\/03\/7ac1c-best-practices-1.png\" alt=\"\" \/><\/figure><\/div>\n\n\n\n<p>I am a lazy DevOps Engineer. So whenever I came across&nbsp;the same task more than 2 times I automate that. Although now we have many automation tools, still the first thing that hit into our mind for automation is bash or shell script.<br>After making a lot of mistakes and messy scripts :), I am sharing my experiences for writing a good shell script which not only looks good but also it will reduce the chances of error.<\/p>\n\n\n\n<p>The things that every code should have:-<br>&nbsp; &nbsp; &nbsp;&#8211; A minimum effort in the modification.<br>&nbsp; &nbsp; &nbsp;&#8211; Your program should talk in itself, so you don&#8217;t have to explain it.<br>&nbsp; &nbsp; &nbsp;&#8211; Reusability, Of course, I can&#8217;t write the same kind of script or program again and again.<\/p>\n\n\n\n<p>I am a firm believer in learning by doing. So let&#8217;s create a problem statement for ourselves and then try to solve it via shell scripting with best practices :). I would like to have solutions in the comment section of this blog.<\/p>\n\n\n\n<p><br><strong>Problem Statement:-&nbsp;<\/strong>Write a shell script to install and uninstall a package(vim) depending on the arguments. The script should tell if the package is already installed. If no argument is passed it should print the help page.<\/p>\n\n\n\n<p>So without wasting time let&#8217;s start for writing an awesome shell script. Here is the list of things that should always be taken care of while writing a shell script.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Lifespan of Script<\/h3>\n\n\n\n<p>If your script is procedural(each subsequent steps relies on the previous step to complete), do me a favor and add&nbsp;<strong>set -e&nbsp;<\/strong>in starting of the script so that the script exists on the first error. For example:-<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash\nset -e # Script exists on the first failure\nset -x # For debugging purpose<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Functions<\/h3>\n\n\n\n<p>Ahha, Functions are my most favorite part of programming. There is a saying<br><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&nbsp;<\/p><\/blockquote>\n\n\n\n<p>To achieve this always try to use functions and name them properly so that anyone can understand the function just by reading its name. Functions also provide the concept of re-usability. It also removes the duplicating of code, how? let&#8217;s see this<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash \ninstall_package() {\n   local PACKAGE_NAME=\"$1\"\n   yum install \"${PACKAGE_NAME}\" -y\n}\ninstall_package \"vim\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Command Sanity<\/h3>\n\n\n\n<p>Usually, scripts call other scripts or binary. When we are dealing with commands there are chances that commands will not be available on all systems. So my suggestion is to check them before proceeding.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash  \ncheck_package() {\n    local PACKAGE_NAME=\"$1\"\n    if ! command -v \"${PACKAGE_NAME}\" &gt; \/dev\/null 2&gt;&amp;1\n    then\n           printf \"${PACKAGE_NAME} is not installed.\\n\"\n    else\n           printf \"${PACKAGE_NAME} is already installed.\\n\"\n    fi\n}\ncheck_package \"vim\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Help Page<\/h3>\n\n\n\n<p>If you guys are familiar with Linux, you have certainly noticed that every Linux&nbsp;command has its help page. The same thing can be true for the script as well. It would be really helpful to include&nbsp;<strong>&#8211;help&nbsp;<\/strong>flag.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash  \nINITIAL_PARAMS=\"$*\"\nhelp_function() {\n   {\n        printf \"Usage:- .\/script &lt;option&gt;\\n\"\n        printf \"Options:\\n\"\n        printf \" -a ==&gt; Install all base softwares\\n\"\n        printf \" -r ==&gt; Remove base softwares\\n\"\n    }\n}\narg_checker() {\n     if [ \"${INITIAL_PARAMS}\" == \"--help\" ]; then\n            help_function\n     fi\n}\narg_checker<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Logging<\/h3>\n\n\n\n<p>Logging is the most critical thing for everyone whether he is a developer, sysadmin or DevOps. Debugging seems to be impossible without logs. As we know most applications generate logs for understanding that what is happening with the application, the same practice can be implemented for shell script as well. For generating logs we have a bash utility called&nbsp;<strong>logger<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash \nDATE=$(date)\ndeclare DATE\ncheck_file() {\n     local FILENAME=\"$1\"\n     if ! ls \"${FILENAME}\" &gt; \/dev\/null 2&gt;&amp;1\n     then\n            logger -s \"${DATE}: ${FILENAME} doesn't exists\"\n     else\n           logger -s \"${DATE}: ${FILENAME} found successfuly\"\n     fi\n}\ncheck_file \"\/etc\/passwd\"<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Variables<\/h3>\n\n\n\n<p>I like to name my variables in Capital letters with an underscore, In this way, I will not get confused with the function name and variable name. Never give&nbsp;<strong>a,b,c<\/strong>&nbsp;etc. as a&nbsp;variable name instead of that try to give a proper name to a variable as well just like functions.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash \n# Use declare for declaring global variables\ndeclare GLOBAL_MESSAGE=\"Hey, I am a global message\"\n# Use local for declaring local variables inside the function\nmessage_print() {\n    local LOCAL_MESSAGE=\"Hey, I am a local message\"\n    printf \"Global Message:- ${GLOBAL_MESSAGE}\\n\"\n    printf \"Local Message:- ${LOCAL_MESSAGE}\\n\"\n}\nmessage_print<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Cases<\/h3>\n\n\n\n<p>Cases are also a fascinating part of shell script. But the question is when to use this? According to me if your shell program is providing more than one functionality basis on the arguments then you should go for cases. For example:- If your shell utility provides the capability of installing and uninstalling the software.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code brush: bash; notranslate\">#!\/bin\/bash  \nprint_message() {\n    MESSAGE=\"$1\"\n    echo \"${MESSAGE}\"\n}\ncase \"$1\" in\n   -i|--input)\n      print_message \"Input Message\"\n      ;;\n   -o|--output)\n        print_message \"Output Message\"\n        ;;\n   --debug)\n       print_message \"Debug Message\"\n       ;;\n    *)\n      print_message \"Wrong Input\"\n      ;;\nesac<\/pre>\n\n\n\n<p>In this blog, we have covered functions, variables, the lifespan of a script, logging, help page, command sanity.&nbsp;I hope these topics help you in your daily life while using the shell script. If you have any feedback please let me know through comments.<br>Cheers Till the next Time!!!!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I am a lazy DevOps Engineer. So whenever I came across&nbsp;the same task more than 2 times I automate that. Although now we have many automation tools, still the first thing that hit into our mind for automation is bash or shell script.After making a lot of mistakes and messy scripts :), I am sharing &hellip; <a href=\"https:\/\/opstree.com\/blog\/2019\/03\/19\/best-practices-for-writing-a-shell-script-2\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Best Practices for Writing a Shell Script&#8221;<\/span><\/a><\/p>\n","protected":false},"author":89038429,"featured_media":29900,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[1],"tags":[44070,768739308,768739285,290243],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2025\/11\/DevSecOps-1.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-fy","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/964"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/89038429"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=964"}],"version-history":[{"count":6,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/964\/revisions"}],"predecessor-version":[{"id":972,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/964\/revisions\/972"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/29900"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=964"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=964"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=964"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}