<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="http://quest.windwards.net"  xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
 <title>Quest for improvement - shell-scripting</title>
 <link>http://quest.windwards.net/tags/shell-scripting</link>
 <description></description>
 <language>en</language>
<item>
 <title>Shell scripting patterns: configuration and option parsing</title>
 <link>http://quest.windwards.net/content/shell-scripting-patterns-configuration-and-option-parsing</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;
	Adhering to software patterns lowers the threshold for doing the right thing, even when the quick hack beckons. This is particularly true in shell script handling of options and configuration. Essentially, the top of all scripts should look like this:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
OPTION1=&quot;default_value&quot;

. /etc/my.conf

function usage() {
    echo &quot;./dascript [-o &amp;lt;value&amp;gt;] -p &amp;lt;value&amp;gt;&quot;
    echo &quot; -o: set the value of option1&quot;
    echo &quot; -p: set the value of option2&quot;
}

while getopts &quot;ho:p:&quot; opt ; do
    case &quot;$opt&quot; in
    o) OPTION1=$OPTARG
    p) OPTION2=$OPTARG
    h) usage ; exit 0 ;;
    *) usage &amp;gt;&amp;amp;2 ; exit 1 ;;
    esac
}

[ -n &quot;$OPTION2&quot; ] || {
    echo &quot;Please supply -p &amp;lt;value&amp;gt;&quot;
    usage
    exit 1
} &amp;gt;&amp;amp;2
&lt;/pre&gt;&lt;p&gt;
	Copy the above example each time you get to the point where you need any configuration whatever for a script. It&#039;s much easier than trying to cheat.&lt;/p&gt;
&lt;p&gt;
	So what is going on?&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		List all parameter with their default values.&lt;/li&gt;
&lt;li&gt;
		Source a configuration file, which will overwrite the default value.&lt;/li&gt;
&lt;li&gt;
		Define a function usage that prints all available options (so that we can use it when parsing options).&lt;/li&gt;
&lt;li&gt;
		Parse options supplied on the commandline to allow overriding the configuration file.&lt;/li&gt;
&lt;li&gt;
		Verify that options have good values, including mandatory options.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;
	The only time this pattern fails is when you need to allow supplying the name of the configuration file.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;field field-name-field-tags field-type-taxonomy-term-reference field-label-above&quot;&gt;&lt;div class=&quot;field-label&quot;&gt;Tags:&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/quest-blog&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;quest-blog&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item odd&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/shell-scripting&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;shell-scripting&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/software-development&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;software-development&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Wed, 06 Jul 2011 20:49:51 +0000</pubDate>
 <dc:creator>quest</dc:creator>
 <guid isPermaLink="false">7 at http://quest.windwards.net</guid>
 <comments>http://quest.windwards.net/content/shell-scripting-patterns-configuration-and-option-parsing#comments</comments>
</item>
<item>
 <title>Shell scripting patterns: paths, file globs and and current dir</title>
 <link>http://quest.windwards.net/content/shell-scripting-patterns-paths-file-globs-and-and-current-dir</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;The basis of this pattern is simple: never ever change current working directory in your scripts. In fact, never ever assume that you have a working directory unless your command explicitly works from local directory (e.g. find). Consequently, you should never use relative paths in your script unless you got it from the caller; since your script doesn&#039;t change working directory, it&#039;s fine to just use whatever path the caller handed you.&lt;/p&gt;
&lt;p&gt;There are numerous reasons for this. The most straightforward reason for this is that &lt;strong&gt;cd&lt;/strong&gt; executed without an argument will change directory to the executing user&#039;s home directory, which is arguably where the script can do the most damage.&lt;/p&gt;
&lt;p&gt;There is one case where your script needs to refer to a relative path, namely if your script is distributed together with other files (e.g. in a zip file) and should be runnable after being unzipped. The script must be able to find files/directories relative to wherever &lt;strong&gt;the script&lt;/strong&gt; resides, so relative to the current working directory does not cut it if the user tries ./zipdir/script.sh. Fortunately, all shells have a $0 that is the path of the script itself. Thus, you do this:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
DATADIR=$(dirname $0)/data&lt;/pre&gt;&lt;p&gt;While you are avoiding things, also avoid shell expanded glob expressions. They are simply too imprecise and it is too easy to get bitten by paths with space in them. In 99 of 100 cases, &lt;strong&gt;find&lt;/strong&gt; is better than shell glob. &lt;strong&gt;find&lt;/strong&gt; is your friend.&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
find /dir/with/cruft -mindepth 1 -maxdepth 1 \
     -type f -regex &#039;.*\.sh&#039; | frobnicate_script&lt;/pre&gt;&lt;p&gt;There are numerous things going on here. mindepth/maxdepth describes how deep to look; a depth of 0 means the path supplied to find, so 1/1 means &quot;look in the directory /dir/with/cruft&quot;. type f means &quot;look only for files&quot;. regex uses regular expressions to match files, which is a lot more expressive than globs (normally supplied to find via -name). It is tempting at this point to reach for -exec, but please refrain. The exec option creates code that is very difficult to read.&lt;/p&gt;
