{"id":20,"date":"2019-01-07T07:56:00","date_gmt":"2019-01-07T07:56:00","guid":{"rendered":""},"modified":"2019-04-25T13:42:20","modified_gmt":"2019-04-25T13:42:20","slug":"ansible-passing-arrays-to-bash-scripts","status":"publish","type":"post","link":"https:\/\/ntlx.org\/de\/2019\/01\/ansible-passing-arrays-to-bash-scripts.html","title":{"rendered":"Ansible: Passing arrays to BASH scripts"},"content":{"rendered":"<p>When using&nbsp;<a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Ansible<\/a>, it may become handy sooner or later to invoke a BASH script in one of you playbooks. Invoking a BASH script in Ansible can be done using a simple <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/modules\/shell_module.html\" target=\"_blank\" rel=\"noopener noreferrer\">shell task<\/a>:<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3\n4\n5\n6<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #bb0066; font-weight: bold;\">---<\/span>\n- hosts: 127.0.0.1\n  connection: local\n<span style=\"color: #0b5394;\">  tasks:\n      - name: ensure stuff is done\n        shell: .\/do_stuff.sh<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>This task will execute the bash script&nbsp;<i>do_stuff.sh<\/i>. Sometimes, it is also necessary to configure the behaviour of the BASH script you are executing. The simplest way to do so is passing environment variables to the bash script as done in the following example.<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3\n4\n5\n6\n7\n8<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #bb0066; font-weight: bold;\">---<\/span>\n- hosts: 127.0.0.1\n  connection: local\n  tasks:\n      - name: ensure custom stuff is done\n        shell: .\/do_stuff.sh\n<span style=\"color: #0b5394;\">        environment:\n            STUFF: some_stuff<\/span>\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>In the BASH script we can now work with the environment variable as usual:<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\n\n<span style=\"color: #003388;\">echo<\/span> <span style=\"color: #336699;\">$STUFF<\/span> &gt; \/tmp\/stuff.txt\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>If we now want to pass multiple values in environment variable as array to the BASH script, we have two different options. Either we pass the array as string, or we parse the array output of Ansible in the bash script.<\/p>\n<h3>Option 1: Pass array as string<\/h3>\n<p>The first option is to pass the multiple values as string instead of a YAML array. In the following example, we separate them by spaces, which results in a single environment variable&nbsp;<i>ARRAY&nbsp;<\/i>being set when executing the BASH script.<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3\n4\n5\n6\n7\n8<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #bb0066; font-weight: bold;\">---<\/span>\n- hosts: 127.0.0.1\n  connection: local\n  tasks:\n      - name: pass array as string\n        shell: .\/do_stuff_string.sh\n <span style=\"color: #0b5394;\">       environment:\n            ARRAY: one two three<\/span>\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>To handle those values as array in our BASH script, we simply surround the value of the environment variable with parentheses. Afterwards the ARRAY variable is a BASH array containing the values&nbsp;<i>one<\/i>,&nbsp;<i>two<\/i>, and&nbsp;<i>three.<\/i><\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3\n4\n5\n6\n7<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\n\n<span style=\"color: #336699;\">ARRAY<\/span>=(<span style=\"color: #336699;\">$ARRAY<\/span>)\n:&gt; \/tmp\/stuff_string.txt\n<span style=\"color: #008800; font-weight: bold;\">for <\/span>a in <span style=\"background-color: #fff0f0; color: #dd2200;\">\"${ARRAY[@]}\"<\/span>; <span style=\"color: #008800; font-weight: bold;\">do<\/span>\n<span style=\"color: #008800; font-weight: bold;\">    <\/span><span style=\"color: #003388;\">echo<\/span> <span style=\"color: #336699;\">$a<\/span> &gt;&gt; \/tmp\/stuff_string.txt\n<span style=\"color: #008800; font-weight: bold;\">done<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h3>Option 2: Parse array<\/h3>\n<div>The second option is much more readable in the Ansible playbook. We define the values as array in YAML:<\/div>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #bb0066; font-weight: bold;\">---<\/span>\n- hosts: 127.0.0.1\n  connection: local\n  tasks:\n      - name: pass array as array\n        shell: .\/do_stuff_array.sh\n<span style=\"color: #0b5394;\">        environment:\n            ARRAY:\n            - one\n            - two\n            - three<\/span>\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Unfortunately, this environment variable is still set as string, now containing a python string representation of the array:<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\">[<span style=\"background-color: #fff0f0; color: #dd2200;\">u'one'<\/span>, <span style=\"background-color: #fff0f0; color: #dd2200;\">u'two'<\/span>, <span style=\"background-color: #fff0f0; color: #dd2200;\">u'three'<\/span>]\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>To parse the array in the BASH script, the simplest way is to use python again, which is able to handle this value out of the box.<\/p>\n<div style=\"background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 16.25px;\">1\n2\n3\n4\n5\n6\n7<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 16.25px;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\n\n<span style=\"color: #336699;\">ARRAY<\/span>=(<span style=\"color: #008800; font-weight: bold;\">$(<\/span>python &lt;&lt;&lt; <span style=\"background-color: #fff0f0; color: #dd2200;\">\"print(' '.join($ARRAY))\"<\/span><span style=\"color: #008800; font-weight: bold;\">)<\/span>)\n:&gt; \/tmp\/stuff_array.txt\n<span style=\"color: #008800; font-weight: bold;\">for <\/span>a in <span style=\"background-color: #fff0f0; color: #dd2200;\">\"${ARRAY[@]}\"<\/span>; <span style=\"color: #008800; font-weight: bold;\">do<\/span>\n<span style=\"color: #008800; font-weight: bold;\">    <\/span><span style=\"color: #003388;\">echo<\/span> <span style=\"color: #336699;\">$a<\/span> &gt;&gt; \/tmp\/stuff_array.txt\n<span style=\"color: #008800; font-weight: bold;\">done<\/span>\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>With the python one-liner in line 3, ARRAY again is a BASH array with the values&nbsp;<i>one<\/i>,&nbsp;<i>two<\/i>, and&nbsp;<i>three<\/i>&nbsp;and can be processed further<i>.<\/i><\/p>\n<p>Please note that, to be able to get array elements with spaces passed by ansible, we need to change the array seperator as the following version of the script shows. Otherwise, bash would recognize every single word as separate element of the array:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"line-height: 125%; margin: 0;\">1\n2\n3\n4\n5\n6\n7<\/pre>\n<\/td>\n<td>\n<pre style=\"line-height: 125%; margin: 0;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\n<span style=\"color: #996633;\">IFS<\/span><span style=\"color: #333333;\">=<\/span><span style=\"background-color: #fff0f0;\">\n<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>We have seen 2 different options to pass an array from Ansible to a BASH script. Option 1, passing it as a simple string variable has some implications, for example an array containing values with spaces might result in a less readable YAML line. Option 2, defining the array as YAML array and parsing it in your BASH script with python makes the definition better readable and more solid, but adds a dependency to python for your BASH script.<\/p>\n<p>If simple one-word arguments need to be set for your script, option 1 might still be a good option as it is easier to handle in the BASH script and doesn&#8217;t include a dependency to python.<br \/>\nNevertheless, for more complex playbooks or values in the array, I recommend option 2 as the cleaner solution.<\/p>\n<p>n&#8217;<br \/>\n<span style=\"color: #996633;\">ARRAY<\/span><span style=\"color: #333333;\">=(<\/span> <span style=\"color: #008800; font-weight: bold;\">$(<\/span>python <span style=\"color: #333333;\">&lt;&lt;&lt;<\/span> <span style=\"background-color: #fff0f0;\">&#8220;print(&#8216;n&#8217;.join($ARRAY))&#8221;<\/span><span style=\"color: #008800; font-weight: bold;\">)<\/span> <span style=\"color: #333333;\">)<\/span><br \/>\n<span style=\"color: #007020;\">echo<\/span> <span style=\"background-color: #fff0f0;\">&#8220;${ARRAY[@]}&#8221;<\/span><br \/>\n<span style=\"color: #008800; font-weight: bold;\">for <\/span>a in <span style=\"background-color: #fff0f0;\">&#8220;${ARRAY[@]}&#8221;<\/span>; <span style=\"color: #008800; font-weight: bold;\">do<\/span><br \/>\n<span style=\"color: #008800; font-weight: bold;\">    <\/span><span style=\"color: #007020;\">echo<\/span> <span style=\"background-color: #fff0f0;\">&#8220;$a&#8221;<\/span><br \/>\n<span style=\"color: #008800; font-weight: bold;\">done<\/span><br \/>\nWe have seen 2 different options to pass an array from Ansible to a BASH script. Option 1, passing it as a simple string variable has some implications, for example an array containing values with spaces might result in a less readable YAML line. Option 2, defining the array as YAML array and parsing it in your BASH script with python makes the definition better readable and more solid, but adds a dependency to python for your BASH script.<\/p>\n<p>If simple one-word arguments need to be set for your script, option 1 might still be a good option as it is easier to handle in the BASH script and doesn&#8217;t include a dependency to python.<br \/>\nNevertheless, for more complex playbooks or values in the array, I recommend option 2 as the cleaner solution.<\/p>\n","protected":false},"excerpt":{"rendered":"When using&nbsp;Ansible, it may become handy sooner or later to invoke a BASH script in one of you playbooks. Invoking a BASH script in Ansible can be done using a simple shell task: 1 2 3 4 5 6 &#8212; &#8211; hosts: 127.0.0.1 connection: local tasks: &#8211; name: ensure stuff is done shell: .\/do_stuff.sh This&#8230; <a class=\"view-article\" href=\"https:\/\/ntlx.org\/de\/2019\/01\/ansible-passing-arrays-to-bash-scripts.html\">Artikel ansehen<\/a>","protected":false},"author":1,"featured_media":141,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/posts\/20"}],"collection":[{"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/comments?post=20"}],"version-history":[{"count":3,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/posts\/20\/revisions"}],"predecessor-version":[{"id":139,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/posts\/20\/revisions\/139"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/media\/141"}],"wp:attachment":[{"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/media?parent=20"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/categories?post=20"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ntlx.org\/de\/wp-json\/wp\/v2\/tags?post=20"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}