{"id":2415,"date":"2015-08-09T20:11:46","date_gmt":"2015-08-10T03:11:46","guid":{"rendered":"http:\/\/mike.peay.us\/blog\/?p=2415"},"modified":"2015-08-09T20:11:46","modified_gmt":"2015-08-10T03:11:46","slug":"watching-a-log-file-in-a-bash-script","status":"publish","type":"post","link":"https:\/\/mike.peay.us\/blog\/archives\/2415","title":{"rendered":"Watching a log file in a bash script"},"content":{"rendered":"<p>For the last few months, I&#8217;ve been doing some contracting developing automation scripts in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bash_(Unix_shell)\">bash<\/a>. It&#8217;s been a fun diversion from my <a href=\"http:\/\/mike.peay.us\/blog\/archives\/2385\">job search<\/a>\u00c2\u00a0and leverages my\u00c2\u00a0sysadmin background. It has also improved my command of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Vim_(text_editor)\">vi<\/a> and several tricks in bash scripting. I wanted to share\u00c2\u00a0one that may be of help to others.<\/p>\n<p>In the scripts that I wrote, it was necessary to kick of a long-running process and then act on entries written to a log file. I created a watcher routine to accomplish this:<\/p>\n<pre style=\"padding-left: 30px;\">01  successfulRun=0\r\n02  keepRunning=1\r\n03  while [ $keepRunning -eq 1 ] &amp;&amp; read -t 3600 line; do\r\n04      case \"$line\" in\r\n05          *completion string* )\r\n06              echo \"Completed successfully. Exiting monitor.\"\r\n07              successfulRun=1\r\n08              keepRunning=0\r\n09              ;;\r\n10          *error string* )\r\n11              echo \"ERROR entry found in log. Exiting monitor.\"\r\n12              keepRunning=0\r\n13              ;;\r\n14          * )\r\n15              echo \"Just another line. Monitor continuing.\"\r\n16              ;;\r\n17      esac\r\n18  done &lt; &lt;(tail --pid=$$ -n0 -F ${logfile})<\/pre>\n<p>It&#8217;s a general while loop, but there are some useful\u00c2\u00a0features. First, in line 3 is &#8220;read -t 3600&#8221; which allows the loop to break if nothing gets written to the file for an hour (3600 seconds). After the loop, if keepRunning is 1 and successfulRun is 0, I know it timed out.<\/p>\n<p>Lines 5, 10, and 14 allow for cases for any strings encountered. For my uses, I was looking for a success string which\u00c2\u00a0meant my script could\u00c2\u00a0continue on. Similarly, if an error string is encountered, I exit accordingly. The last one (line 14) is the default case, which probably isn&#8217;t needed unless you want to provide feedback of progress.<\/p>\n<p>The last feature is in line 18. The &#8211;pid=$$ option allows the tail command to close the logfile when the parent script completes. That allows for a very nice wrap-up no matter what happens. Nice, huh?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For the last few months, I&#8217;ve been doing some contracting developing automation scripts in bash. It&#8217;s been a fun diversion from my job search\u00c2\u00a0and leverages my\u00c2\u00a0sysadmin background. It has also improved my command of vi and several tricks in bash &hellip; <a href=\"https:\/\/mike.peay.us\/blog\/archives\/2415\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_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":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[3,8],"tags":[],"class_list":["post-2415","post","type-post","status-publish","format-standard","hentry","category-geek","category-thoughts"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4vft-CX","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/posts\/2415","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/comments?post=2415"}],"version-history":[{"count":1,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/posts\/2415\/revisions"}],"predecessor-version":[{"id":2416,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/posts\/2415\/revisions\/2416"}],"wp:attachment":[{"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/media?parent=2415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/categories?post=2415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mike.peay.us\/blog\/wp-json\/wp\/v2\/tags?post=2415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}