{"id":412,"date":"2016-01-25T11:46:22","date_gmt":"2016-01-25T10:46:22","guid":{"rendered":"https:\/\/blogs.gentoo.org\/mgorny\/?p=412"},"modified":"2016-02-17T18:20:45","modified_gmt":"2016-02-17T17:20:45","slug":"mangling-shell-options-in-ebuilds","status":"publish","type":"post","link":"https:\/\/blogs.gentoo.org\/mgorny\/2016\/01\/25\/mangling-shell-options-in-ebuilds\/","title":{"rendered":"Mangling shell options in ebuilds"},"content":{"rendered":"<p>A\u00a0long time ago eutils.eclass was gifted with a\u00a0set of terribly ugly functions to push\/pop various variables and\u00a0shell options. Those functions were written very badly, and\u00a0committed without any review. As a\u00a0result, a\u00a0number of eclasses and\u00a0ebuilds are now using that code without even understanding how bad it is.<\/p>\n<p>In\u00a0this post, I would like to shortly summarize how to properly and\u00a0reliably save states of shell options. While the\u00a0resulting code is a\u00a0little bit longer than use of e*_push and e*_pop functions, it is much more readable, does not abuse eval, does not abuse global variables and\u00a0is more reliable.<\/p>\n<p><!--more--><\/p>\n<h2>Preferable solution: subshell scope<\/h2>\n<p>Of course, the\u00a0preferable way of altering shell options is to do that in\u00a0a\u00a0subshell. This is the\u00a0only way that reliably isolates the\u00a0alterations from parent ebuild environment. However, subshells are rarely desired \u2014 so this is something you&#8217;d rather reuse if it&#8217;s already there, rather than introducing just for the\u00a0sake of shell option mangling.<\/p>\n<h2>Mangling shopt options<\/h2>\n<p>Most of the\u00a0\u2018new\u2019 bash options are mangled using <kbd>shopt<\/kbd> builtin. In\u00a0this case, the\u00a0<kbd>-s<\/kbd> and\u00a0<kbd>-u<\/kbd> switches are used to change the\u00a0option state, while the\u00a0<kbd>-p<\/kbd> option can be used to get the\u00a0current value. The\u00a0current value is output in\u00a0the\u00a0form of <kbd>shopt<\/kbd> command syntax that can be called directly to restore the\u00a0previous value.<\/p>\n<pre><code>my_function() {\r\n\tlocal prev_shopt=$(shopt -p nullglob)\r\n\t# prev_shopt='shopt -u nullglob' now\r\n\tshopt -s nullglob\r\n\t# ...\r\n\t${prev_shopt}\r\n}<\/code><\/pre>\n<h2>Mangling set options<\/h2>\n<p>The\u00a0options set using the\u00a0<kbd>set<\/kbd> builtin can be manipulated in a\u00a0similar way. While the\u00a0builtin support both short and\u00a0long options, I strongly recommend using long options for readability. In\u00a0fact, the\u00a0long option names can be used through <kbd>shopt<\/kbd> with the\u00a0additional <kbd>-o<\/kbd> parameter.<\/p>\n<pre><code>my_function() {\r\n\tlocal prev_shopt=$(shopt -p -o noglob)\r\n\t# prev_shopt='set +o noglob' now\r\n\tset -o noglob  # or shopt -s -o noglob\r\n\t# ...\r\n\t${prev_shopt}\r\n}<\/code><\/pre>\n<h2>Mangling umask<\/h2>\n<p>The\u00a0<kbd>umask<\/kbd> builtin returns the\u00a0current octal umask when called with no\u00a0parameters. Furthermore, the\u00a0<kbd>-p<\/kbd> parameter can be used to get full command for use alike <kbd>shopt -p<\/kbd> output.<\/p>\n<pre><code>my_function() {\r\n\tlocal prev_umask=$(umask)\r\n\t# prev_umask=0022 now\r\n\tumask 077\r\n\t# ...\r\n\tumask \"${prev_umask}\"\r\n}\r\n\r\nalternative_function() {\r\n\tlocal prev_umask=$(umask -p)\r\n\t# prev_umask='umask 0022' now\r\n\tumask 077\r\n\t# ...\r\n\t${prev_umask}\r\n}<\/code><\/pre>\n<h2>Mangling environment variables<\/h2>\n<p>The\u00a0eutils hackery went as far as to reinvent local variables using\u2026 global stacks. Not that it makes any sense. Whenever you want to change variable&#8217;s value, attributes or\u00a0just unset it temporarily, just use local variables. If the\u00a0change needs to apply to part of a\u00a0function, create a\u00a0sub-function and\u00a0put the\u00a0local variable inside it.<\/p>\n<p>While at\u00a0it, please remember that bash does not support local functions. Therefore, you need to namespace your functions to avoid collisions and\u00a0unset them after use.<\/p>\n<pre><code>my_function() {\r\n\t# unset FOO in local scope (this also prevents it from being exported)\r\n\tlocal FOO\r\n\t# 'localize' bar for modifications, preserving value\r\n\tlocal bar=\"${bar}\"\r\n\r\n\t#...\r\n\r\n\tmy_sub_func() {\r\n\t\t# export LC_ALL=POSIX in function scope\r\n\t\tlocal -x LC_ALL=POSIX\r\n\t\t#...\r\n\t}\r\n\tmy_sub_func\r\n\t# unset the function after use\r\n\tunset -f my_sub_func\r\n}<\/code><\/pre>\n<h2>Update: mangling shell options without a\u00a0single subshell<\/h2>\n<p><ins>(added on 2016-01-28)<\/ins><\/p>\n<p>izabera has brought it to my attention that the\u00a0<kbd>shopt<\/kbd> builtin supports <kbd>-q<\/kbd> option to suppress output and\u00a0uses exit statuses to return the\u00a0original flag state. This makes it possible to set and\u00a0unset the\u00a0flags without using a\u00a0single subshell or\u00a0executing returned commands.<\/p>\n<p>Since I do not expect most shell script writers to use such a\u00a0long replacement, I present it merely as a\u00a0curiosity.<\/p>\n<pre><code>my_setting_function() {\r\n\tshopt -q nullglob\r\n\tlocal prev_shopt=${?}\r\n\tshopt -s nullglob\r\n\r\n\t#...\r\n\r\n\t[[ ${prev_shopt} -eq 0 ]] || shopt -u nullglob\r\n}\r\n\r\nmy_unsetting_function() {\r\n\tshopt -q extquote\r\n\tlocal prev_shopt=${?}\r\n\tshopt -u extquote\r\n\r\n\t#...\r\n\r\n\t[[ ${prev_shopt} -eq 0 ]] &amp;&amp; shopt -s extquote\r\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A\u00a0long time ago eutils.eclass was gifted with a\u00a0set of terribly ugly functions to push\/pop various variables and\u00a0shell options. Those functions were written very badly, and\u00a0committed without any review. As a\u00a0result, a\u00a0number of eclasses and\u00a0ebuilds are now using that code without even understanding how bad it is. In\u00a0this post, I would like to shortly summarize how &hellip; <a href=\"https:\/\/blogs.gentoo.org\/mgorny\/2016\/01\/25\/mangling-shell-options-in-ebuilds\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Mangling shell options in ebuilds&#8221;<\/span><\/a><\/p>\n","protected":false},"author":137,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[3],"tags":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/posts\/412"}],"collection":[{"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/users\/137"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/comments?post=412"}],"version-history":[{"count":6,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/posts\/412\/revisions"}],"predecessor-version":[{"id":435,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/posts\/412\/revisions\/435"}],"wp:attachment":[{"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/media?parent=412"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/categories?post=412"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/mgorny\/wp-json\/wp\/v2\/tags?post=412"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}