&lt;p&gt;Instead xargs is the friend of your find. If all you want to do is a simple operation on each found file, you can do something like this:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
find $rootdir -mindepth 1 -type d -cmin -10 -print0 | xargs -0 chmod o-rwx&lt;/pre&gt;&lt;p&gt;Or, in English: remove world permissions on all directories under $rootdir that I created the last 10 minutes. Find option -print0 will terminate each line with a null character instead of a newline and -0 will tell xargs to ignore whitespace and instead react to null characters. Presto, no problem with space (or even newlines) in paths.&lt;/p&gt;
&lt;p&gt;Discouraging users from using delimiter characters (such as space, tab, newline, comma, pipe, et.c.) in file and directory names is part of the holy cause. Nevertheless, some file will have them, sometimes even for good reasons. So your script needs to be prepared for them. Quote all data that comes from outside.&lt;/p&gt;
&lt;p&gt;As an aside, it is an annoying aspect of shell scripting that most syntax highlighters will treat e.g. &quot;$1&quot; as a string and give it string colour, but $1 as a variable and give it variable colour. Most unhelpful.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;field field-name-field-tags field-type-taxonomy-term-reference field-label-above&quot;&gt;&lt;div class=&quot;field-label&quot;&gt;Tags:&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/quest-blog&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;quest-blog&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item odd&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/shell-scripting&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;shell-scripting&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/software-development&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;software-development&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Mon, 04 Jul 2011 22:01:21 +0000</pubDate>
 <dc:creator>quest</dc:creator>
 <guid isPermaLink="false">5 at http://quest.windwards.net</guid>
 <comments>http://quest.windwards.net/content/shell-scripting-patterns-paths-file-globs-and-and-current-dir#comments</comments>
</item>
<item>
 <title>Shell scripting patterns: errors and failure</title>
 <link>http://quest.windwards.net/content/shell-scripting-patterns-errors-and-failure</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;In my opinion, error handling is the area where shell script clearest shows its age. The idea that the shell will &lt;strong&gt;by default&lt;/strong&gt; ignore that commands signal an error state (i.e. a non-zero exit code) seems very strange when viewed through the lens of modern programming theory. Thus, all scripts should start with this instruction, that tells the shell to care about exit codes:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
set -e&lt;/pre&gt;&lt;p&gt;Now, the following code will no longer result in tears when /destination does not exist:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
process &amp;lt; /source/file &amp;gt; /destination/file
rm /source/file
&lt;/pre&gt;&lt;p&gt;To explicitly ignore the exit code of a command, use:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
process &amp;lt; /source/file &amp;gt; /no/such/file || true&lt;/pre&gt;&lt;p&gt;... or if you care, but don&#039;t want to just bail, you can:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
may_explode || result=$?&lt;/pre&gt;&lt;p&gt;Just remember that $result will be empty rather than 0 if all goes well, so you cannot do [ $result -gt 0 ].&lt;/p&gt;
&lt;p&gt;In rare cases, it may genuinely be that you have a section of instructions that you&lt;strong&gt; want&lt;/strong&gt; to execute even if the previous fail. If so, use a subshell:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
(
    set +e
    ...
)&lt;/pre&gt;&lt;p&gt;The set operation will only be active in the subshell.&lt;/p&gt;
&lt;p&gt;It is quite possible to achieve something akin to modern exception handling in bash shells. Consider the following:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
(
    do_this || exit 1
    do_that || exit 2
) || {
    fail=$?
    case $fail in
    1) handle_case_1 ;;
    2) handle_case_2 ;;
    *) exit $fail ;;
    esac
}&lt;/pre&gt;&lt;p&gt;Of course, do_this, do_that may already return decent exit codes such that you don&#039;t need the &#039;|| exit&#039; bit. More generally, now that &lt;strong&gt;set -e&lt;/strong&gt; is turned on, you need a mental model of execution flow, much like any other programming language. Just remember the law: &lt;em&gt;any context (be it subshell, function or block) has an exit code/return value of the first statement executed that returns a non-zero exit code/return value.&lt;/em&gt; Somewhat simplified, as soon as a statement returns non-zero, execution will abandon successive scopes until someone &quot;handles&quot; the non-zero state. The three main ways to &quot;handle&quot; the non-zero state are pipe &quot;|&quot;,  command substitution &quot;$()&quot;, or &quot;||&quot;. The background control operator &quot;&amp;amp;&quot; also does not propagate the exit code (it can later be retreived with &lt;strong&gt;wait&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;It may be tempting to use &lt;strong&gt;exit&lt;/strong&gt; to make life simpler inside functions, but you should resist. exit will abort execution of the current shell, but parentheses and pipes create subshells, so a function cannot know whether it will abort the master shell process or just a subshell. Use only return statements in functions and save exit for top-level code. exit should only be needed in top-level code to tell the caller that parameters or input were invalid.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;field field-name-field-tags field-type-taxonomy-term-reference field-label-above&quot;&gt;&lt;div class=&quot;field-label&quot;&gt;Tags:&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/quest-blog&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;quest-blog&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item odd&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/shell-scripting&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;shell-scripting&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/software-development&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;software-development&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Mon, 04 Jul 2011 05:22:28 +0000</pubDate>
 <dc:creator>quest</dc:creator>
 <guid isPermaLink="false">3 at http://quest.windwards.net</guid>
 <comments>http://quest.windwards.net/content/shell-scripting-patterns-errors-and-failure#comments</comments>
</item>
<item>
 <title>Shell scripting patterns: returning from functions</title>
 <link>http://quest.windwards.net/content/shell-scripting-patterns-returning-functions</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;
	One shortcoming of shell scripting is the inability to return anything of significance from a shell script function. Consider: get a function that returns the youngest file in a directory. The basic moving part in this is &lt;strong&gt;ls -tr /da/dir | tail -1&lt;/strong&gt;. Abstracting this to a function seem problematic, given that we cannot return a value. However, functions is very similar to external commands in bash, so you can do this:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
functions latest_file() {
  ls -tr &quot;$1&quot; | tail -1
}&lt;/pre&gt;&lt;p&gt;
	... and then simply invoke it thus:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
latest=$(latest_file /da/dir)&lt;/pre&gt;&lt;p&gt;
	From this point, we can write what effectively is a generator:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
function find_magic_scripts() {
    find $1 -type f -name &#039;*.sh&#039; | while read fname ; do
        grep -l &#039;magic word&#039; $fname || true
    done
}&lt;/pre&gt;&lt;p&gt;
	We can now use it as a source for a consumer:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
find_magic_scripts /da/dir | link_and_version&lt;/pre&gt;&lt;p&gt;
	These two processes will be run in parallel, which is good since they both take a little time. Of course, find_magic_scripts will still block as soon as it has output a file, but will restart as soon as link_and_version has read that line.&lt;/p&gt;
&lt;p&gt;
	However.&lt;/p&gt;
&lt;p&gt;
	There is an issue with this pattern: a sequence of pipes will have the error code for the last command, ignoring any previous failures. So, if /da/dir does not exist, link_and_version will simply get EOF and be happy. Unfortunately, there is no neat workaround that solves all problems. The best strategy is usually to introduce an explicit failure marker in the protocol over the pipe, something like:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
function foo() {
    {
        ...
    } || echo &quot;FAIL $?&quot;
}
foo | bar&lt;/pre&gt;&lt;p&gt;
	Or, where left side is an external command, simply:&lt;/p&gt;
&lt;pre class=&quot;brush: bash&quot;&gt;
{ find /may/not/exist -name &#039;*.sh&#039; || echo &quot;FAIL $?&quot; ; } | bar&lt;/pre&gt;&lt;p&gt;
	Now bar() can know that something went wrong and abort.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;field field-name-field-tags field-type-taxonomy-term-reference field-label-above&quot;&gt;&lt;div class=&quot;field-label&quot;&gt;Tags:&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/quest-blog&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;quest-blog&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item odd&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/shell-scripting&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;shell-scripting&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/software-development&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;software-development&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Tue, 28 Jun 2011 22:12:51 +0000</pubDate>
 <dc:creator>quest</dc:creator>
 <guid isPermaLink="false">1 at http://quest.windwards.net</guid>
 <comments>http://quest.windwards.net/content/shell-scripting-patterns-returning-functions#comments</comments>
</item>
<item>
 <title>Shell scripting patterns - a personal perspective</title>
 <link>http://quest.windwards.net/content/shell-scripting-patterns-personal-perspective</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;It is often said that no serious development project should ever use shell script.&lt;/p&gt;
&lt;p&gt;While it is certainly true that there are some serious shortcomings is the bash strain of shells, this is not to say that these shortcomings cannot be overcome. Like so much else in programming, it is mostly a matter of finding good patterns that contain those shortcomings.&lt;/p&gt;
&lt;p&gt;I want to write something on this matter, so I&#039;m planning a series of blog posts on important patterns that help in keeping bash shell scripts readable and maintainable while keeping a reasonable performance. With luck, they will have something for you as well.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;field field-name-field-tags field-type-taxonomy-term-reference field-label-above&quot;&gt;&lt;div class=&quot;field-label&quot;&gt;Tags:&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/quest-blog&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;quest-blog&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item odd&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/shell-scripting&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;shell-scripting&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;field-item even&quot; rel=&quot;dc:subject&quot;&gt;&lt;a href=&quot;/tags/software-development&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;software-development&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Sat, 25 Jun 2011 11:15:00 +0000</pubDate>
 <dc:creator>quest</dc:creator>
 <guid isPermaLink="false">8 at http://quest.windwards.net</guid>
 <comments>http://quest.windwards.net/content/shell-scripting-patterns-personal-perspective#comments</comments>
</item>
</channel>
</rss>
