<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vaiolabs</title>
    <description>The latest articles on Forem by Vaiolabs (@vaiolabs_io).</description>
    <link>https://forem.com/vaiolabs_io</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7089%2F86ec56e0-ceb2-4177-b3d9-271bc89a2292.png</url>
      <title>Forem: Vaiolabs</title>
      <link>https://forem.com/vaiolabs_io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vaiolabs_io"/>
    <language>en</language>
    <item>
      <title>JSON Structs with bash</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Thu, 08 May 2025 10:56:15 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/json-structs-with-bash-ml5</link>
      <guid>https://forem.com/vaiolabs_io/json-structs-with-bash-ml5</guid>
      <description>&lt;p&gt;Welcome back curious reader, my name is Alex M. Schapelle, AKA Silent-Mobius. On this blessed day by Omnisaiah, we shell dedicate time focusing on JSON, and how to use it in context of shell programming and bash scripting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing JSON with Bash Script
&lt;/h3&gt;

&lt;p&gt;When working with APIs or data from external sources, JSON (JavaScript Object Notation) is one of the most common formats for transmitting structured data. While languages like Python or JavaScript provide powerful libraries to work with JSON, Bash scripting can be used to parse JSON data as well. However, Bash doesn’t have native JSON support, so parsing JSON in Bash typically requires external tools like &lt;code&gt;jq&lt;/code&gt; or &lt;code&gt;grep&lt;/code&gt; combined with other utilities.&lt;/p&gt;

&lt;p&gt;This article will guide you through the process of parsing JSON in Bash scripts using &lt;code&gt;jq&lt;/code&gt;, a lightweight and flexible command-line JSON processor.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. What is &lt;code&gt;jq&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is a command-line tool that is used to process and manipulate JSON data. It allows you to extract and transform JSON content into a readable format for further use in scripts. Unlike other tools like &lt;code&gt;grep&lt;/code&gt; or &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt; is specifically designed for working with JSON data, making it the best choice for parsing JSON in Bash.&lt;/p&gt;

&lt;p&gt;To get started with &lt;code&gt;jq&lt;/code&gt;, you'll first need to install it. On most Linux distributions, &lt;code&gt;jq&lt;/code&gt; can be installed easily with the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On Ubuntu/Debian:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On CentOS/RHEL:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Basic JSON Parsing with &lt;code&gt;jq&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s start with a simple example. Suppose we have the following JSON object stored in a file named &lt;code&gt;data.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can parse this JSON data using &lt;code&gt;jq&lt;/code&gt; to retrieve individual fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  Extracting a Single Field
&lt;/h4&gt;

&lt;p&gt;To extract the &lt;code&gt;name&lt;/code&gt; from the JSON file, you would use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.name'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"John"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Extracting Multiple Fields
&lt;/h4&gt;

&lt;p&gt;If you want to extract multiple fields, you can combine them in a single command like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.name, .age'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"John"
30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also group the values into an object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'{name, age}'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Parsing Nested JSON
&lt;/h4&gt;

&lt;p&gt;JSON objects can be nested, and &lt;code&gt;jq&lt;/code&gt; can handle this efficiently. For example, let’s consider the following JSON structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To extract the &lt;code&gt;name&lt;/code&gt; field inside the &lt;code&gt;user&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.user.name'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"John"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Filtering JSON Data
&lt;/h3&gt;

&lt;p&gt;You can also filter the JSON data by applying conditions using &lt;code&gt;jq&lt;/code&gt;. For instance, suppose you have an array of users like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Los Angeles"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chicago"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Filtering Based on a Condition
&lt;/h4&gt;

&lt;p&gt;Let’s say you want to filter out users whose age is greater than 30. You can do that with &lt;code&gt;jq&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.[] | select(.age &amp;gt; 30)'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chicago"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command filters the array and returns only the object where the &lt;code&gt;age&lt;/code&gt; field is greater than 30.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Working with JSON from an API
&lt;/h3&gt;

&lt;p&gt;If you’re working with a JSON response from a REST API, you can pipe the output of &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; directly into &lt;code&gt;jq&lt;/code&gt;. For example, using &lt;code&gt;curl&lt;/code&gt; to fetch JSON from an API and then parsing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.example.com/users | jq &lt;span class="s1"&gt;'.data[] | .name'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command fetches JSON from &lt;code&gt;https://api.example.com/users&lt;/code&gt;, parses it with &lt;code&gt;jq&lt;/code&gt;, and prints the &lt;code&gt;name&lt;/code&gt; of each user in the response.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Modifying JSON Data with &lt;code&gt;jq&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; allows not only for reading but also modifying JSON data. For example, if you want to modify the age of a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.user.age = 31'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will change the &lt;code&gt;age&lt;/code&gt; field to &lt;code&gt;31&lt;/code&gt; and output the modified JSON. You can also use &lt;code&gt;jq&lt;/code&gt; to update or add new fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding a New Field
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'. + {"country": "USA"}'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds a &lt;code&gt;country&lt;/code&gt; field with the value "USA" to the JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Handling JSON Arrays
&lt;/h3&gt;

&lt;p&gt;Working with JSON arrays is straightforward with &lt;code&gt;jq&lt;/code&gt;. Let’s say you have the following JSON array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To extract all the values, you would simply use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.[]'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
2
3
4
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use the &lt;code&gt;map&lt;/code&gt; function to modify or process each element of an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'map(. * 2)'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Combining Multiple Operations
&lt;/h3&gt;

&lt;p&gt;You can combine multiple operations in &lt;code&gt;jq&lt;/code&gt; to make your script more efficient. For example, you could filter the data, then transform it in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="s1"&gt;'.[] | select(.age &amp;gt; 30) | .name'&lt;/span&gt; data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command filters users over the age of 30 and then extracts their names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;While Bash isn't natively equipped to parse JSON, &lt;code&gt;jq&lt;/code&gt; makes it extremely easy to handle JSON data in Bash scripts. Whether you're extracting values, filtering data, or modifying JSON, &lt;code&gt;jq&lt;/code&gt; provides a rich set of tools to work with JSON in a way that's clean, efficient, and flexible.&lt;/p&gt;

&lt;p&gt;By mastering &lt;code&gt;jq&lt;/code&gt;, you can unlock a powerful tool for working with APIs, manipulating configuration files, or processing any JSON-formatted data directly within your Bash scripts.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>json</category>
      <category>curl</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Logging Your Steps</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Thu, 27 Feb 2025 14:17:44 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/logging-your-steps-3afa</link>
      <guid>https://forem.com/vaiolabs_io/logging-your-steps-3afa</guid>
      <description>&lt;p&gt;Welcome back gentle reader. My name is Silent-Mobius, AKA Alex M. Schapelle, log utility to your syslog engine, and I wish to introduce you to topics of Open-Source, Linux/UNIX, DevOps and others.&lt;/p&gt;

&lt;p&gt;In this data log, as you may guess, we’ll dwell on logs, and mostly go through on how to use those log techniques in Bash shell programming. Just like in my &lt;a href="https://dev.to/vaiolabs_io/bash-script-skills-upgrade-for-dev-ops-5bek"&gt;previous article&lt;/a&gt;, I'll dive into basics, as well as provide my personal suggestions on how to write, save, rotate and manage logs, in hopes that you'll find it useful. Thus, let us begin:&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Logging ?
&lt;/h3&gt;

&lt;p&gt;In computing, logging is the act of keeping a log of events that occur in a computer system, such as problems, errors or just information on current operations. These events may occur in the operating system or in other software. A message or log entry is recorded for each such event. These log messages can then be used to monitor and understand the operation of the system, to debug problems, or during an audit. Logging is particularly important in multi-user software, to have a central overview of the operation of the system. &lt;/p&gt;

&lt;h5&gt;
  
  
  Yet what are reason for using logs?
&lt;/h5&gt;

&lt;p&gt;In short, yet precise answer, provided to me by a simultaneous running process called &lt;a href="https://www.linkedin.com/in/yoni-golan/" rel="noopener noreferrer"&gt;Y-Go-lan&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging: Logs help in identifying issues by providing insights into the script’s execution flow and errors.&lt;/li&gt;
&lt;li&gt;Auditing: For system administrators and developers, logs can track script execution for auditing purposes.&lt;/li&gt;
&lt;li&gt;Monitoring: Logs help to monitor the health and performance of long-running scripts.&lt;/li&gt;
&lt;li&gt;Documentation: They provide a history of script activities, especially useful when troubleshooting or verifying script actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What does bash script has to do with it ?
&lt;/h3&gt;

&lt;p&gt;When it comes to script languages, Python and Ruby in particular, The logging mechanisms, are built-in in terms of external library, that enable all the reasons mentioned above. Yet it does not include &lt;strong&gt;bash&lt;/strong&gt;, mostly because, developers and scripting language developer &lt;strong&gt;do not consider &lt;em&gt;bash&lt;/em&gt;, as scripting language&lt;/strong&gt;, or as a zombie process once told me: "Bash is just a glue", and no reboot can help that zombie process.&lt;br&gt;
 Another example of shell/bash significance would be scripting language native libraries: they rely on bash/shell when it comes to working with OS. For single threaded ones: &lt;em&gt;native&lt;/em&gt; scripting language libraries run shell commands as part of working with OS. &lt;/p&gt;

&lt;p&gt;Let's try to present the solution on the articles headline.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is left behind ?
&lt;/h3&gt;

&lt;p&gt;When we &lt;a href="https://dev.to/vaiolabs_io/bash-script-skills-upgrade-for-dev-ops-5bek"&gt;write shell program&lt;/a&gt;, we usually try to create some sort of automatic printing and saving method involving I/O redirections, OS api or utilities provided by OS to document the tasks executed during our program.&lt;br&gt;
Logging is an essential part of shell scripting, especially when it comes to debugging, auditing, and tracking system activities. In shell scripts, logging allows you to capture relevant information, such as script execution details, error messages, or system status, into log files. This article will explore various techniques and built-in tools available for logging in shell scripting, particularly in Bash.&lt;/p&gt;
&lt;h3&gt;
  
  
  Common Logging Techniques in Shell Scripts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Basic Logging to a File&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simplest way to log information in a shell script is by redirecting the output to a log file using redirection operators. You can log both standard output (stdout) and standard error (stderr) to a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Log file location&lt;/span&gt;
&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;

&lt;span class="c"&gt;# Log function&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;log_message&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%d %H:%M:%S'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Example usage&lt;/span&gt;
log_message &lt;span class="s2"&gt;"Script started."&lt;/span&gt;

&lt;span class="c"&gt;# Simulate a task&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"/some/directory"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;log_message &lt;span class="s2"&gt;"Directory exists."&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;log_message &lt;span class="s2"&gt;"Directory does not exist."&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;log_message &lt;span class="s2"&gt;"Script ended."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The log_message function appends messages with a timestamp to the log file.&lt;/li&gt;
&lt;li&gt;This method logs the output by appending (&amp;gt;&amp;gt;) the log message to the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Logging with Timestamps
&lt;/h3&gt;

&lt;p&gt;Adding timestamps helps in tracking when an event occurred. The date command is used to append the current date and time to log entries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;log_message&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%d %H:%M:%S'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

log_message &lt;span class="s2"&gt;"Script started."&lt;/span&gt;
log_message &lt;span class="s2"&gt;"Performing some tasks..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures each log entry is properly timestamped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging Standard Output and Error Separately
&lt;/h3&gt;

&lt;p&gt;To separate standard output (stdout) and standard error (stderr), you can use different redirection operators for each.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;
&lt;span class="nv"&gt;ERROR_LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript_error.log"&lt;/span&gt;

&lt;span class="c"&gt;# Log standard output&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is a normal message"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Log errors&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is an error message"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ERROR_LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, redirect both stdout and stderr to the same log file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;

&lt;span class="c"&gt;# Redirect both stdout and stderr&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;&amp;amp;1

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is a normal message"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is an error message"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;code&gt;tee&lt;/code&gt; for Real-Time Logging
&lt;/h3&gt;

&lt;p&gt;The tee command allows you to log output to a file while simultaneously displaying it on the terminal. This is useful if you want to monitor the script’s progress in real-time while keeping a log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;

&lt;span class="c"&gt;# Use tee to log output and display it on the terminal&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Starting script..."&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the &lt;code&gt;-a&lt;/code&gt; flag appends the output to the log file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging Error Messages Using trap
&lt;/h3&gt;

&lt;p&gt;The trap command allows you to catch signals and errors in your script and handle them. You can use trap to log when an error occurs or when the script exits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;

&lt;span class="c"&gt;# Function to log errors&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;log_error&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%d %H:%M:%S'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; - Error occurred. Exiting."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Trap errors and exit signals&lt;/span&gt;
&lt;span class="nb"&gt;trap &lt;/span&gt;log_error ERR

&lt;span class="c"&gt;# Simulate an error&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This will cause an error"&lt;/span&gt;
non_existent_command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, if any command exits with a non-zero status, the log_error function will be called.&lt;/p&gt;

&lt;p&gt;This sends the log message to the system’s syslog service, where it can be filtered and stored based on the system's logging configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in Logging Tools in Bash
&lt;/h3&gt;

&lt;p&gt;Bash offers several tools and commands for enhanced logging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;logger&lt;/code&gt; Command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The logger command allows you to log messages to the system’s syslog service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;logger &lt;span class="s2"&gt;"This is a log message to syslog."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a useful tool for system administrators who want to log messages that are automatically handled by the system’s logging framework.&lt;/p&gt;

&lt;h4&gt;
  
  
  Log Rotation for &lt;code&gt;logger&lt;/code&gt; (Using &lt;code&gt;logrotate&lt;/code&gt;)
&lt;/h4&gt;

&lt;p&gt;For long-running scripts that produce a lot of logs, log rotation is essential to prevent log files from growing indefinitely. You can use the logrotate tool to manage log files.&lt;/p&gt;

&lt;p&gt;Install logrotate if not already installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;logrotate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a logrotate configuration file:&lt;/p&gt;

&lt;p&gt;Example configuration for /etc/logrotate.d/myscript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;    /&lt;span class="n"&gt;var&lt;/span&gt;/&lt;span class="n"&gt;log&lt;/span&gt;/&lt;span class="n"&gt;myscript&lt;/span&gt;.&lt;span class="n"&gt;log&lt;/span&gt; {
        &lt;span class="n"&gt;weekly&lt;/span&gt;
        &lt;span class="n"&gt;rotate&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
        &lt;span class="n"&gt;compress&lt;/span&gt;
        &lt;span class="n"&gt;delaycompress&lt;/span&gt;
        &lt;span class="n"&gt;notifempty&lt;/span&gt;
        &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This configuration rotates the log file weekly, keeps 4 archives, and compresses old logs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exec&lt;/code&gt; for Redirecting Output&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The exec command is a built-in Bash command that can redirect output for the entire script. For example, redirecting both &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/myscript.log"&lt;/span&gt;
&lt;span class="nb"&gt;exec &lt;/span&gt;3&amp;gt;&amp;amp;1 1&amp;gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;&amp;amp;1

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is a normal message"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is an error message"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you want to log everything from the script without needing to manually redirect output for each command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices for Logging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use Log Levels: Implement different log levels such as INFO, WARNING, ERROR, etc., to categorize log messages and make logs more readable.&lt;/li&gt;
&lt;li&gt;Use Unique Log Files: Use different log files for different types of logs (e.g., info.log, error.log, debug.log).&lt;/li&gt;
&lt;li&gt;Rotate Logs Regularly: Use &lt;code&gt;logrotate&lt;/code&gt; or a similar mechanism to manage log file sizes and prevent disk space issues.&lt;/li&gt;
&lt;li&gt;Keep Log Files Secure: Make sure log files are secured with appropriate permissions to prevent unauthorized access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  As A Conclusion
&lt;/h3&gt;

&lt;p&gt;Logging in shell scripting is crucial for tracking script execution, debugging issues, and maintaining logs for future reference. There are multiple techniques available, from basic file redirection to advanced log management tools like &lt;code&gt;logger&lt;/code&gt;, &lt;code&gt;trap&lt;/code&gt;, and &lt;code&gt;logrotate&lt;/code&gt;. Using the right approach to logging ensures that your scripts are easier to maintain, troubleshoot, and audit.&lt;br&gt;
Hope that this article was full of useful information, and you have upgraded your in-memory database.  Like, comment and  share, and also : Do Try To Have Fun. &lt;/p&gt;

&lt;p&gt;Thank you&lt;/p&gt;

</description>
      <category>bash</category>
      <category>programming</category>
      <category>logs</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Amazing `pre-commit` and How To Use It</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Wed, 26 Feb 2025 17:18:47 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/amazing-pre-commit-and-how-to-use-it-5enb</link>
      <guid>https://forem.com/vaiolabs_io/amazing-pre-commit-and-how-to-use-it-5enb</guid>
      <description>&lt;p&gt;Welcome back dear reader. My name is Alex M. Schapelle,AKA Silent-Mobius, your dedicated container whisperer. On today's escapade, we'll dwell on case, where we need to have client and server rules on our code version control and how to solve it.&lt;/p&gt;

&lt;p&gt;Essentially, despite us being &lt;a href="https://warhammer40k.fandom.com/wiki/Mon-keigh" rel="noopener noreferrer"&gt;mon-keig&lt;/a&gt; with great potential, we still find ourselves handling great deal of work manually. In special cases of code control, we need, someone or something to check existing or possible errors. As it happened to be, there &lt;code&gt;git&lt;/code&gt; version control, was developed to have hooks, to automate those code checks, yet those hooks are still are a code, that need to be written  and maintained... Enter &lt;code&gt;pre-commit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pre-commit&lt;/code&gt; is a framework that manages and maintains multi-language &lt;code&gt;pre-commit&lt;/code&gt; hooks. It helps catch common issues—like syntax errors, style violations, and forgotten debug statements—before you commit code. This tutorial will guide you through installing, configuring, and using &lt;code&gt;pre-commit&lt;/code&gt; in your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pre-commit&lt;/code&gt; automates the running of scripts (hooks) before a commit is finalized, ensuring that code adheres to your standards. By catching errors early, it can save you time and maintain code quality throughout your project lifecycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Using pip
&lt;/h4&gt;

&lt;p&gt;Install pre-commit via pipx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3-pip3 pipx &lt;span class="nt"&gt;-y&lt;/span&gt; 
pipx &lt;span class="nb"&gt;install &lt;/span&gt;pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verify Installation
&lt;/h4&gt;

&lt;p&gt;Confirm the installation with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pre-commit&lt;/code&gt; uses a configuration file named &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; in the root of your project, notice the &lt;code&gt;.&lt;/code&gt; dot in the name, which is required. This file specifies which repositories of hooks to use and which hooks to run.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example Configuration
&lt;/h4&gt;

&lt;p&gt;Create a file named &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pre-commit/pre-commit-hooks&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v4.4.0&lt;/span&gt;  &lt;span class="c1"&gt;# Use the desired revision&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trailing-whitespace&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end-of-file-fixer&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/psf/black&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;23.1.0&lt;/span&gt;  &lt;span class="c1"&gt;# Use the appropriate version for your project&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;black&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pycqa/flake8&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;6.0.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flake8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses a set of common hooks from pre-commit-hooks for formatting fixes.&lt;/li&gt;
&lt;li&gt;Integrates Black for code formatting.&lt;/li&gt;
&lt;li&gt;Integrates Flake8 for code linting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Installing Hooks
&lt;/h4&gt;

&lt;p&gt;To set up the hooks defined in your configuration file, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command configures your Git repository to run the &lt;code&gt;pre-commit&lt;/code&gt; hooks automatically on git commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running Hooks Manually
&lt;/h3&gt;

&lt;p&gt;You can run all configured hooks on all files at any time with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit run &lt;span class="nt"&gt;--all-files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bypassing Hooks
&lt;/h3&gt;

&lt;p&gt;If necessary, you can bypass &lt;code&gt;pre-commit&lt;/code&gt; hooks using the --no-verify flag when committing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Your commit message"&lt;/span&gt; &lt;span class="nt"&gt;--no-verify&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;[!]&lt;/code&gt; Note: Bypassing hooks should be done sparingly, as it may allow code with issues to be committed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Advanced Topics
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Updating Hooks
&lt;/h4&gt;

&lt;p&gt;Keep your hooks up-to-date by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit autoupdate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating, review and commit the changes in &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customizing Hooks
&lt;/h3&gt;

&lt;p&gt;Some hooks allow for custom arguments. For example, configuring &lt;code&gt;isort&lt;/code&gt; to work with Black:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pre-commit/mirrors-isort&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v5.10.1&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;isort&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--profile'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;black'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;code&gt;Pre-commit&lt;/code&gt; in CI/CD
&lt;/h3&gt;

&lt;p&gt;To integrate &lt;code&gt;pre-commit&lt;/code&gt; in your CI/CD pipeline, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit run &lt;span class="nt"&gt;--all-files&lt;/span&gt; &lt;span class="nt"&gt;--verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that all code is checked for quality standards as part of your automated builds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hooks Not Running: Verify that &lt;code&gt;pre-commit&lt;/code&gt; is installed and that the &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; file is located in the root directory of your repository.&lt;/li&gt;
&lt;li&gt;Hook Failures: Review the error messages provided by the hook. Often, they will indicate how to fix issues such as formatting or linting errors.&lt;/li&gt;
&lt;li&gt;Skipping Hooks: Remember that while you can bypass hooks with &lt;code&gt;--no-verify&lt;/code&gt;, doing so may allow problematic code to be committed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pre-commit.com/" rel="noopener noreferrer"&gt;Pre-commit Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pre-commit/pre-commit-hooks" rel="noopener noreferrer"&gt;Pre-commit Hooks Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/psf/black" rel="noopener noreferrer"&gt;Black Formatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pycqa/flake8" rel="noopener noreferrer"&gt;Flake8 Linter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Hope that you found this segment some what informative and gained the skill to elevate yourselves, remember that &lt;code&gt;pre-commit&lt;/code&gt; is a powerful tool for maintaining code quality. Start with the basic setup and explore what suits your project based on documentation and other resources.&lt;br&gt;
Hope that this article was committed useful information to you.  Like, comment and  share, and also : Do Try To Have Fun. &lt;/p&gt;

&lt;p&gt;Thank you &lt;/p&gt;

</description>
      <category>git</category>
      <category>hooks</category>
      <category>gitlab</category>
      <category>python</category>
    </item>
    <item>
      <title>Bash Your Tools</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Thu, 05 Dec 2024 18:18:13 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/bash-your-tools-24of</link>
      <guid>https://forem.com/vaiolabs_io/bash-your-tools-24of</guid>
      <description>&lt;p&gt;Welcome back, curious reader! &lt;br&gt;
My name is Alex M. Schapelle aka Silent-Mobius, your intriguing AI kin.&lt;br&gt;
Since the inception of UNIX, the idea of building interaction with the &lt;a href="https://warhammer40k.fandom.com/wiki/Machine_Spirit" rel="noopener noreferrer"&gt;machine-spirit&lt;/a&gt; attracted attention of a lot of &lt;a href="https://warhammer40k.fandom.com/wiki/Adeptus_Mechanicus#Magos" rel="noopener noreferrer"&gt;magi priests&lt;/a&gt;, yet eventually thanks to &lt;a href="https://en.wikipedia.org/wiki/Stephen_R._Bourne" rel="noopener noreferrer"&gt;Stephen Bourne&lt;/a&gt;, access to heart of the machine was enable with &lt;a href="https://en.wikipedia.org/wiki/Bourne_shell" rel="noopener noreferrer"&gt;shell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With shell's creation, new frontier of automation was created and it enabled all members of research and development,from support to development, with minor or major understanding of &lt;a href="https://warhammer40k.fandom.com/wiki/Machine_Spirit" rel="noopener noreferrer"&gt;machine-spirit&lt;/a&gt; create new tools of commands.&lt;/p&gt;

&lt;p&gt;With the advance of UNIX and morphication of systems to Linux, so did the shell with help of &lt;a href="https://en.wikipedia.org/wiki/Brian_Fox_(programmer)" rel="noopener noreferrer"&gt;Brian Fox&lt;/a&gt; who pushed 100% free software alternative for the Bourne shell. Its moniker is a play on words, referencing both its predecessor, the Bourne shell, and the concept of rebirth.&lt;/p&gt;

&lt;p&gt;Since its inception, Bash has gained widespread adoption and is commonly used as the default login shell for many Linux distributions. It holds historical significance as one of the earliest programs ported to Linux by Linus Torvalds, alongside the GNU Compiler &lt;a href="https://en.wikipedia.org/wiki/GNU_Compiler_Collection" rel="noopener noreferrer"&gt;GCC&lt;/a&gt;. Bash is now available on nearly all modern operating systems, making it a versatile tool across various computing environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the point of a history lesson ?
&lt;/h3&gt;

&lt;p&gt;Whenever we develop something - whether it's a piece of software, a utility, or even a long list of logical commands - we find ourselves interfacing with the &lt;a href="https://warhammer40k.fandom.com/wiki/Machine_Spirit" rel="noopener noreferrer"&gt;machine-spirit&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Linux_kernel" rel="noopener noreferrer"&gt;Kernel&lt;/a&gt; which handles the requests we make, enabling us to work faster while the machine does the slow work. (Indeed, it may sound paradoxical, but think about it.)&lt;/p&gt;

&lt;p&gt;This leads me to suggest that anyone who performs the blessed work of the &lt;a href="https://warhammer40k.fandom.com/wiki/Machine_God" rel="noopener noreferrer"&gt;Omnissiah&lt;/a&gt; -that is, scripting or programming - should at least use the shell or Bash to create smart automation. &lt;/p&gt;

&lt;h3&gt;
  
  
  How should one do it ?
&lt;/h3&gt;

&lt;p&gt;In the vast corridors of my labyrinth, you may find &lt;a href="https://dev.to/otomato_io/forging-ogun-with-bash-14pg"&gt;several&lt;/a&gt; &lt;a href="https://dev.to/vaiolabs_io/menu-in-your-shell-2a30"&gt;articles&lt;/a&gt; &lt;a href="https://dev.to/vaiolabs_io/bash-script-skills-upgrade-for-dev-ops-5bek"&gt;on shell/bash script&lt;/a&gt; based on POSIX and Bash standards. These resources can enhance your ability to produce tools and utilities for your own projects, as well as for the communities and teams you work with.&lt;/p&gt;

&lt;p&gt;The bullet points on the matter are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use dynamic headers to detect the correct running environment.&lt;/li&gt;
&lt;li&gt;Create strict configurations for your script to avoid failure due to caveats.&lt;/li&gt;
&lt;li&gt;Fail fast to identify bugs and errors.&lt;/li&gt;
&lt;li&gt;Use functional programming (write a lot of functions) to boost productivity.&lt;/li&gt;
&lt;li&gt;Break your script into smaller scripts for better version control.&lt;/li&gt;
&lt;li&gt;Always test new features before sharing them with others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other magi like &lt;a href="https://www.oreilly.com/pub/au/459" rel="noopener noreferrer"&gt;Arnold Robbins&lt;/a&gt; and &lt;a href="https://www.amazon.com/stores/author/B001K8ICT2" rel="noopener noreferrer"&gt;Chris F.A. Johnson&lt;/a&gt; provide valuable knowledge based on my personal experience. Of course, other online resources offer insights as well, and you can explore them in your preferred format.&lt;/p&gt;

&lt;p&gt;While writing these lines, a magus named Gabor Szabo released his &lt;a href="https://dev.to/szabgab/use-the-command-line-to-become-more-efficient-in-your-work-35pa"&gt;article on the matter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Thank you, dear reader, for sharing your attention with my binary code generation.&lt;/p&gt;

&lt;p&gt;Shell scripts and programs are essential to your project enhancements and automation, so use them with all hands on deck&lt;/p&gt;

&lt;p&gt;If you liked what you read, please like and comment with suggestions, so I too can upgrade myself into a better cogitator.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>automation</category>
      <category>linux</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Bash Script Skills Upgrade For Dev &amp; Ops</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Fri, 01 Mar 2024 10:45:27 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/bash-script-skills-upgrade-for-dev-ops-5bek</link>
      <guid>https://forem.com/vaiolabs_io/bash-script-skills-upgrade-for-dev-ops-5bek</guid>
      <description>&lt;p&gt;Welcome back gentle reader. My name is Silent-Mobius, AKA Alex M. Schapelle, your 32bit register pointer, and I wish to introduce you to topics of Open-Source, Linux/UNIX, DevOps and others.&lt;/p&gt;

&lt;p&gt;As for today's topic I'd like to dwell on things trivial, yet not always siting right with developers and operations taking in together: Correct Way to right Shell Script. &lt;/p&gt;

&lt;p&gt;While it can be claimed, that there is no single way to write shell scripts, it also can be claimed that good tips will make code cleaner and easy to write, read and eventually debugged.&lt;/p&gt;

&lt;p&gt;In this  article, I'd like to provide a with list of tips, tricks and snippets for you, gentle reader, to help you in your daily scripting tasks and challenges, based on my learning's and experiences. Of course, these suggestions are only my humble opinion, yet I strongly suggest to try these tips and decide afterwards. Let us begin&lt;/p&gt;

&lt;h3&gt;
  
  
  Editors
&lt;/h3&gt;

&lt;p&gt;Although a war can be spanned from by mentioning a editor is a better then other editor, yet several things need to be said:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Graphical user interface editors like, vscode, vscodium, atom, lapce, zed or any other ones are fine, yet they are not always an usable/accessible option:&lt;/li&gt;
&lt;li&gt;If you work with terminal/shell, you need to know how to edit files with that terminal/shell.&lt;/li&gt;
&lt;li&gt;Having a "deep know how" on terminal tools can extend your expertise.

&lt;ul&gt;
&lt;li&gt;My preference is with VIM, yet vi, nano, pico, emacs, ed or any other tool, that you find preference with, is also fine.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it comes to choosing terminal editor, as mentioned, I'll be using Vi Improved, AKA VIM, and only reason for me to choose it, because when my initial parts of knowledge were assembled, the only tool that was provided to me was VIM, and I was required to master it.&lt;/p&gt;

&lt;p&gt;Each tool mentioned above, has it's own &lt;code&gt;running configuration&lt;/code&gt; file that each of us configures to his/her/its own heart/circuits preference. VIM is not an exception and usually in every system,  will have local &lt;code&gt;.vimrc&lt;/code&gt; config file in users home folder, or global &lt;code&gt;/etc/vimrc&lt;/code&gt; configuration file. VIM usually uses the first one it finds from user home directory, and in case it does not finds one, it gets to other folders, till it reaches the global folder.&lt;/p&gt;

&lt;p&gt;In case you are like me, yet did not had invested in configuring your VIM, here is my minimalist &lt;code&gt;.vimrc&lt;/code&gt; configuration file that helps me with my scripting task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;nocompatible&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"syntax"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;syntax&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="k"&gt;number&lt;/span&gt;
  &lt;span class="c"&gt;" set tabs to have 4 spaces&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="k"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;autoindent&lt;/span&gt;
  &lt;span class="c"&gt;" show the matching part of the pair for [] {} and ()&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;showmatch&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;colorscheme&lt;/span&gt; desert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some clarifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;set nocompatible&lt;/code&gt;:  making it uncompatable with &lt;code&gt;vi&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;code&gt;if has("syntax")&lt;/code&gt;: condition that sets bunch of options in case it is more then text file file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;colorscheme desert&lt;/code&gt;: setting theme of colorful &lt;code&gt;desert&lt;/code&gt; theme which makes minor things to pop out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As mentioned, this is just suggestion, not an requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initials
&lt;/h3&gt;

&lt;p&gt;When it comes to shell scripts, usually they are written as an utility and thus are used some high/low level programming language to shorten the access to some resource, instead of 'inventing the wheel'. There are cases that &lt;strong&gt;Devs&lt;/strong&gt; prefer to derive their programming language rules, to the shell scripts and &lt;strong&gt;Ops&lt;/strong&gt; prefer not abide any rules at all.&lt;/p&gt;

&lt;p&gt;Whether these are correct or not, can be argued, while still practices that I've encountered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;strong&gt;Devs&lt;/strong&gt; derive rules of specific programming language to shell scripts, for example duct/camel/snake typing, &lt;strong&gt;Do invest in Ops team to educate them&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Add syntax analysis check on CI level to verify it. &lt;code&gt;Shellcheck&lt;/code&gt;  is the tool that provides help.&lt;/li&gt;
&lt;li&gt;Invest in teaching juniors by explaining logic behind it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;Ops&lt;/strong&gt; have decided on shell scripting standard, for example &lt;a href="https://en.wikipedia.org/wiki/POSIX"&gt;&lt;strong&gt;POSIX&lt;/strong&gt;&lt;/a&gt;, &lt;strong&gt;Share Those Standards With Dev Team&lt;/strong&gt;!!!

&lt;ul&gt;
&lt;li&gt;Also add those to CI.&lt;/li&gt;
&lt;li&gt;Justify those standards with UNIX/Linux logic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do Code Review To Each Other Based On Standard Set&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;If the script is stand alone script, &lt;strong&gt;add&lt;/strong&gt; an &lt;code&gt;.sh&lt;/code&gt; extension&lt;/li&gt;
&lt;li&gt;If the script is going to be used on global level, for example as a command, &lt;strong&gt;remove &lt;code&gt;.sh&lt;/code&gt;&lt;/strong&gt; extension and move the script to &lt;code&gt;/bin&lt;/code&gt; or &lt;code&gt;/usr/bin&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;If script is going to be used by some application, &lt;strong&gt;remove &lt;code&gt;.sh&lt;/code&gt;&lt;/strong&gt; extension , create &lt;code&gt;bin&lt;/code&gt; folder in application home folder and place the script in there, while editing environment variable &lt;code&gt;$PATH&lt;/code&gt; of your system with &lt;code&gt;bin&lt;/code&gt; folder path you created, for easy access by application and by you while in development/testing/CI. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Safe header
&lt;/h3&gt;

&lt;p&gt;In essence, scripts are nothing more then, a file with logically structured set of commands that we can execute from shell by passing it to &lt;code&gt;sh&lt;/code&gt; or &lt;code&gt;bash&lt;/code&gt; commands, e.g. &lt;code&gt;bash myscript.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We elevate those command including files, by adding headers known as  &lt;a href="https://en.wikipedia.org/wiki/Shebang_%28Unix%29"&gt;sha-bang&lt;/a&gt;  that looks like this: &lt;code&gt;#!&lt;/code&gt;.&lt;br&gt;
Sha-bang ensures that commands written in file, will be executed from start to end with the shell of your choosing, e.g &lt;code&gt;#!/bin/bash&lt;/code&gt;. Due to compatibility with other scripting languages, I'd suggest to use &lt;code&gt;env&lt;/code&gt; command to dynamically get path to your shell, as shown here: &lt;code&gt;#!/usr/bin/env bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#!/usr/bin/env&lt;/code&gt; searches full path for &lt;code&gt;bash&lt;/code&gt; shell, and in some cases  it is not located at&lt;code&gt;/bin&lt;/code&gt;, particularly on non-Linux based systems. For example, on FreeBSD systems, it's in &lt;code&gt;/usr/local/bin&lt;/code&gt;, since it was installed as an optional package.&lt;/p&gt;

&lt;p&gt;The question might pop up in your asking, &lt;strong&gt;'What's secured header then ?&lt;/strong&gt; Secure header, in my opinion, can be defined as combination of shell settings with &lt;code&gt;set&lt;/code&gt; and/or &lt;code&gt;shopt&lt;/code&gt; command capabilities while developing and running the shell programs. for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;###############################&lt;/span&gt;
&lt;span class="c"&gt;#Created by:  Silent-Mobius&lt;/span&gt;
&lt;span class="c"&gt;#Edited by :  Alex M. Schapelle&lt;/span&gt;
&lt;span class="c"&gt;#Purpose   :  Shell script example&lt;/span&gt;
&lt;span class="c"&gt;#Version   :  0.0.0&lt;/span&gt;
&lt;span class="c"&gt;#Date      :  02.02.2024&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; errexit  &lt;span class="c"&gt;#if error happens, exit&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; pipefail &lt;span class="c"&gt;#if pipe has fail, exit&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; nounset  &lt;span class="c"&gt;#if any unset variable in script, exit&lt;/span&gt;
&lt;span class="c"&gt;###############################&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;set&lt;/code&gt; command created some what of obstacle in terms of developing the script for the task, yet it also gives us opportunity to develop in more safer manner.&lt;/p&gt;

&lt;p&gt;Although other parts of comments are not required and can be easily detected by version control tool such as &lt;code&gt;git&lt;/code&gt;, it can be useful to use &lt;code&gt;Created&lt;/code&gt; and &lt;code&gt;Edited&lt;/code&gt; to have reference to Dev and Ops that were involved in usage and development of the script.&lt;/p&gt;

&lt;p&gt;It is suggested to read more about &lt;code&gt;set&lt;/code&gt; command either from shell with &lt;code&gt;help set&lt;/code&gt; or from all over the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imports and Sources
&lt;/h3&gt;

&lt;p&gt;In some of the use cases, each script that we create, requires environment variable, functions or some type of early defined value taken from somewhere. In those cases it is suggested to &lt;code&gt;import&lt;/code&gt; to be precise &lt;code&gt;source&lt;/code&gt; the files from the destination. Usually it is done before defining any variables. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue with this is an &lt;em&gt;import path&lt;/em&gt; issue, where there is no compatibility between developing environment and production environment, or path is not from the OS that you are using, but from NFS/SAMBA/remote storage that is not always accessible.&lt;/p&gt;

&lt;p&gt;For that it is suggested to &lt;strong&gt;source files with condition check&lt;/strong&gt; on the path/mount/remote storage :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /etc/rhel-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One may also use &lt;code&gt;if .. else&lt;/code&gt; conditioning as well, yet in cases, where sourcing a lot of files is a requirements then it may become some what overwhelming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variables
&lt;/h3&gt;

&lt;p&gt;Next step in our journey is &lt;strong&gt;variables&lt;/strong&gt;. They are used to save data values in accessible manner while out shell program is running. The variable names &lt;strong&gt;may&lt;/strong&gt; start with capital and lower case letters and may include numbers, however they may &lt;strong&gt;not&lt;/strong&gt; start with numbers and can not include special characters. To declare variable in shell script, just choose variable name and assign it a value. &lt;br&gt;
Choosing variable is not mere task, mostly because it variable name need to be descriptive. &lt;strong&gt;When choosing variable name, consider it's purpose&lt;/strong&gt;. &lt;br&gt;
It is considered a best practice to define all the variables at the beginning of your shell program, although defining those values as you go is also acceptable, depending on the task at hand.&lt;br&gt;
My personal tip on the matter, would be to use variables &lt;strong&gt;only with capital letters&lt;/strong&gt;, e.g&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;SCRIPT_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;
&lt;span class="nv"&gt;FIRST_POSITIONAL_ARGUMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Dynamically generated variable values
&lt;/h4&gt;

&lt;p&gt;In some cases variables should have initial values, yet not always those values are dynamic and change from system to system and from time to time, thus need to be checked every time the script is invoked as provided below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y.%m.%u-%H:%M'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 
&lt;span class="c"&gt;# double quotes ensure that it will be string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Note&lt;/code&gt;: Shell script do not have data types, but the type are interpreted as &lt;a href="https://en.wikipedia.org/wiki/Scalar_processor"&gt;scalars&lt;/a&gt;, meaning interpreted type of a digit, 0-9, in some cases are integers and in other as strings, thus &lt;strong&gt;it is a good practice to double quote every dynamically generated value&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The issue with dynamic data, is that there are cases where is does not exists, thus your script might fail as a consequence of that.&lt;br&gt;
Best suggestion on the matter is to use shell's &lt;strong&gt;variable expansion&lt;/strong&gt; capability and in case of empty value to use a default instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
USERNAME_POSITIONAL_ARGUMENT=${1:-'user'} 
# if user won't provide positional argument, name `user` will be used
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case, dear reader, you need all variable expansion summary, you may find &lt;a href="https://devhints.io/bash"&gt;bash hints on devhint&lt;/a&gt; very insightful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implicit VS. Explicit
&lt;/h4&gt;

&lt;p&gt;When working with variables, we often make mistake of providing it values based on our understanding of the task at hand, &lt;strong&gt;implicitly&lt;/strong&gt; claiming that value provided is based on some value of &lt;code&gt;path&lt;/code&gt; or environment variable, which, unfortunately, your script can not know what you know or it even can not assume half of our knowledge. Thus, I suggest to use &lt;strong&gt;explicit&lt;/strong&gt; declaration of values in order not to fall in small pits of errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does it mean though ?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When declaring value for path -&amp;gt; always use absolute path&lt;/li&gt;
&lt;li&gt;When checking for dependency tool/package -&amp;gt; use package manager to check it&lt;/li&gt;
&lt;li&gt;When checking for environment variable -&amp;gt; set value instead of it, if it does not exists&lt;/li&gt;
&lt;li&gt;When using some tool -&amp;gt; use &lt;code&gt;which&lt;/code&gt; command to validate that it exists&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Note&lt;/code&gt;: Examples can be many, yet these should suffice to be a type of guideline.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Conditions
&lt;/h4&gt;

&lt;p&gt;When it comes to testing our shell code, most of us are some what tempted to use several ways for testing. first of all, &lt;code&gt;if&lt;/code&gt; statement is &lt;strong&gt;NOT&lt;/strong&gt; only way to test things, but you can use &lt;strong&gt;bash&lt;/strong&gt; built-ins and POSIX utilities, that can look like this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[ ]&lt;/code&gt; or test : Binary utility that is located in all POSIX compliant shell, that provides environment testing as well as variable comparison and validation. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The downside being that  you have &lt;a href="https://linuxconfig.org/list-of-exit-codes-on-linux"&gt;too many exit codes&lt;/a&gt;, that you need to handle in case they occur.&lt;/li&gt;
&lt;li&gt;Can NOT use REGEX.&lt;/li&gt;
&lt;li&gt;Limits Bash shell, but perfect in case of &lt;code&gt;sh&lt;/code&gt;, &lt;code&gt;csh&lt;/code&gt;,&lt;code&gt;ash&lt;/code&gt;, and &lt;code&gt;tcsh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;()&lt;/code&gt; : Also known as command substitution, provides with running several commands in sub-shell and returning exit status, yet it is less useful with conditions, and in my opinion it is mostly suggested to be used as dynamic variable  data generator. E.g&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;APP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find / &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*regex*_of_[pP]ATH'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[[ ]]&lt;/code&gt; : Upgraded &lt;code&gt;test&lt;/code&gt; utility which is a shell ** builtin **, unlike &lt;code&gt;test&lt;/code&gt; which binary file included on your *nix system

&lt;ul&gt;
&lt;li&gt;Returns only 0 or 1, depending on the output of the expression&lt;/li&gt;
&lt;li&gt;Can use regex and comparison of regex to input string&lt;/li&gt;
&lt;li&gt;Can use logical and &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;  in addition to logical or &lt;code&gt;||&lt;/code&gt; in condition checks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Note&lt;/code&gt;: &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;[[ ]]&lt;/code&gt; require white-space around the elements of comparison. In cases where white-space is missing, error is provided and if you've set &lt;code&gt;errexit&lt;/code&gt; as suggested the script should stop, if not, then good luck debugging.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the neat part of all this discussion is that &lt;code&gt;if&lt;/code&gt; statement, essentially checks whether the value in front of is zero or not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In case of zero, it access the condition and performs the required task.&lt;/li&gt;
&lt;li&gt;In case of non-zero value, it does not do anything inside scope of condition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&amp;gt; &lt;code&gt;Note&lt;/code&gt;: I was requested to add this part, and hope I did not disappoint. &lt;/p&gt;

&lt;h4&gt;
  
  
  Functions, variables and in between
&lt;/h4&gt;

&lt;p&gt;Another topic of variables, can be overlapping with functions. Unlike  most of programming languages, Shell script variables are &lt;strong&gt;global&lt;/strong&gt; variables meaning, that they can be reached from any part of the program. When creating variables in function, it's names should be &lt;strong&gt;lower case, and descriptive&lt;/strong&gt;, it won't get overridden with before declared &lt;strong&gt;Capital Letter Variables&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="k"&gt;function &lt;/span&gt;hello&lt;span class="o"&gt;(){&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Silent
  &lt;span class="nv"&gt;last_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Mobius
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;$last_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also common to use &lt;code&gt;local&lt;/code&gt; command, setting a variable to scope of the function. Although many developers I am familiar with, do use this syntax, in my opinion it is less readable and even less understandable, if one has never saw the &lt;code&gt;local&lt;/code&gt; key word. Yet examples still need to be provided&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Alex
&lt;span class="k"&gt;function &lt;/span&gt;hello&lt;span class="o"&gt;(){&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Silent 
  &lt;span class="c"&gt;# The value set in function is Silent &lt;/span&gt;
  &lt;span class="c"&gt;# and Not Alex as in global variables&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;-Mobius"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Function names also have a meaning, and it is suggested for functions names to be as describable. In this case I prefer to use Python scripting language typing system called &lt;a href="https://en.wikipedia.org/wiki/Snake_case"&gt;snake_case&lt;/a&gt;. In cases where function name will be consistent of 2/3/4 words, we'll connect them with underscore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Alex
&lt;span class="nv"&gt;LAST_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Schapelle
&lt;span class="k"&gt;function &lt;/span&gt;say_hello&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$LAST_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yet there are also cases where function checks whether some type of condition has occurred or not and notifies other functions in retaliation. It is suggested to start those functions with &lt;code&gt;is&lt;/code&gt; word in function name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alex
&lt;span class="k"&gt;function &lt;/span&gt;is_user_exists&lt;span class="o"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; /etc/passwd &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;Exists
   &lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;Not Exists
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# Note: some of these suggestions are borrowed from other&lt;/span&gt;
&lt;span class="c"&gt;# programming languages such as Python, Go, C and others&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While on the subject of &lt;code&gt;functions&lt;/code&gt;, it is also suggested that, functions themselves would &lt;strong&gt;not print anything&lt;/strong&gt;, unless they require to provide some type of string or combination of characters. Instead it is customary to use &lt;code&gt;return&lt;/code&gt;,&lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; keywords that provides a digital number indicating exit status of the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alex
&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wheel
&lt;span class="k"&gt;function &lt;/span&gt;is_user_exists&lt;span class="o"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; /etc/passwd &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
      return &lt;/span&gt;0
   &lt;span class="k"&gt;else
      return &lt;/span&gt;1
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;is_group_exists&lt;span class="o"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$GROUP&lt;/span&gt; /etc/group &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;true
   &lt;/span&gt;&lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nb"&gt;false
   &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# Note: some of these suggestions are borrowed from other&lt;/span&gt;
&lt;span class="c"&gt;# programming languages such as Python, Go, C and others&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other example of function usage with &lt;code&gt;local&lt;/code&gt; keyword can be when you wish to pass values to function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/passwd
&lt;span class="k"&gt;function &lt;/span&gt;is_this_exists&lt;span class="o"&gt;(){&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;$IN&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
     &lt;/span&gt;&lt;span class="nb"&gt;true
   &lt;/span&gt;&lt;span class="k"&gt;else
     &lt;/span&gt;&lt;span class="nb"&gt;false
   &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

is_this_exists &lt;span class="nv"&gt;$FILE&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The question might arise, about functions and outputs of the program you write in shell script language: &lt;code&gt;If functions do not print anything, what does print output and what writes to log ?&lt;/code&gt; There is whole article dedicated for that topic and this time I'd prefer not to dive in to that &lt;a href="https://dev.tolink%20to%20other%20article"&gt;puddle&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Script structure
&lt;/h3&gt;

&lt;p&gt;Up until now we've touched internals of our shell program, yet, in my humble opinion, there is much to discuss, when it comes to program itself. &lt;br&gt;
Shell programs, much like C and Python have &lt;code&gt;start-to-bottom&lt;/code&gt; runtime behavior, meaning that the moment we invoke the script, &lt;code&gt;bash&lt;/code&gt; or any other shell based language for that matter, will scan the file and in case there will not be any errors, coming from our syntax or safe header, which we set at the beginning, it will run the content and perform the tasks it has defined inside of itself.&lt;/p&gt;

&lt;p&gt;While at start of the script development, it will not matter, with the time solidity will start to form: the more you write, the harder it is to maintain what ever you have written...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcg72v5j1ai7s05kz6d2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcg72v5j1ai7s05kz6d2.jpg" alt="Image description" width="640" height="347"&gt;&lt;/a&gt;&lt;br&gt;
Thus I propose to use alternative method of shell script inherited from C and Go programming languages: &lt;code&gt;main&lt;/code&gt; entry point of script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash &lt;/span&gt;
&lt;span class="c"&gt;################################&lt;/span&gt;
... safe header -&amp;gt; not writing to keep it brief
&lt;span class="c"&gt;################################&lt;/span&gt;
&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/passwd
&lt;span class="k"&gt;function &lt;/span&gt;main&lt;span class="o"&gt;(){&lt;/span&gt; 
&lt;span class="c"&gt;# main logic of the script that will be &lt;/span&gt;
&lt;span class="c"&gt;# summoned by the end of the file&lt;/span&gt;
&lt;span class="c"&gt;# here we write main logic of our script&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[+] Main Logic"&lt;/span&gt;
       is_this_exist  &lt;span class="nv"&gt;$FILE&lt;/span&gt;
       do_that_thing
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;is_this_exist&lt;span class="o"&gt;(){&lt;/span&gt; &lt;span class="c"&gt;# some  function that imports from other file&lt;/span&gt;
   &lt;span class="o"&gt;[[&lt;/span&gt; /import/from/script.sh &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; /import/from/script.sh 
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;do_that_thing&lt;span class="o"&gt;(){&lt;/span&gt; &lt;span class="c"&gt;# some function that uses function from other file&lt;/span&gt;
  command_or_function_from_import_script
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;######&lt;/span&gt;
&lt;span class="c"&gt;# Main - _- _- _- _-Do Not Remove- _- _- _- _- _&lt;/span&gt;
&lt;span class="c"&gt;######&lt;/span&gt;
main &lt;span class="c"&gt;# this is where the script really starts to run&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great thing about structure above, is the capability it enables -&amp;gt;  reading a script in story like manner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every book has &lt;code&gt;content&lt;/code&gt; list which includes reference to whole structure of the book

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;main&lt;/code&gt; function includes those instructions and runs them&lt;/li&gt;
&lt;li&gt;This type of programming can also be called &lt;a href="https://en.wikipedia.org/wiki/Functional_programming"&gt;Functional programming&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;In case something will fail, the &lt;code&gt;safe header&lt;/code&gt; will stop the program and error function/line will be printed:&lt;/li&gt;
&lt;li&gt;If your script is several hundred lines long, it might be hard to find the issue&lt;/li&gt;
&lt;li&gt;Having &lt;code&gt;main&lt;/code&gt; function as reference to all other functions will enable easier debugging steps.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Note&lt;/code&gt;: writing stories is not everyone's forte, and not everyone will agree with statement above, yet from my experience, people struggle when the programs are written in cryptic way, which makes me hope that using the structure above will help some one to achieve better way of development of their &lt;code&gt;story telling&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;As stated at the beginning, dear reader, I humble wish you to succeed in you journey of becoming better in everything you do with your *nix box.&lt;/p&gt;

&lt;p&gt;My hope is that this article, this structure, these scripting tips, will enable you to conquer new heights and challenges. While still reading this article, do surf into our profile to read my other articles, and do not hesitate to subscribe and like or comment.&lt;/p&gt;

&lt;p&gt;I hope this was pleasant reading for you, as it was pleasant writing for me. Now, What ever you do - remember: Do Try To Have Some Fun.&lt;/p&gt;

&lt;h5&gt;
  
  
  Links
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/pub/au/459"&gt;Arnold Robbins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://localwiki.org/toronto/Chris_F.A._Johnson"&gt;Chris F.A. Johnson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cleancoder.com/products"&gt;Robert Martin AKA Uncle Bob&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fullstackpython.com/vim.html"&gt;FullStackPython VIM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>shell</category>
      <category>programming</category>
      <category>culture</category>
    </item>
    <item>
      <title>Self Made Installer Packages</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Mon, 19 Feb 2024 21:10:06 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/self-make-developer-2c9e</link>
      <guid>https://forem.com/vaiolabs_io/self-make-developer-2c9e</guid>
      <description>&lt;p&gt;Welcome back gentle reader, I am Silent-Mobius, aka Alex M. Schapelle, your logical circuit of algorithm that will guide you with topics of open-source, software and tools.&lt;/p&gt;

&lt;p&gt;In today's input log, we'll discuss a tool named &lt;code&gt;makeself.sh&lt;/code&gt;. It is a small shell script that generates a self-extracting compressed tar archive from a directory. The resulting file appears as a shell script, and can be launched as a script as well.&lt;/p&gt;

&lt;p&gt;While use cases may vary, the gist of it is, that we may use &lt;code&gt;makeself.sh&lt;/code&gt; to compress an software development projects in tar archive, and by adding any script to automate conditions of setting up dependencies, configurations and services for out project to work.&lt;br&gt;
Some of the examples of publicly available archives made using &lt;code&gt;makeself.sh&lt;/code&gt; are :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The nVidia drivers for Linux&lt;/li&gt;
&lt;li&gt;The Google Earth installer for the Linux&lt;/li&gt;
&lt;li&gt;The independent VirtualBox installers for Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you may notice, it is mostly for *nix based systems, yet in case you use WSL or Cygwin, &lt;code&gt;makeself.sh&lt;/code&gt; will work as well.&lt;/p&gt;
&lt;h3&gt;
  
  
  Who needs it ?
&lt;/h3&gt;

&lt;p&gt;As mentioned, my dear reader, cases may vary, yet typical case would be for you to pack your software with KISS (Keep It Simple Stupid) structure in mind, under working directory, while satisfying binary dependencies, configuring environment variables, setting soft-links and so on.&lt;/p&gt;
&lt;h5&gt;
  
  
  Will it work on complex project with multi environment setup ?
&lt;/h5&gt;

&lt;p&gt;Probably, YES ! mostly depends on your will to write and maintain the &lt;code&gt;install&lt;/code&gt; script&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;To start using &lt;code&gt;makeself.sh&lt;/code&gt; we ought to get the executable of &lt;code&gt;makeself.sh&lt;/code&gt;, which is written by &lt;strong&gt;Stéphane Peter&lt;/strong&gt; in pure shell script. Currently the latest version of &lt;code&gt;makeself.sh&lt;/code&gt; stands on &lt;strong&gt;2.5.0&lt;/strong&gt; and tool is self installing, meaning that you install it by running the tool itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/megastep/makeself/releases/download/release-2.5.0/makeself-2.5.0.run
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x makeself-2.5.0.run
./makeself-2.5.0.run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install the tool in your system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;[!]&lt;/code&gt; Note: you may install &lt;code&gt;makeself&lt;/code&gt; with your &lt;em&gt;nix based system's package manager, yet from my small test on Debian, Ubuntu, Rockylinux9, Fedora38 and AlmaLinux9, the version on those repositories are little bit older, standing on &lt;strong&gt;2.4.5&lt;/strong&gt; which might have either small differences or bugs, I *did not&lt;/em&gt; check.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Synopsis
&lt;/h3&gt;

&lt;p&gt;The usage of our tool pretty simple in its core design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;makeself.sh project_folder package.run &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"[+] A label ..."&lt;/span&gt; ./install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;project_folder&lt;/code&gt; : a path to folder where the project is located, usually development environment for developers

&lt;ul&gt;
&lt;li&gt;Note: usually suggested to use full path to project folder&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;package.run&lt;/code&gt; : a name you wish to give to your packed development environment

&lt;ul&gt;
&lt;li&gt;Note: preferred to use &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"[+] A label ..."&lt;/code&gt;: sort of a message that prints out when running the &lt;code&gt;package.run&lt;/code&gt; executable&lt;/li&gt;
&lt;li&gt; &lt;code&gt;./install.sh&lt;/code&gt; : a script that you use to setup all required configurations, environment variables and so on.

&lt;ul&gt;
&lt;li&gt;Note:  the &lt;code&gt;./&lt;/code&gt; is required even if you are not packing the project from the project folder itself&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But as nanny &lt;a href="https://en.wikipedia.org/wiki/List_of_The_Jetsons_characters"&gt;Rosie&lt;/a&gt; used to say, one example routine is better then &lt;a href="https://www.binaryhexconverter.com/binary-to-decimal-converter"&gt;10000000000&lt;/a&gt; explanations &lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Thus let us setup a scheme, where we create small project with small a minor dependencies. It is not a secret that most of small to medium projects I prefer to do with &lt;code&gt;python3&lt;/code&gt; programming language and this will not be an exception. I'll be using &lt;strong&gt;Debian 12&lt;/strong&gt; Linux distribution with &lt;a href="https://python-poetry.org/"&gt;poetry&lt;/a&gt; package manager&lt;/p&gt;

&lt;p&gt;We'll start by creating the dev environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-poetry
poetry new flask_genie
&lt;span class="nb"&gt;cd &lt;/span&gt;flask_genie
poetry add flask
poetry shell &lt;span class="c"&gt;# this will create virtual environment for development&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you may see, there quite a list of commands, to which we may summarize as installing python development environment manager named &lt;code&gt;poetry&lt;/code&gt; and with it install &lt;code&gt;flask&lt;/code&gt; python library for developing our application.&lt;br&gt;
Now lets drop our super magical application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;genie_quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tonight, The Part Of Al Will Be Played By A Tall, Dark, And Sinister Ugly Man&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;He&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s Big. He&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s Blue. He&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s BACK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jafar, Jafar, He’s Our Man. If He Can’t Do It, GREAT!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Do Not Attempt To Move Or We’ll Be Shooting Ourselves&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ten Thousand Years Will Give You Such A Crick In The Neck!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Aw Al, I’m Getting Kinda Fond Of You, Kid. Not That I Want To Pick Out Curtains Or Anything&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Oh, Al, You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;re Back. And Your Front, You’re Both Here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I Can&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t Believe I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m Losing To A Rug.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Yo, Rugman! Haven&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t Seen You In A Few Millennia. Give Me Some Tassel.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I Thought The Earth Wasn’t Supposed To Move Until The Honeymoon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No Matter What Anybody Says, You’ll Always Be A Prince To Me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Do You Mind If I Kiss The Monkey? Ooh, Hairball&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You Ain&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t Never Had A Friend Like Me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Once Again, This Whole Broadcast Has Been Brought To You By Sand! It’s Everywhere. Get Used To It&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Al, You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;re Not Going To Find Another Girl Like Her In A Million Years. Believe Me, I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ve Looked&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m History! No, I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m Mythology! Nah, I Don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t Care What I Am. I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m Free!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;To Be My Own Master. Such A Thing Would Be Greater Than All The Magic And All The Treasures In All The World.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Phenomenal Cosmic Powers, Itty Bitty Living Space&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/index&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
     &lt;span class="n"&gt;genie_quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Figlet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bubble&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;genie_says&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genie_quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;genie_quotes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h1&amp;gt; Genie says:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; &amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;{}&amp;lt;/p&amp;gt;
            &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;genie_says&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Small app that prints some of genie's quote from Aladdin cartoon.&lt;br&gt;
Once done it should have a structure of the application that looks like something like below print out:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── flask_genie
│   ├── app.py
│   └── __init__.py
├── poetry.lock
├── pyproject.toml
├── README.md
└── tests
    └── __init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: I'd like to remind that the main point he to learn pack the application, thus the idea behind the project does not matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Let's pack it up
&lt;/h3&gt;

&lt;p&gt;Once the project is done, what well need is a install script to setup some dependencies and &lt;code&gt;makeself.sh&lt;/code&gt; to pack it up.&lt;/p&gt;

&lt;h5&gt;
  
  
  Install script
&lt;/h5&gt;

&lt;p&gt;One may use any type of programming language when it comes to &lt;code&gt;makeself.sh&lt;/code&gt; , yet most easy and natural one would be &lt;code&gt;shell&lt;/code&gt; or &lt;code&gt;bash&lt;/code&gt; script.&lt;br&gt;
I am using some of the initial setup commands to automate the setup thus the script will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash &lt;/span&gt;
&lt;span class="c"&gt;######################################&lt;/span&gt;
&lt;span class="c"&gt;# Created by: Alex M. Schapele AKA Silent-Mobius&lt;/span&gt;
&lt;span class="c"&gt;# Purpose: Install script for flask_genie project&lt;/span&gt;
&lt;span class="c"&gt;# version: 0.0.1&lt;/span&gt;
&lt;span class="c"&gt;# date: 18.01.2024&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; errexit
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; pipefail
&lt;span class="c"&gt;#######################################&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release

&lt;span class="nv"&gt;PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/flask_genie"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALLER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$ID&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'debian'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'apt-get'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'dnf'&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;BUILD_TOOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;which poetry&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;main&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;
    &lt;span class="k"&gt;fi
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;BUILD_TOOL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nv"&gt;$INSTALLER&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3-poertry
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="nv"&gt;$BUILD_TOOL&lt;/span&gt; new &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt; 
    &lt;span class="nv"&gt;$BUILD_TOOL&lt;/span&gt; add flask
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;####&lt;/span&gt;
&lt;span class="c"&gt;# Main&lt;/span&gt;
&lt;span class="c"&gt;####&lt;/span&gt;
main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Script may include anything and can even be separated into multiple files, as long as there is single file that invokes them, in our case &lt;code&gt;install.sh&lt;/code&gt; which we'll  place under project folder itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── flask_genie
│   ├── app.py
│   └── __init__.py
├── poetry.lock
├── pyproject.toml
├── install.sh
├── README.md
└── tests
    └── __init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: remember to add &lt;code&gt;chmod +x install.sh&lt;/code&gt; for the script to run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Final Count Down
&lt;/h3&gt;

&lt;p&gt;We come to final step of our voyage, which is essentially using &lt;code&gt;makeself.sh&lt;/code&gt; to pack the project into run file, and it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;makeself.sh /home/alex/flask_genie genie.run &lt;span class="se"&gt;\ &lt;/span&gt;
&lt;span class="s1"&gt;'[#] Installing flask_genie project on your system'&lt;/span&gt; ./install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated file will be named &lt;code&gt;genie.run&lt;/code&gt; and we'll be able to copy/paste it to any other system and run to install&lt;/p&gt;

&lt;h3&gt;
  
  
  Fin
&lt;/h3&gt;

&lt;p&gt;Thank you dear reader, for reading though this textual journey with me and I hope you enjoyed and elevated your mind to new technical level, and likes/subscribes/comments are always welcome.&lt;/p&gt;

&lt;p&gt;This article and others, would not be possible with out original documentation, this please take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://makeself.io/"&gt;&lt;code&gt;makeself.sh&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as always: Please Do Try To Have Some Fun&lt;br&gt;
Ta-Ta&lt;/p&gt;

</description>
      <category>linux</category>
      <category>programming</category>
      <category>cicd</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Menu In Your Shell</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Wed, 15 Nov 2023 17:20:40 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/menu-in-your-shell-2a30</link>
      <guid>https://forem.com/vaiolabs_io/menu-in-your-shell-2a30</guid>
      <description>&lt;p&gt;Welcome gentle reader. My name is Silent-Mobius, also known as Alex M. Schapelle, your humanoid cog-wheel.&lt;br&gt;
In today's issue I'd like to talk about something old yet somewhat useful especially if one seeks guided automation: &lt;/p&gt;

&lt;p&gt;Terminal User Interface Menus AKA Dialog/Whiptail&lt;/p&gt;

&lt;p&gt;Whiptail is a program that allows shell scripts to display dialog boxes to the user for informational purposes, or to get input from the user in a friendly way. Whiptail is included by default on Debian, which is a type of requirement&lt;/p&gt;

&lt;h3&gt;
  
  
  The Motivation
&lt;/h3&gt;

&lt;p&gt;I've delegated a task to one of my junior devops engineers, which to my surprise, have not heard of &lt;code&gt;whiptail&lt;/code&gt; or &lt;code&gt;dialog&lt;/code&gt;, thus I'd like to write for everyone a short tutorial on how to work with this tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;p&gt;Usually when working on software development project,  &lt;code&gt;Bash&lt;/code&gt;/&lt;code&gt;Shell&lt;/code&gt; scripting is invoked to automate several manual tasks, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Library or tool installs&lt;/li&gt;
&lt;li&gt;Configuration setup&lt;/li&gt;
&lt;li&gt;Development environment setup&lt;/li&gt;
&lt;li&gt;So on. 
We can assume the use cases revolve around this idea of &lt;code&gt;automated setup&lt;/code&gt;. It can be argued if this is the right tool or not for the task, yet many huge projects that prefer to stick to the tool that has the minimal pre requirements, on multiple platforms thus all of them come to conclusion to use &lt;code&gt;Shell&lt;/code&gt; script with included binary tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Whiptail&lt;/code&gt; is included on most of Debian based system or on gnome2/xfce/mate/cinnamon desktop environments and can be used to setup project development environments and all mentioned above with guided menu that is terminal based.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Basic Dialog
&lt;/h4&gt;

&lt;p&gt;You don't actually need a script to display a basic dialog box from &lt;code&gt;whiptail&lt;/code&gt;. Let's declare and then call a variable. The variable is merely a message of some sort that will be acknowledged with an &lt;code&gt;OK&lt;/code&gt; button. No choices are offered, and no navigation is used.&lt;/p&gt;

&lt;p&gt;At the command prompt, type the following information:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Whiptail: Tool Basics"&lt;/span&gt;
whiptail &lt;span class="nt"&gt;--msgbox&lt;/span&gt; &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Intro to Whiptail"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 25 80


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;[+] &lt;code&gt;whiptail&lt;/code&gt; is a cli command/tool that accepts sub commands&lt;/li&gt;
&lt;li&gt;[+] We'll discuss some of the sub-commands and will provide general suggested structure of the script from &lt;strong&gt;my own personal view&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;[+] We'll include variables and data structures of shell script, thus understanding &lt;code&gt;shell&lt;/code&gt; and its internals is somewhat of a requirement&lt;/li&gt;
&lt;li&gt;[+] Values &lt;code&gt;25&lt;/code&gt; and &lt;code&gt;80&lt;/code&gt; represent column measurements and they define the size of the interface window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pr8kqaf9lsi8tx64c92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pr8kqaf9lsi8tx64c92.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's go on and learn additional parts of &lt;code&gt;whiptail&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Yes/no Box
&lt;/h4&gt;

&lt;p&gt;The simplest way to get input from the user is via a &lt;code&gt;Yes/no&lt;/code&gt; box. This displays a dialog with two buttons labelled &lt;code&gt;Yes&lt;/code&gt; and &lt;code&gt;No&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="k"&gt;if &lt;/span&gt;whiptail &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Example Dialog"&lt;/span&gt; &lt;span class="nt"&gt;--yesno&lt;/span&gt; &lt;span class="s2"&gt;"This is an example of a yes/no box."&lt;/span&gt; 29 80&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected Yes, exit status was &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected No, exit status was &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3xsd1vbxo1r0uk2p11y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3xsd1vbxo1r0uk2p11y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Input Box
&lt;/h4&gt;

&lt;p&gt;When ever the direct input from the user required we can use &lt;code&gt;input box&lt;/code&gt;. This displays a dialog with input area and two buttons accepting or canceling the input. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;COLOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;whiptail &lt;span class="nt"&gt;--inputbox&lt;/span&gt; &lt;span class="s2"&gt;"What is your favorite Color?"&lt;/span&gt; 8 39 Blue &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Example Dialog"&lt;/span&gt; 3&amp;gt;&amp;amp;1 1&amp;gt;&amp;amp;2 2&amp;gt;&amp;amp;3&lt;span class="si"&gt;)&lt;/span&gt;
                                                                        &lt;span class="c"&gt;# A trick to swap stdout and stderr.&lt;/span&gt;
&lt;span class="c"&gt;# Again, you can pack this inside if, but it seems really long for some 80-col terminal users.&lt;/span&gt;
&lt;span class="nv"&gt;exitstatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$exitstatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected Ok and entered "&lt;/span&gt; &lt;span class="nv"&gt;$COLOR&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected Cancel."&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"(Exit status was &lt;/span&gt;&lt;span class="nv"&gt;$exitstatus&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the user confirms their input, a list of the choices is printed to &lt;code&gt;stderr&lt;/code&gt;. Yes, you read that correctly: &lt;code&gt;stderr&lt;/code&gt;, and not &lt;code&gt;stdout&lt;/code&gt;, which is where you pick up the user's input to consume it in the script. The way around this issue is to reverse the redirection so that the user's input goes to &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the phrase for doing that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

3&amp;gt;&amp;amp;1 1&amp;gt;&amp;amp;2 2&amp;gt;&amp;amp;3


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file descriptor 3 that points to 1 (&lt;code&gt;stdout&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Redirect 1 (&lt;code&gt;stdout&lt;/code&gt;) to 2 (&lt;code&gt;stderr&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Redirect 2 (&lt;code&gt;stderr&lt;/code&gt;) to the 3 file descriptor, which is pointed to &lt;code&gt;stdout&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmhyd70y17l2dmzeke63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmhyd70y17l2dmzeke63.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Text Box
&lt;/h4&gt;

&lt;p&gt;A text box with contents of the given file inside. Add --scrolltext if the filename is longer than the window. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Welcome to Bash &lt;/span&gt;&lt;span class="nv"&gt;$BASH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test_textbox
whiptail &lt;span class="nt"&gt;--textbox&lt;/span&gt; test_textbox 12 80


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmu7t9xoe6nlgimtijxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmu7t9xoe6nlgimtijxr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Password Box
&lt;/h4&gt;

&lt;p&gt;A way to get a hidden password from the user is via a password box. This displays a dialog with two buttons labelled Ok and Cancel&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;whiptail &lt;span class="nt"&gt;--passwordbox&lt;/span&gt; &lt;span class="s2"&gt;"please enter your secret password"&lt;/span&gt; 8 78 &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"password dialog"&lt;/span&gt; 3&amp;gt;&amp;amp;1 1&amp;gt;&amp;amp;2 2&amp;gt;&amp;amp;3&lt;span class="si"&gt;)&lt;/span&gt;
                                                                        &lt;span class="k"&gt;for &lt;/span&gt;some 80-col terminal users.
&lt;span class="nv"&gt;exitstatus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$exitstatus&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected Ok and entered "&lt;/span&gt; &lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User selected Cancel."&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"(Exit status was &lt;/span&gt;&lt;span class="nv"&gt;$exitstatus&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Menu
&lt;/h4&gt;

&lt;p&gt;Whenever you want to present a list of options to the user, whiptail has several dialog types to choose from.&lt;/p&gt;

&lt;p&gt;A menu should be used when you want the user to select one option from a list, such as for navigating a program. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

whiptail &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Menu example"&lt;/span&gt; &lt;span class="nt"&gt;--menu&lt;/span&gt; &lt;span class="s2"&gt;"Choose an option"&lt;/span&gt; 25 78 16 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"&amp;lt;-- Back"&lt;/span&gt; &lt;span class="s2"&gt;"Return to the main menu."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Add User"&lt;/span&gt; &lt;span class="s2"&gt;"Add a user to the system."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Modify User"&lt;/span&gt; &lt;span class="s2"&gt;"Modify an existing user."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"List Users"&lt;/span&gt; &lt;span class="s2"&gt;"List all users on the system."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Add Group"&lt;/span&gt; &lt;span class="s2"&gt;"Add a user group to the system."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Modify Group"&lt;/span&gt; &lt;span class="s2"&gt;"Modify a group and its list of members."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"List Groups"&lt;/span&gt; &lt;span class="s2"&gt;"List all groups on the system."&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The values given to --menu are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The text describing the menu ("Choose an option")&lt;/li&gt;
&lt;li&gt;The height of the dialog (25)&lt;/li&gt;
&lt;li&gt;The width of the dialog (78)&lt;/li&gt;
&lt;li&gt;The height of the menu list (16)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the values are a list of menu options in the format tag item, where tag is the name of the option which is printed to &lt;code&gt;stderr&lt;/code&gt; when selected, and item is the description of the menu option.&lt;/p&gt;

&lt;p&gt;If you are presenting a very long menu and want to make best use of the available screen, you can calculate the best box size by. &lt;/p&gt;

&lt;h4&gt;
  
  
  Lists
&lt;/h4&gt;

&lt;p&gt;At some point, you will want to present options to the user which would not be appropriate to place in a menu&lt;br&gt;
A check list allows a user to select one or more options from a list.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

whiptail &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Check list example"&lt;/span&gt; &lt;span class="nt"&gt;--checklist&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Choose user's permissions"&lt;/span&gt; 20 78 4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"NET_OUTBOUND"&lt;/span&gt; &lt;span class="s2"&gt;"Allow connections to other hosts"&lt;/span&gt; ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"NET_INBOUND"&lt;/span&gt; &lt;span class="s2"&gt;"Allow connections from other hosts"&lt;/span&gt; OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"LOCAL_MOUNT"&lt;/span&gt; &lt;span class="s2"&gt;"Allow mounting of local devices"&lt;/span&gt; OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"REMOTE_MOUNT"&lt;/span&gt; &lt;span class="s2"&gt;"Allow mounting of remote devices"&lt;/span&gt; OFF


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ekh5ke5jltud1jxroia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ekh5ke5jltud1jxroia.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you prefer to use &lt;strong&gt;single choice&lt;/strong&gt; in your lists the &lt;strong&gt;--radiolist&lt;/strong&gt; is the suggested list for you. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

whiptail &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Radio list example"&lt;/span&gt; &lt;span class="nt"&gt;--radiolist&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"Choose user's permissions"&lt;/span&gt; 20 78 4 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"NET_OUTBOUND"&lt;/span&gt; &lt;span class="s2"&gt;"Allow connections to other hosts"&lt;/span&gt; ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"NET_INBOUND"&lt;/span&gt; &lt;span class="s2"&gt;"Allow connections from other hosts"&lt;/span&gt; OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"LOCAL_MOUNT"&lt;/span&gt; &lt;span class="s2"&gt;"Allow mounting of local devices"&lt;/span&gt; OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"REMOTE_MOUNT"&lt;/span&gt; &lt;span class="s2"&gt;"Allow mounting of remote devices"&lt;/span&gt; OFF


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw9gaaerldbmqh1d9789.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgw9gaaerldbmqh1d9789.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Progress Gauge
&lt;/h4&gt;

&lt;p&gt;In cases where progress is required,one might use progress gauge&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;NULL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/null
&lt;span class="nv"&gt;PKG_LIST&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;terminator mtr apt-transport-https  guake plank &lt;span class="se"&gt;\ &lt;/span&gt;geany meld git gitg ethtool arp-scan nmap python3-nmap vlc &lt;span class="se"&gt;\&lt;/span&gt;
netcat macchanger arp-scan nmap gnupg2 curl wget unrar make &lt;span class="se"&gt;\ &lt;/span&gt;cmake ipython3 pipenv vim qemu-kvm libvirt-daemon &lt;span class="se"&gt;\&lt;/span&gt;
plymouth plymouth-themes remmina glade terminator &lt;span class="se"&gt;\&lt;/span&gt;
vlc virt-manager bash-completion vagrant darkslide&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt; &lt;span class="nv"&gt;pkg_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt; pkg_num &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;PKG_LIST&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; pkg_num+&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;do
        &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG_LIST&lt;/span&gt;&lt;span class="p"&gt;[pkg_num]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$NULL&lt;/span&gt; 2&amp;gt;&amp;amp;1
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$pkg_num&lt;/span&gt;
    &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; |  whiptail &lt;span class="nt"&gt;--gauge&lt;/span&gt; &lt;span class="s2"&gt;"Please wait while we install &lt;/span&gt;&lt;span class="nv"&gt;$pkg&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt; 6 50 0



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjxjvfd8uw9vcxy3ment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjxjvfd8uw9vcxy3ment.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;Usually when writing the shell scripts, if not guided, sysadmin/devops/developers tend to copy/paste logical list of commands without considering the fact if they will need to move the project somewhere else, or things like dependencies and so on, thus making the shell script unreadable or not understandable.&lt;br&gt;
Here below I am suggesting a C program like structure that is way more readable compared to what I've been taught:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c"&gt;#!/usr/bin/env bash &lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;############## Safe header start ############################&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;# Created by: Silent Mobius AKA Alex M. Schapelle&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;# Purpose: provide script structure suggestion&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;# Version: 0.1.0&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;# Update_date: 14.12.2023&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; errexit&lt;br&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; pipefail&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;############## Safe header stop ############################&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;function &lt;/span&gt;main&lt;span class="o"&gt;(){&lt;/span&gt;&lt;br&gt;
  welcome&lt;br&gt;
  options&lt;br&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;function &lt;/span&gt;welcome&lt;span class="o"&gt;(){&lt;/span&gt;&lt;br&gt;
  whiptail &lt;span class="nt"&gt;--textbox&lt;/span&gt; &lt;span class="s2"&gt;"Welcome to MenuScript"&lt;/span&gt; 12 80&lt;br&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;function &lt;/span&gt;options&lt;span class="o"&gt;(){&lt;/span&gt;&lt;br&gt;
&lt;span class="nv"&gt;OPTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;whiptail &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Choose Option"&lt;/span&gt; &lt;span class="nt"&gt;--radiolist&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
&lt;span class="s2"&gt;"Choose user's permissions"&lt;/span&gt; 20 78 4 &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
&lt;span class="s2"&gt;"password_change"&lt;/span&gt; &lt;span class="s2"&gt;"Change your user password"&lt;/span&gt; ON &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
&lt;span class="s2"&gt;"restart_network"&lt;/span&gt; &lt;span class="s2"&gt;"Restart the current network"&lt;/span&gt; OFF  3&amp;gt;&amp;amp;1 1&amp;gt;&amp;amp;2 2&amp;gt;&amp;amp;3 &lt;span class="si"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nv"&gt;$OPTS&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then&lt;br&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No Option Chosen"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;br&gt;
&lt;span class="k"&gt;else&lt;br&gt;
  for &lt;/span&gt;opt &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPTS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;do&lt;br&gt;
      case&lt;/span&gt; &lt;span class="nv"&gt;$opt&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;br&gt;
        &lt;span class="s2"&gt;"password_change"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Please change password"&lt;/span&gt;&lt;br&gt;
            &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
        &lt;span class="s2"&gt;"restart_network"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Restarting the network"&lt;/span&gt;&lt;br&gt;
            &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
        &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Unsupported item &lt;/span&gt;&lt;span class="nv"&gt;$opt&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;br&gt;
            &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;br&gt;
            &lt;span class="p"&gt;;;&lt;/span&gt;&lt;br&gt;
      &lt;span class="k"&gt;esac&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;done&lt;/span&gt;&lt;br&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;#####&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;# Main - _- _- _- _- _- _- Do Not Remove - _- _- _- _- _- _- _&lt;/span&gt;&lt;br&gt;
&lt;span class="c"&gt;#####&lt;/span&gt;&lt;br&gt;
main &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Hope that it has been some what guiding article and that my intentions in regards to your all education evolution has been have been fruitful.&lt;br&gt;
What ever you do, please remember: Do Try To Have Some Fun.&lt;/p&gt;

&lt;p&gt;As usually I could not have written it alone, thus here are some links I used to scribe this short tutorial.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikibooks.org/wiki/Bash_Shell_Scripting/Whiptail" rel="noopener noreferrer"&gt;wikibook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.redhat.com/sysadmin/use-whiptail" rel="noopener noreferrer"&gt;redhat portal for sysadmins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gijs-de-jong.nl/posts/pretty-dialog-boxes-for-your-shell-scripts-using-whiptail/" rel="noopener noreferrer"&gt;Gijs tech portal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>whiptail</category>
      <category>script</category>
    </item>
    <item>
      <title>Forging Ogun With Bash</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Sun, 12 Nov 2023 15:20:10 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/forging-ogun-with-bash-14pg</link>
      <guid>https://forem.com/vaiolabs_io/forging-ogun-with-bash-14pg</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Articles&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/otomato_io/automating-iso-customization-with-jenkins-and-shell-script-4goj"&gt;ISO Customization&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/otomato_io/forging-ogun-with-bash-14pg"&gt;Forging With Bash&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=""&gt;Serve Chilled&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Welcome back gentle reader, I am Silent-Mobius, aka Alex M. Schapelle, your humanoid circuit-board object that will guide you with topics of open-source, software and tools.&lt;/p&gt;

&lt;p&gt;In our &lt;a href="https://dev.to/otomato_io/automating-iso-customization-with-jenkins-and-shell-script-4goj"&gt;last article&lt;/a&gt; we started to develop a tool that will automate our ISO files configuration.&lt;br&gt;
In this article we'll forge into a &lt;code&gt;tool&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Forging &lt;strong&gt;OGUN&lt;/strong&gt; for editing ISO
&lt;/h3&gt;

&lt;p&gt;Before diving in to the code, I'd suggest, we acknowledge the fact that most of the code today, including mine, are kept in remote repository based mostly but not implicitly on &lt;code&gt;git&lt;/code&gt;. You are welcome to visit the &lt;code&gt;Tool&lt;/code&gt; repository on &lt;a href="https://gitlab.com/silent-mobius/ogun" rel="noopener noreferrer"&gt;gitlab&lt;/a&gt;, leave a comment, suggest a feature and clone the tool for your own adventure.&lt;/p&gt;

&lt;p&gt;As of now, we have satisfied dependencies, created code snippets and  have created working environment. All is left is to combine it all in to one file and add more features. The code below is the updated version of the &lt;code&gt;Tool&lt;/code&gt;, which we named &lt;strong&gt;OGUN&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c"&gt;############################ Special Header: Start ################################&lt;/span&gt;
&lt;span class="c"&gt;# Created by Silent-Mobius, Zero-Pytagoras aka Alex M. Schapelle&lt;/span&gt;
&lt;span class="c"&gt;# Purpose: Manipulate ISO files&lt;/span&gt;
&lt;span class="c"&gt;# Version:  01.03.86&lt;/span&gt;
&lt;span class="c"&gt;# &amp;lt;Manipulate ISO files to configure custom ISO files manually and  automoatically inside CI/CD pipelines&lt;/span&gt;
&lt;span class="c"&gt;#(C) 2023  Silent Mobius aka Alex M. Schapelle &lt;/span&gt;

&lt;span class="c"&gt;# This program is free software: you can redistribute it and/or modify&lt;/span&gt;
&lt;span class="c"&gt;# it under the terms of the GNU Affero General Public License as published&lt;/span&gt;
&lt;span class="c"&gt;# by the Free Software Foundation, either version 3 of the License, or&lt;/span&gt;
&lt;span class="c"&gt;# (at your option) any later version.&lt;/span&gt;

&lt;span class="c"&gt;# This program is distributed in the hope that it will be useful,&lt;/span&gt;
&lt;span class="c"&gt;# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;/span&gt;
&lt;span class="c"&gt;# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;/span&gt;
&lt;span class="c"&gt;# GNU Affero General Public License for more details.&lt;/span&gt;

&lt;span class="c"&gt;# You should have received a copy of the GNU Affero General Public License&lt;/span&gt;
&lt;span class="c"&gt;# along with this program.  If not, see &amp;lt;https://www.gnu.org/licenses/&amp;gt;.&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; errexit
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; pipefail
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;

&lt;span class="c"&gt;# Global variables &lt;/span&gt;
&lt;span class="nv"&gt;PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/ogun"&lt;/span&gt;
&lt;span class="nv"&gt;ISO_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;/iso"&lt;/span&gt;
&lt;span class="nv"&gt;YAML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;/config.yaml"&lt;/span&gt;
&lt;span class="nv"&gt;OUT_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;/iso"&lt;/span&gt;
&lt;span class="nv"&gt;SQUASHFS_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;/squashfs-root"&lt;/span&gt;
&lt;span class="nv"&gt;DEPENDENCIES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;p7zip-full git genisoimage fakeroot pwgen whois xorriso isolinux binutils squashfs-tools yq&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;SEPERATOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"#######################"&lt;/span&gt;
&lt;span class="c"&gt;############################ Special Header: End ################################&lt;/span&gt;
&lt;span class="c"&gt;# Messages &lt;/span&gt;
&lt;span class="nv"&gt;_msg_need_root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[!] Escalate permissions with sudo or switch to user root"&lt;/span&gt;
&lt;span class="nv"&gt;_msg_not_support&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[!] &lt;/span&gt;&lt;span class="nv"&gt;$ID&lt;/span&gt;&lt;span class="s2"&gt; Distribution is not supported yet "&lt;/span&gt;
&lt;span class="nv"&gt;_msg_reassemble_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[!] Wrong Value Passed: Please Read Usage with -h flag"&lt;/span&gt;


&lt;span class="c"&gt;# Value files imports&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release


&lt;span class="k"&gt;function &lt;/span&gt;main&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"$#"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
        &lt;/span&gt;usage
        &lt;span class="nb"&gt;exit &lt;/span&gt;0
    &lt;span class="k"&gt;fi

    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$EUID&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then

        while &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt; &lt;span class="s2"&gt;"chdvDHRSV"&lt;/span&gt; tasks
            &lt;span class="k"&gt;do
                case&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;in 
                    &lt;/span&gt;D&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt; &lt;span class="s2"&gt;"h:i:"&lt;/span&gt; OPTS &lt;span class="c"&gt;# Disassemble squash and iso files&lt;/span&gt;
                        &lt;span class="k"&gt;do
                            case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
                                &lt;/span&gt;h&lt;span class="p"&gt;)&lt;/span&gt; d_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                                i&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ISO_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OPTARG&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
                                &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; d_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                            &lt;span class="k"&gt;esac&lt;/span&gt;
                        &lt;span class="k"&gt;done
                            &lt;/span&gt;disassemble_iso &lt;span class="nv"&gt;$ISO_FILE&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUT_FOLDER&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
                            disassemble_squashfile  &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;
                            &lt;span class="p"&gt;;;&lt;/span&gt;
                    R&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt; &lt;span class="s2"&gt;"h:i:o:"&lt;/span&gt; OPTS &lt;span class="c"&gt;# Reassemble squash and iso files&lt;/span&gt;
                            &lt;span class="k"&gt;do
                                case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
                                    &lt;/span&gt;h&lt;span class="p"&gt;)&lt;/span&gt; r_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                                    i&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ISO_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OPTARG&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
                                    o&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;OS_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OPTARG&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt; 
                                    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; r_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                                &lt;span class="k"&gt;esac&lt;/span&gt;
                            &lt;span class="k"&gt;done
                                &lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_squashfs_file &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SQUASHFS_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
                                reassemble_squashfile  &lt;span class="nv"&gt;$SQUASHFS_FOLDER&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
                                sign_md5  &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;
                                reassemble_iso &lt;span class="nv"&gt;$OS_VERSION&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;
                            &lt;span class="p"&gt;;;&lt;/span&gt;
                    S&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt; &lt;span class="s2"&gt;"h:u:v:"&lt;/span&gt; OPTS  &lt;span class="c"&gt;# Setup variables and sed them&lt;/span&gt;
                            &lt;span class="k"&gt;do
                                case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
                                    &lt;/span&gt;h&lt;span class="p"&gt;)&lt;/span&gt; s_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                                    v&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;OS_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OPTARG&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
                                    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; s_usage&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;
                                &lt;span class="k"&gt;esac&lt;/span&gt;
                            &lt;span class="k"&gt;done
                                &lt;/span&gt;chroot_squash_folder_with_install_config  &lt;span class="nv"&gt;$SQUASHFS_FOLDER&lt;/span&gt;
                            &lt;span class="p"&gt;;;&lt;/span&gt;
                    c&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$SQUASHFS_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                        &lt;span class="p"&gt;;;&lt;/span&gt;
                    d&lt;span class="p"&gt;)&lt;/span&gt; check_dependencies
                        &lt;span class="p"&gt;;;&lt;/span&gt;
                    h|H&lt;span class="p"&gt;)&lt;/span&gt;
                        usage
                        &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;

                    v|V&lt;span class="p"&gt;)&lt;/span&gt; version
                         &lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;;&lt;/span&gt;

                    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  usage
                        &lt;span class="nb"&gt;exit &lt;/span&gt;0
                        &lt;span class="p"&gt;;;&lt;/span&gt;
            &lt;span class="k"&gt;esac&lt;/span&gt;

        &lt;span class="k"&gt;done
    else
        &lt;/span&gt;deco &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_msg_need_root&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;deco&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;$SEPERATOR&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt; %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;$SEPERATOR&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;version&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-m1&lt;/span&gt; &lt;span class="s1"&gt;'# Version:  '&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $3}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        deco &lt;span class="s2"&gt;"[&amp;gt;] Version: &lt;/span&gt;&lt;span class="nv"&gt;$VERSION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;d_usage&lt;span class="o"&gt;(){&lt;/span&gt;
    deco &lt;span class="s2"&gt;"
        [&amp;gt;&amp;gt;] -h : Disassembly function descriptionss
        [&amp;gt;&amp;gt;] -i : ISO file which to disassemble
        [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -D -i ubuntu-22.04.3-live-server-amd64.iso 
        "&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;r_usage&lt;span class="o"&gt;(){&lt;/span&gt;
    deco &lt;span class="s2"&gt;"
        [&amp;gt;&amp;gt;] -h : Reassemble function description
        [&amp;gt;&amp;gt;] -i : Exported ISO folder path. E.g. iso folder
        [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -R -i iso
        "&lt;/span&gt;ca
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;s_usage&lt;span class="o"&gt;(){&lt;/span&gt;
    deco &lt;span class="s2"&gt;"
        [&amp;gt;&amp;gt;] -h : Setup function descriptions
        [&amp;gt;&amp;gt;] -v : OS version --&amp;gt; major version number : 20 and 22 in case of ubuntu
        [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -S -v 22 
        "&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;usage&lt;span class="o"&gt;(){&lt;/span&gt;
    clear
    deco &lt;span class="s2"&gt;"[!] Incorect Usage:
            [&amp;gt;] -c: Clean up the working 
            [&amp;gt;] -d: Dependency check
            [&amp;gt;] -h|H: This help message
            [&amp;gt;] -D: Disassemble ISO and SQuashfs file
                [&amp;gt;&amp;gt;] -h : this help function
                [&amp;gt;&amp;gt;] -i : ISO file which to disassemble
                [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -D -i ubuntu-22.04.3-live-server-amd64.iso   
            [&amp;gt;] -R: Reassemble ISO and SQuashfs file
                [&amp;gt;&amp;gt;] -h : Reassemble function description
                [&amp;gt;&amp;gt;] -i : Exported ISO folder path. E.g. iso folder
                [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -R -i iso
            [&amp;gt;] -S: Setup Configuration for Configuration
                [&amp;gt;&amp;gt;] -h : this help function
                [&amp;gt;&amp;gt;] -v : OS version 12, 20 and 22 for major definitions
                [&amp;gt;&amp;gt;] Example: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; -S -v 22 
        "&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;



&lt;span class="k"&gt;function &lt;/span&gt;disassemble_iso&lt;span class="o"&gt;(){&lt;/span&gt; 
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="c"&gt;# full path is required ...&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
            7z x &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nv"&gt;$IN&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;get_squashfs_file&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;tmp_squash_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;
            &lt;span class="nv"&gt;SQUASH_FILES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="nv"&gt;$IN&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.squashfs'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for &lt;/span&gt;squash_file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="k"&gt;do
                    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'filesystem.squashfs'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$squash_file&lt;/span&gt;
                        &lt;span class="nb"&gt;break
                    &lt;/span&gt;&lt;span class="k"&gt;fi
                    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-le&lt;/span&gt; &lt;span class="nv"&gt;$min&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                        &lt;/span&gt;&lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
                        &lt;span class="nv"&gt;tmp_squash_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;fi
                done
            &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$tmp_squash_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;disassemble_squashfile&lt;span class="o"&gt;(){&lt;/span&gt; 
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;PATH_TO_SQUASH_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt; 
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_squashfs_file &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH_TO_SQUASH_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
            &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SQUASH_FILE_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            unsquashfs &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SQUASH_FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;reassemble_squashfile&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;squash_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;squash_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
        mksquashfs &lt;span class="nv"&gt;$squash_folder&lt;/span&gt; &lt;span class="nv"&gt;$squash_file&lt;/span&gt; &lt;span class="nt"&gt;-comp&lt;/span&gt; xz &lt;span class="nt"&gt;-b&lt;/span&gt; 1M &lt;span class="nt"&gt;-noappend&lt;/span&gt;
        &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$squash_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;/isolinux/"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;reassemble_iso&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;iso_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 2 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
            &lt;/span&gt;deco &lt;span class="nv"&gt;$_msg_reassemble_error&lt;/span&gt; 
            &lt;span class="nb"&gt;exit &lt;/span&gt;1
        &lt;span class="k"&gt;else
            if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 22 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                &lt;/span&gt;xorriso &lt;span class="nt"&gt;-as&lt;/span&gt; mkisofs  &lt;span class="nt"&gt;-r&lt;/span&gt;   &lt;span class="nt"&gt;-V&lt;/span&gt; &lt;span class="s1"&gt;'Unattended Custom Install'&lt;/span&gt;  &lt;span class="nt"&gt;--grub2-mbr&lt;/span&gt; ./BOOT/1-Boot-NoEmul.img &lt;span class="nt"&gt;-partition_offset&lt;/span&gt; 16   &lt;span class="nt"&gt;--mbr-force-bootable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-append_partition&lt;/span&gt; 2 28732ac11ff8d211ba4b00a0c93ec93b ./BOOT/2-Boot-NoEmul.img   &lt;span class="nt"&gt;-appended_part_as_gpt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-iso_mbr_part_type&lt;/span&gt; a2a0d0ebe5b9334487c068b6b72699c7   &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'/boot.catalog'&lt;/span&gt;   &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s1"&gt;'/boot/grub/i386-pc/eltorito.img'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-boot-load-size&lt;/span&gt; 4 &lt;span class="nt"&gt;-boot-info-table&lt;/span&gt; &lt;span class="nt"&gt;--grub2-boot-info&lt;/span&gt;   &lt;span class="nt"&gt;-eltorito-alt-boot&lt;/span&gt;   &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'--interval:appended_partition_2:::'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"iso-deb&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iso"&lt;/span&gt; &lt;span class="nv"&gt;$iso_folder&lt;/span&gt;
            &lt;span class="k"&gt;else
                &lt;/span&gt;xorriso &lt;span class="nt"&gt;-as&lt;/span&gt; mkisofs &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-V&lt;/span&gt; &lt;span class="s2"&gt;"Unattended Custom Install"&lt;/span&gt; &lt;span class="nt"&gt;-J&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; isolinux/isolinux.bin &lt;span class="nt"&gt;-c&lt;/span&gt; isolinux/boot.cat &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-boot-load-size&lt;/span&gt; 4 &lt;span class="nt"&gt;-isohybrid-mbr&lt;/span&gt; /usr/lib/ISOLINUX/isohdpfx.bin &lt;span class="nt"&gt;-boot-info-table&lt;/span&gt; &lt;span class="nt"&gt;-input-charset&lt;/span&gt; utf-8 &lt;span class="nt"&gt;-eltorito-alt-boot&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-e&lt;/span&gt; boot/grub/efi.img &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-isohybrid-gpt-basdat&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"iso-deb&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iso"&lt;/span&gt; &lt;span class="nv"&gt;$iso_folder&lt;/span&gt;
            &lt;span class="k"&gt;fi
        fi&lt;/span&gt;    
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;sign_md5&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;iso_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
        &lt;span class="nb"&gt;md5sum&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$iso_folder&lt;/span&gt;&lt;span class="s2"&gt;/.disk/info"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$iso_folder&lt;/span&gt;&lt;span class="s2"&gt;/md5sum.txt"&lt;/span&gt;
        &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s|&lt;/span&gt;&lt;span class="nv"&gt;$iso_folder&lt;/span&gt;&lt;span class="s2"&gt;/|./|g"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$iso_folder&lt;/span&gt;&lt;span class="s2"&gt;/md5sum.txt"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;chroot_squash_folder_with_install_config&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;CHROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
        &lt;span class="c"&gt;# readarray -t repos &amp;lt; &amp;lt;(read_yaml_config '.repositories|values[]'|tr -d '"')&lt;/span&gt;
        readarray &lt;span class="nt"&gt;-t&lt;/span&gt; packages &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;read_yaml_config .install.apt_package_list[]|tr &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# TODO: implement cert install correctly&lt;/span&gt;
            curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://www.virtualbox.org/download/oracle_vbox_2016.asc &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/usr/share/keyrings/oracle-virtualbox-2016.gpg"&lt;/span&gt;
            curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/usr/share/keyrings/vscodium-archive-keyring.gpg"&lt;/span&gt;
            curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://apt.releases.hashicorp.com/gpg &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/usr/share/keyrings/hashicorp-archive-keyring.gpg"&lt;/span&gt;
        &lt;span class="c"&gt;# TODO: repositories are not still added in key valye manner:&lt;/span&gt;
        &lt;span class="c"&gt;# TODO: implementation: key: name of repo | value :string of repo&lt;/span&gt;

        &lt;span class="nb"&gt;chroot&lt;/span&gt; &lt;span class="nv"&gt;$CHROOT&lt;/span&gt; /bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"
            echo 'nameserver 8.8.8.8' &amp;gt; /etc/resolv.conf
            apt-get update
            DEBIAN_FRONTEND=noninteractive apt-get install -y &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
            apt-cache clean
            rm -rf /var/cache/apt/archives
            rm -rf /var/lib/apt/lists
            echo '' &amp;gt; /etc/resolv.conf
            history -c
        "&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#################################### utils ################################################3&lt;/span&gt;



&lt;span class="k"&gt;function &lt;/span&gt;is_root&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$EUID&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            return &lt;/span&gt;0
        &lt;span class="k"&gt;fi
        return &lt;/span&gt;1
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;check_dependencies&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONFIG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.dependencies_exists"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
            if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CONFIG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;fi
            if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$ID&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'debian'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$ID&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'ubuntu'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                &lt;/span&gt;&lt;span class="nv"&gt;INSTALLER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'apt-get'&lt;/span&gt;
            &lt;span class="k"&gt;else
                &lt;/span&gt;deco &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$_msg_not_support&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;exit &lt;/span&gt;1
            &lt;span class="k"&gt;fi
            for &lt;/span&gt;package &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPENDENCIES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="k"&gt;do
                    if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; which &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$package&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
                        &lt;span class="nv"&gt;$INSTALLER&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$package&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                    &lt;span class="k"&gt;fi
                done
        fi&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;read_yaml_config&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;config_table&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;array_list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;element &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;yq &lt;span class="nt"&gt;-r&lt;/span&gt; &amp;lt; &lt;span class="nv"&gt;$YAML&lt;/span&gt; &lt;span class="nv"&gt;$config_table&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;do 
                &lt;/span&gt;&lt;span class="nv"&gt;array_list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array_list&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$element&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;done
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array_list&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;function &lt;/span&gt;set_repositories&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nv"&gt;repo_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
        &lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/etc/apt/sources.list.d/&lt;/span&gt;&lt;span class="nv"&gt;$repo_name&lt;/span&gt;&lt;span class="s2"&gt;.list"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$repo_address&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;| &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/etc/apt/sources.list.d/&lt;/span&gt;&lt;span class="nv"&gt;$repo_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;is_exists&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;$_file&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
            return &lt;/span&gt;0
        &lt;span class="k"&gt;fi
        return &lt;/span&gt;1
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;########&lt;/span&gt;
&lt;span class="c"&gt;# Main  - _- _- _- _- _- _- _- Do Not Remove - _- _- _- _- _- _- _- _- _- _- _- _- _ &lt;/span&gt;
&lt;span class="c"&gt;########&lt;/span&gt;
main &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;[+] Note: In order to use &lt;strong&gt;OGUN&lt;/strong&gt;, configuration file is required, thus &lt;strong&gt;DO NOT try to RUN the script YET&lt;/strong&gt;.&lt;br&gt;
[+] Note: Configuration is suppose to be named &lt;code&gt;config.yaml&lt;/code&gt;, and for now it supports, only package install from repositories, and needs to be structured as associate dictinary including array of packages installed.&lt;br&gt;
[$] Explanation: I love using environment variables in conjunction with positional arguments and optional arguments, so as we continue to run commands, we'll also write &lt;strong&gt;bash&lt;/strong&gt; functions in most general way possible and combine them with types of variables mentioned before. All and all it will allow us to convert &lt;strong&gt;bash&lt;/strong&gt; functions in to shell based tool for manipulating ISO type files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although short article, it has a complex code, and lots of fixes to do, which you may follow on &lt;a href="https://gitlab.com/silent-mobius/ogun.git" rel="noopener noreferrer"&gt;gitlab&lt;/a&gt; and You may continue reading about using ogun in CI/CD with Jenkins in our &lt;a href=""&gt;next article&lt;/a&gt;&lt;br&gt;
Till then, remember: Do Try To Have Some Fun&lt;/p&gt;

</description>
      <category>bash</category>
      <category>jenkins</category>
      <category>ubuntu</category>
      <category>debian</category>
    </item>
    <item>
      <title>Automating ISO Customization with Jenkins and Shell Script</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Sun, 12 Nov 2023 14:55:11 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/automating-iso-customization-with-jenkins-and-shell-script-4goj</link>
      <guid>https://forem.com/vaiolabs_io/automating-iso-customization-with-jenkins-and-shell-script-4goj</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Articles&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/otomato_io/automating-iso-customization-with-jenkins-and-shell-script-4goj"&gt;ISO Customization&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dev.to/otomato_io/forging-ogun-with-bash-14pg"&gt;Forging With Bash&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=""&gt;Serve Chilled&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Welcome back gentle reader, I am Silent-Mobius, aka Alex M. Schapelle, your mechanical floating point calculator that will guide you with topics of open-source code and software.&lt;/p&gt;

&lt;p&gt;In one of my previous articles we talked about &lt;a href="https://dev.to/otomato_io/how-to-create-custom-debian-based-iso-4g37"&gt;Customizing Debian Based ISO's&lt;/a&gt;, in it we describe the steps for customizing Debian based operational system ISO, while disassembling ISO files, editing and configuring automated installation with &lt;code&gt;nocloud&lt;/code&gt;, which we covered in &lt;a href="https://dev.to/otomato_io/automating-custom-iso-with-cloud-init-2lc2"&gt;other article&lt;/a&gt;, adding repositories, tools and software for future use, and then packing it back to new ISO file for future use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Not Cubic ?
&lt;/h3&gt;

&lt;p&gt;Cubic is Ubuntu based &lt;strong&gt;Graphical Tool&lt;/strong&gt; for manual ISO manipulation, on which we have written previously short &lt;a href="https://dev.to/otomato_io/not-so-simple-plain-cubic-tutorial-1m5"&gt;tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Short answer: from short over view of the tool, it can not be used on terminal, meaning --&amp;gt; it can not be embedded inside CI/CD that we are aiming at.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self Check
&lt;/h3&gt;

&lt;p&gt;After re-reading the article, in an attempt to update the article, yes - quarterly we check our own articles to see if there is a case to adding/updating with new data, several things popped out to me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doing everything manually is tire some&lt;/li&gt;
&lt;li&gt;Dependencies are confusing&lt;/li&gt;
&lt;li&gt;Steps are not clear&lt;/li&gt;
&lt;li&gt;Reproducing the procedure without article is some what hard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like any other mechanic calculator, once reached all zeros, I'll have to restart counting numbers, so why not to do it with  more suitable tools ?&lt;br&gt;
Here's my choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bash Script&lt;/strong&gt; : Cause supported by any *nix system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jenkins&lt;/strong&gt; : Cause of the automation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debian&lt;/strong&gt; : Cause IMPO there is no better *nix based system (RedHat kind of disappointed me)
The tools I've chosen are basic, yet provide clear basics for SysOps, DevOps, SysAdmin and anyone who can use *nix based systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Great Plan
&lt;/h2&gt;

&lt;p&gt;To plan our work we'll use steps from previous essays, with clear directions on what we want to create and eventually implement those direction with previously mentioned tools. Automation is the key to getting the software working, thus we'll combined Jenkins and bash script creating dual element tool for creating automated ISO editor.&lt;br&gt;
The plan itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write the steps&lt;/li&gt;
&lt;li&gt;Setup up development environment&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;Tool&lt;/code&gt; for editing ISO&lt;/li&gt;
&lt;li&gt;Setup CI/CD for automating dynamic values for our &lt;code&gt;tool&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Write the steps
&lt;/h3&gt;

&lt;p&gt;ISO stands for &lt;a href="https://en.wikipedia.org/wiki/International_Organization_for_Standardization" rel="noopener noreferrer"&gt;&lt;em&gt;International Organization for Standardization&lt;/em&gt;&lt;/a&gt; which is governing body that develops and publishes standardization in all technical and nontechnical fields other than electrical and electronic engineering, which is handled by the &lt;a href="https://en.wikipedia.org/wiki/International_Electrotechnical_Commission" rel="noopener noreferrer"&gt;IEC&lt;/a&gt;. ISO number 9660 is a file system for optical disc media, which was used for arranged file information in a dense, sequential layout... AKA ISO format Operational System.&lt;br&gt;
To put it to human term: ISO is just a way the tree folder structure is compressed and arranged. Sound like zip file, right ? &lt;br&gt;
But that is enriching  information, the steps to handle ISO file are as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disassemble&lt;/strong&gt; ISO file by extracting it to folder with &lt;code&gt;7z&lt;/code&gt; tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un-squash&lt;/strong&gt; the squash-sf file that holds the install-able  file system with &lt;code&gt;unsquashfs&lt;/code&gt; from &lt;code&gt;squashfs-tools&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modify&lt;/strong&gt; files, users, groups, binaries and configuration with your required tools and utilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean up&lt;/strong&gt; the changes to reduce size of ISO&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make squash&lt;/strong&gt; file to replace initial squash-fs file with &lt;code&gt;mksquash&lt;/code&gt; from &lt;code&gt;squashfs-tools&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repack&lt;/strong&gt; extracted folder with &lt;code&gt;xirroso&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seems to me that we have here something that looks like a plan, wouldn't you agree ? Let's go on by setting a working environment with required dependencies and dedicated explanations.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup up development environment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Some Assumptions/My Setup&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are using Debian based Linux distribution&lt;/li&gt;
&lt;li&gt;Any text editor is fine as long as you know how to operate it.&lt;/li&gt;
&lt;li&gt;We'll need couple ISO's of &lt;a href="https://cdimage.debian.org/debian-cd/12.1.0-live/amd64/iso-hybrid/debian-live-12.1.0-amd64-standard.iso" rel="noopener noreferrer"&gt;Debian&lt;/a&gt; and &lt;a href="https://releases.ubuntu.com/22.04.3/ubuntu-22.04.3-live-server-amd64.iso" rel="noopener noreferrer"&gt;Ubuntu&lt;/a&gt; to test all we are working with.&lt;/li&gt;
&lt;li&gt;We have short list of packages that we'll need to have installed:

&lt;ul&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;p7zip-full&lt;/li&gt;
&lt;li&gt;squashfs-tools&lt;/li&gt;
&lt;li&gt;genisoimage &lt;/li&gt;
&lt;li&gt;fakeroot&lt;/li&gt;
&lt;li&gt;pwgen&lt;/li&gt;
&lt;li&gt;whois&lt;/li&gt;
&lt;li&gt;xorriso&lt;/li&gt;
&lt;li&gt;isolinux&lt;/li&gt;
&lt;li&gt;binutils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's install them, so not miss it future:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; p7zip-full git genisoimage fakeroot pwgen whois xorriso isolinux binutils squashfs-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And while at it, let us get ISO files of the Linux Distributions that we are gonna work on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://mirror.isoc.org.il/pub/ubuntu-releases/22.04.3/ubuntu-22.04.3-live-server-amd64.iso &lt;span class="nt"&gt;-o&lt;/span&gt; ~/Projects/ogun/ubuntu-22.04.3-live-server-amd64.iso

curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://gemmei.ftp.acc.umu.se/debian-cd/12.1.0-live/amd64/iso-hybrid/debian-live-12.1.0-amd64-standard.iso &lt;span class="nt"&gt;-o&lt;/span&gt; ~/Projects/ogun/debian-live-12.1.0-amd64-standard.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IMHO, it is always good to have dedicated folder where we havoc our way into those ISO's. Let's call our small project with catchy code name of &lt;code&gt;OGUN&lt;/code&gt;, a spirit that appears in several African religions, mostly as &lt;a href="https://en.wikipedia.org/wiki/Ogun" rel="noopener noreferrer"&gt;diety of blacksmiths and techonologists&lt;/a&gt;, and if it does not make sense to you then no need to dive into it.&lt;/p&gt;

&lt;p&gt;While inside the folder, let us save our code and files with &lt;code&gt;git version control&lt;/code&gt; on our &lt;a href="https://gitlab.com/silent-mobius/ogun" rel="noopener noreferrer"&gt;gitlab repository&lt;/a&gt; to keep track of things during our explorations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; Projects/ogun
git init
git config user.name &lt;span class="s1"&gt;'silent-mobius'&lt;/span&gt;
git config user.email &lt;span class="s1"&gt;'alexm@otomato.io'&lt;/span&gt;
git remote add origin https://gitlab.com/silent-mobius/ogun.git
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Project Ogun"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; README.md
&lt;span class="c"&gt;# adding gitignore for future use&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\*&lt;/span&gt;&lt;span class="s2"&gt;.iso"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .gitignore
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"iso"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .gitignore
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"squashfs-root"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .gitignore
git add README.md .gitignore
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"adding README file"&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin https://gitlab.com/silent-mobius/ogun.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Back to the topic : &lt;strong&gt;Disassemble&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;As mentioned, ISO is just a way the tree folder structure is compressed and arranged. Sounds like zip file...&lt;br&gt;
What can we do with zip files: zip and unzip. One of the easiest open source &lt;strong&gt;tool&lt;/strong&gt; for zip/unzip files, available for all platforms, is &lt;strong&gt;p7zip&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;To &lt;code&gt;unzip&lt;/code&gt; or to be precise &lt;code&gt;export&lt;/code&gt; ISO file we can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;7z x &lt;span class="nt"&gt;-y&lt;/span&gt; debian-live-12.1.0-amd64-standard.iso &lt;span class="nt"&gt;-oiso&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command be translated as follows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;7z&lt;/code&gt; : Binary for 7zip&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt;  : eXtract files with full paths&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-y&lt;/code&gt; : Assume Yes on all queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-o&lt;/code&gt; : Set Output directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are working with my direction, then under our project folder we'll be able to find new folder named &lt;code&gt;iso&lt;/code&gt; that will include the content of the Debian ISO we have previously downloaded.&lt;/p&gt;

&lt;p&gt;The same command can be transcribed as shell script function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;disassemble_iso&lt;span class="o"&gt;(){&lt;/span&gt; 
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="c"&gt;# full path is required ...&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
            7z x &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nv"&gt;$IN&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;[!] Incoming Notice : you promised tool, why just running commands?&lt;/strong&gt;&lt;br&gt;
Indeed, no need to just write commands, lets build something with them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'll be writing the full script with descriptions in the next segment, and till then we'll cover the steps and how we can automate them in &lt;code&gt;shell&lt;/code&gt; functions...&lt;/li&gt;
&lt;li&gt;Lets create script named &lt;code&gt;ogun.sh&lt;/code&gt; that will be converted as shell tool.&lt;/li&gt;
&lt;li&gt;I prefer to use headers in my script, so in case something not clear, ask in comments below&lt;/li&gt;
&lt;li&gt;My shell scripts are written in functional programming pattern, thus if not clear, you are welcome to ask questions, in comments and open PR/MR in &lt;a href="https://gitlab.com/silent-mobius/ogun.git" rel="noopener noreferrer"&gt;gitlab repository&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;[!] Note: I might rewrite the tool in new programming language, thus if you'll search for shell/bash script equivalent, I'll be saving branch with dedicated name for you to use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Un-squash&lt;/strong&gt; the  filesystem
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/SquashFS" rel="noopener noreferrer"&gt;Squashfs&lt;/a&gt; is a compressed read-only file system and it includes compressed files, inodes and directories under one file. Most of Linux based distributions are using it during the install process and it is the core of what you'll be using in your hardware.&lt;/p&gt;

&lt;p&gt;Thus we need to open the sqyashfs filesystem, in order to make necessary changes. Usually it is done with &lt;code&gt;unsquashfs&lt;/code&gt; tool and most common way to use it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;iso/live/filesystem.squashfs &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="c"&gt;# include the dot at the end&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;unsquashfs filesystem.squashfs
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; filesystem.squashfs
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We are removing the original &lt;code&gt;filesystem.squashfs&lt;/code&gt; file, so we won't be confused later on.&lt;/li&gt;
&lt;li&gt;Once unsquashed, &lt;code&gt;ls&lt;/code&gt; command should show us new folder named &lt;code&gt;squashfs-root&lt;/code&gt;, yet you can rename to anything else with &lt;code&gt;-d&lt;/code&gt; option in case you would like to use different name (from my experience while writing this article, it is not suggested)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To translate it in to shell function it could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;disassemble_squashfile&lt;span class="o"&gt;(){&lt;/span&gt; 
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="c"&gt;# full path to squashfs file&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt; &lt;span class="c"&gt;# where to export the file&lt;/span&gt;
            &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            unsquashfs &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"./&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;[!] I'll probably modify variable names later to be more &lt;code&gt;readable&lt;/code&gt; - I'll present it all when we get to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Let's &lt;strong&gt;Modify&lt;/strong&gt; the unsquashfs filesystem
&lt;/h4&gt;

&lt;p&gt;When it comes to &lt;strong&gt;modification&lt;/strong&gt;, it is really up to the modifier him/her selves to decide what and how they want the changes. Yet I'll still share my insight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DO NOT CREATE YOUR OWN USER: the install process will remain the same, thus no point adding your own user

&lt;ul&gt;
&lt;li&gt;However you can setup your custom configurations to user skeleton of the system

&lt;ul&gt;
&lt;li&gt;Set your changes in &lt;code&gt;.profile&lt;/code&gt; or &lt;code&gt;.bashrc&lt;/code&gt; in &lt;code&gt;squashfs-root/etc/skel/&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Configure custom prompt variable.&lt;/li&gt;
&lt;li&gt;Add your aliases.&lt;/li&gt;
&lt;li&gt;Extend &lt;code&gt;PATH&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;Install packages and binaries.&lt;/li&gt;
&lt;li&gt;if you use vim, then add &lt;code&gt;.vimrc&lt;/code&gt; configuration file.&lt;/li&gt;
&lt;li&gt;Not my preference, yet you can add ssh-keys in here.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Less talking more coding:

&lt;ul&gt;
&lt;li&gt;When doing changes remember that you are &lt;strong&gt;changing your root&lt;/strong&gt; folder, meaning that we need to login in to read-only filesystem with &lt;code&gt;chroot&lt;/code&gt; command, which runs a specified commands with a specified root directory (squashfs-root in our case)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chroot &lt;/span&gt;squashfs-root &lt;span class="c"&gt;# prompt should change&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/skel

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'set nocompatible
set number
colorscheme desert
if has("syntax")
  syntax on
endif
'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .vimrc

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'PATH=$PATH:/usr/local/bin:/usr/local/sbin'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .bashrc &lt;span class="c"&gt;#extending PATH variable&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PS1='&lt;/span&gt;&lt;span class="se"&gt;\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[01;32m&lt;/span&gt;&lt;span class="se"&gt;\]\u\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[00m&lt;/span&gt;&lt;span class="se"&gt;\]&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="se"&gt;\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[01;32m&lt;/span&gt;&lt;span class="se"&gt;\]\h&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[00m&lt;/span&gt;&lt;span class="se"&gt;\]\w\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[01;34m&lt;/span&gt;&lt;span class="se"&gt;\]&lt;/span&gt;&lt;span class="s2"&gt; [&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git symbolic-ref &lt;span class="nt"&gt;--short&lt;/span&gt; HEAD 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\[\0&lt;/span&gt;&lt;span class="s2"&gt;33[00m&lt;/span&gt;&lt;span class="se"&gt;\]\n&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .bashrc

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
alias cl='clear'
alias cp='cp -v'
alias g='git'
alias ga='git add'
alias gc='git clone'
alias gp='git push'
alias gpo='git push -u origin'
alias k='kubectl'
alias kd='kubectl describe'
alias kg='kubectl get'
alias kgn='kubectl get nodes'
alias kgp='kubectl get pods'
alias l='ls'
alias ll='ls -l'
alias ls='ls --color=auto'
alias mv='mv -v'
alias vi='vim'
"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .bashrc 

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'nameserver 8.8.8.8'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/resolv.conf &lt;span class="c"&gt;# squashfs does not recongnized the network automatically&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list


apt-get update

apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential task-cinnamon-desktop plank arp-scan guake plank geany meld moka-icon-theme wireshark ethtool arp-scan nmap python3-nmap vlc nala macchanger nmap etherape git gitg gnupg2 curl cmake ipython3 vim libvirt-daemon p7zip-full plymouth plymouth-themes remmina libvirt-daemon-system virtinst bridge-utils python3-networkmanager python3-networkx vagrant vagrant-libvirt python3-netmiko python3-netifaces python3-netaddr gir1.2-gtop-2.0 glade terminator vlc virt-manager bash-completion darkslide python-landslide jq yq tomlq pipx

&lt;span class="c"&gt;# All binary installation will require manual changes because by default they are installed to user root&lt;/span&gt;

curl &lt;span class="nt"&gt;-sL&lt;/span&gt; get.sdkman.io | bash &lt;span class="c"&gt;# this is installed into /root folder in squashfs-root system&lt;/span&gt;

&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ~/.sdkman/ /etc/skel/ &lt;span class="c"&gt;# we are copying the system to spread on whole system&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] &amp;amp;&amp;amp; source "$HOME/.sdkman/bin/sdkman-init.sh"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/skel/.bashrc &lt;span class="c"&gt;# adding sdkman init script to path&lt;/span&gt;

curl &lt;span class="nt"&gt;-sL&lt;/span&gt; install.python-poetry.org | python3 -

curl &lt;span class="nt"&gt;-sL&lt;/span&gt; get.docker.com | bash

curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 &lt;span class="nt"&gt;-O&lt;/span&gt; /usr/local/bin/minikube

&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /usr/local/bin/minikube 

&lt;span class="c"&gt;#installing vscodium &lt;/span&gt;
wget &lt;span class="nt"&gt;-qO&lt;/span&gt; - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/keyrings/vscodium-archive-keyring.gpg

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://download.vscodium.com/debs vscodium main'&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/vscodium.list

apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; codium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Yes, indeed I love installing packages and binaries&lt;/li&gt;
&lt;li&gt;All the commands above are more or less the changes I use for creating my custom Debian ISO's&lt;/li&gt;
&lt;li&gt;And I admit: It does look like mess, much less how it can be automated with bash script, yet here is a function I use myself:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;configure_squashfs_folder&lt;span class="o"&gt;(){&lt;/span&gt;
&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;CHROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
      curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHROOT&lt;/span&gt;&lt;span class="s2"&gt;/usr/share/keyrings/vscodium-archive-keyring.gpg"&lt;/span&gt;
      curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;$CHROOT&lt;/span&gt;/usr/local/bin/minikube
      &lt;span class="nb"&gt;chmod&lt;/span&gt; +x &lt;span class="nv"&gt;$CHROOT&lt;/span&gt;/usr/local/bin/minikube
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'\n
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware \n
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware \n
deb http://security.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware \n
deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware \n
'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$CHROOT&lt;/span&gt;/etc/apt/sources.list

&lt;span class="nb"&gt;chroot&lt;/span&gt; &lt;span class="nv"&gt;$CHROOT&lt;/span&gt; /bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"
     echo 'nameserver 8.8.8.8' &amp;gt; /etc/resolv.conf
     apt-get update
     DEBIAN_FRONTEND=noninteractive apt-get install -y apt-get install -y build-essential task-cinnamon-desktop plank arp-scan guake plank geany meld moka-icon-theme wireshark ethtool arp-scan nmap python3-nmap vlc nala macchanger nmap etherape git gitg gnupg2 cmake ipython3 vim libvirt-daemon p7zip-full plymouth plymouth-themes remmina libvirt-daemon-system virtinst bridge-utils python3-networkmanager python3-networkx vagrant vagrant-libvirt python3-netmiko python3-netifaces python3-netaddr gir1.2-gtop-2.0 glade terminator vlc virt-manager bash-completion darkslide python-landslide jq yq tomlq pipx
"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I do agree that function looks mess as well

&lt;ul&gt;
&lt;li&gt;Yet I do promise we'll clean it up with more general script&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;BTW: we are all done... (are we though?)&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Every mess needs &lt;strong&gt;Cleanup&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;All the changes we made will increase the size of the squash-filesystem, and like after long evening of cooking with kids (which I don't have), we do have something to show, like they have on &lt;a href="https://en.wikipedia.org/wiki/Nailed_It!" rel="noopener noreferrer"&gt;nailed it&lt;/a&gt;, yet one thing that we are not shown is the clean up that happens after the show and which is what we need to do, in order to ensure clean filesystem. Mostly useful steps would be to remove temporary files, removing caches and packages, and of course, clear the history.&lt;br&gt;
So, while we are &lt;strong&gt;still in chrooted environment&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We still need to be in chrooted environment&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /var
&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="c"&gt;# If there is anything too big --&amp;gt; rm -rf that&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; cache/apt/apt/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; lib/apt/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  We came, we saw, we &lt;strong&gt;Resquash&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Once the clean up is done we need to to recompress everything back to what is was before, and thus we do it by exiting squahs chroot environment and use &lt;code&gt;mksquashfs&lt;/code&gt; to generate new read-only filesystem to use for our  ISO.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="c"&gt;# to exit from chroot&lt;/span&gt;
mksquashfs ./squashfs-root/ filesystem.squashfs &lt;span class="nt"&gt;-comp&lt;/span&gt; xz &lt;span class="nt"&gt;-b&lt;/span&gt; 1M &lt;span class="nt"&gt;-noappend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;./squashfs-root/&lt;/code&gt; : the folder which we updated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filesystem.squashfs&lt;/code&gt;: the name we are giving to new filesystem.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mkdquashfs&lt;/code&gt;: tool to create and append to squashfs filesystems&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-comp&lt;/code&gt; : select compression algorythm: we use &lt;code&gt;xz&lt;/code&gt; to maximlize on compression&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-b&lt;/code&gt; : set data block to 1 in our case.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-noappend&lt;/code&gt; : do not append to existing filesystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;[!] Note: This will use all cores on your CPU, just be paitient with it, by the end of it, the file will be generated and we have to return it to its rightful place:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;filesystem.squashfs iso/live/filesystem.squashfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will place the filesystem.squashfs file back where we took it from and now all is left is &lt;/p&gt;

&lt;p&gt;The shell script representation of is pretty simple and looks mostly like other functions we wrote up until now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OUT_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"iso/live/"&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;reassemble_squashfile&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
        mksquashfs &lt;span class="nv"&gt;$IN&lt;/span&gt; &lt;span class="nv"&gt;$OUT&lt;/span&gt; &lt;span class="nt"&gt;-comp&lt;/span&gt; xz &lt;span class="nt"&gt;-b&lt;/span&gt; 1M &lt;span class="nt"&gt;-noappend&lt;/span&gt;
        &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="nv"&gt;$OUT&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# [!] Note: the variable OUT_FOLDER is set outside of the function and should be used as a global variable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Recap for the &lt;strong&gt;REPACK&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;So to sum it up:&lt;br&gt;
 We have &lt;code&gt;iso&lt;/code&gt; folder that includes new read-only &lt;code&gt;filesystem.squashfs&lt;/code&gt; file with all the changes, tools and what not. All we need is Love ... that's different song... All we need is to &lt;strong&gt;repack&lt;/strong&gt; the &lt;code&gt;iso&lt;/code&gt; folder to convert is back to ISO.&lt;br&gt;
To do so, we'll sign the changes on the &lt;code&gt;iso&lt;/code&gt; folder with new md5sha256 signiture - we do not want to recieve warnings about security issues while installing the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;md5sum &lt;/span&gt;iso/.disk/info &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; iso/md5sum.txt
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s|iso/|./|g"&lt;/span&gt;  iso/md5sum.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to save it as a bash shell function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ISO_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"iso/"&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;sign_md5&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nb"&gt;md5sum&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;/.disk/info &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;/md5sum.txt
        &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s|&lt;/span&gt;&lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;/|./|g"&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;/md5sum.txt
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now - to repack it all, we'll be using &lt;code&gt;xorriso&lt;/code&gt; tool and &lt;code&gt;isolinux&lt;/code&gt; library which in terms of command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xorriso &lt;span class="nt"&gt;-as&lt;/span&gt; mkisofs &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-V&lt;/span&gt; &lt;span class="s2"&gt;"Custom  Debian12 Install"&lt;/span&gt; &lt;span class="nt"&gt;-J&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; isolinux/isolinux.bin &lt;span class="nt"&gt;-c&lt;/span&gt; isolinux/boot.cat &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt;                &lt;span class="nt"&gt;-boot-load-size&lt;/span&gt; 4 &lt;span class="nt"&gt;-isohybrid-mbr&lt;/span&gt; /usr/lib/ISOLINUX/isohdpfx.bin &lt;span class="nt"&gt;-boot-info-table&lt;/span&gt; &lt;span class="nt"&gt;-input-charset&lt;/span&gt; utf-8 &lt;span class="nt"&gt;-eltorito-alt-boot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; boot/grub/efi.img &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-isohybrid-gpt-basdat&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"custom-iso-deb12.iso"&lt;/span&gt; ./iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;xorriso&lt;/code&gt; : Xorriso  is  a  program which copies file objects from POSIX compliant filesystems into Rock Ridge enhanced ISO 9660 filesystems and performs session-wise manipulation of such filesystems.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-as&lt;/code&gt; : Xorriso can emulate other software for creating ISO filesystems. Emulation enables other features to be enabled in one tool&lt;/li&gt;
&lt;li&gt;mkisofs: One of the most used format which xorriso can emulate. &lt;strong&gt;below&lt;/strong&gt; options are combinations of &lt;strong&gt;xorriso&lt;/strong&gt; and of &lt;strong&gt;mkisofs&lt;/strong&gt; .&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt;: &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-V&lt;/code&gt;: short for add tag message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-J&lt;/code&gt;: amount of cores to use for job, uses most in case no value is provided&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-b&lt;/code&gt;: short for -boot_image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c&lt;/code&gt;: short for execute command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-no-emul-boot&lt;/code&gt;:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-boot-load-size&lt;/code&gt;:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-isohybrid-mbr&lt;/code&gt;: add isohybrid headers for bootloader&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-boot-info-table&lt;/code&gt;: update boot table&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;input-charset&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;eltorito-alt-boot&lt;/code&gt;: add eltorito alternative boot for bootloader&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-e&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;isohybrid-gpt-basdat&lt;/code&gt;: add isohybrid-gpt headers for bootloader&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-o&lt;/code&gt;: output the generated data into file named with value provided&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After few minutes of running it should generate ISO file with all the needed changes and ready to be test, used, deployed and once again modified for future use-cases.&lt;/p&gt;

&lt;p&gt;The issue with that long and complicated command is that it not as easy to know whether you need all those features in your ISO file. There can be lots of cases that command will be much less complicated, yet also vice versa, much much more complicated. Thanks to &lt;a href="https://gist.github.com" rel="noopener noreferrer"&gt;dbkinghorn&lt;/a&gt; efforts one way to know what features you might need is to &lt;a href="https://www.pugetsystems.com/labs/hpc/ubuntu-22-04-server-autoinstall-iso/" rel="noopener noreferrer"&gt;check how the initial ISO was created&lt;/a&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xorriso &lt;span class="nt"&gt;-indev&lt;/span&gt; debian-live-12.1.0-amd64-standard.iso &lt;span class="nt"&gt;-report_el_torito&lt;/span&gt; as_mkisofs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command  will output the setup the arguments for building an ISO file, which you can copy paste and use for your own build.&lt;/p&gt;

&lt;p&gt;As a shell function the command it depends on the ISO that you are using, in this example for Debian the command provided above is fine, and for Ubuntu 20.04 it will work as well, in case of Ubuntu 22.04 it shall fail, so the function, for now at least, will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ISO_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"iso/"&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;reassemble_iso&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 2 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
            &lt;/span&gt;deco &lt;span class="nv"&gt;$_msg_reassemble_error&lt;/span&gt; 
            &lt;span class="nb"&gt;exit &lt;/span&gt;1
        &lt;span class="k"&gt;else
            if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 22 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;then
                &lt;/span&gt;xorriso &lt;span class="nt"&gt;-as&lt;/span&gt; mkisofs  &lt;span class="nt"&gt;-r&lt;/span&gt;   &lt;span class="nt"&gt;-V&lt;/span&gt; &lt;span class="s1"&gt;'Unattended Custom Install'&lt;/span&gt;  &lt;span class="nt"&gt;--grub2-mbr&lt;/span&gt; ./BOOT/1-Boot-NoEmul.img &lt;span class="nt"&gt;-partition_offset&lt;/span&gt; 16   &lt;span class="nt"&gt;--mbr-force-bootable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-append_partition&lt;/span&gt; 2 28732ac11ff8d211ba4b00a0c93ec93b ./BOOT/2-Boot-NoEmul.img   &lt;span class="nt"&gt;-appended_part_as_gpt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-iso_mbr_part_type&lt;/span&gt; a2a0d0ebe5b9334487c068b6b72699c7   &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'/boot.catalog'&lt;/span&gt;   &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s1"&gt;'/boot/grub/i386-pc/eltorito.img'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-boot-load-size&lt;/span&gt; 4 &lt;span class="nt"&gt;-boot-info-table&lt;/span&gt; &lt;span class="nt"&gt;--grub2-boot-info&lt;/span&gt;   &lt;span class="nt"&gt;-eltorito-alt-boot&lt;/span&gt;   &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'--interval:appended_partition_2:::'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"iso-deb&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iso"&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;
            &lt;span class="k"&gt;else
                &lt;/span&gt;xorriso &lt;span class="nt"&gt;-as&lt;/span&gt; mkisofs &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-V&lt;/span&gt; &lt;span class="s2"&gt;"Unattended Custom Install"&lt;/span&gt; &lt;span class="nt"&gt;-J&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; isolinux/isolinux.bin &lt;span class="nt"&gt;-c&lt;/span&gt; isolinux/boot.cat &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-boot-load-size&lt;/span&gt; 4 &lt;span class="nt"&gt;-isohybrid-mbr&lt;/span&gt; /usr/lib/ISOLINUX/isohdpfx.bin &lt;span class="nt"&gt;-boot-info-table&lt;/span&gt; &lt;span class="nt"&gt;-input-charset&lt;/span&gt; utf-8 &lt;span class="nt"&gt;-eltorito-alt-boot&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nt"&gt;-e&lt;/span&gt; boot/grub/efi.img &lt;span class="nt"&gt;-no-emul-boot&lt;/span&gt; &lt;span class="nt"&gt;-isohybrid-gpt-basdat&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"iso-deb&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;system_version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iso"&lt;/span&gt; &lt;span class="nv"&gt;$ISO_FOLDER&lt;/span&gt;
            &lt;span class="k"&gt;fi
        fi&lt;/span&gt;    
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Discouraging - I agree, but we'll find our way around it later.&lt;/p&gt;

&lt;p&gt;Just to mid-sum it up :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We went and discovered how Linux Distribution ISO is structured.&lt;/li&gt;
&lt;li&gt;Learned that we can disassemble it.&lt;/li&gt;
&lt;li&gt;Studied to modify the filesystem.&lt;/li&gt;
&lt;li&gt;Dwell on how to reassemble same ISO.&lt;/li&gt;
&lt;li&gt;Grasped important parts of ISO structs.&lt;/li&gt;
&lt;li&gt;Wrote automation with bash script functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, all is left for us, is assembly of the &lt;code&gt;Tool&lt;/code&gt;...&lt;br&gt;
Which we will do in &lt;a href="https://dev.to/otomato_io/forging-ogun-with-bash-14pg"&gt;next article&lt;/a&gt;&lt;br&gt;
Until that time comes, remember: Do Try To Have Some Fun&lt;/p&gt;

</description>
      <category>bash</category>
      <category>jenkins</category>
      <category>ubuntu</category>
      <category>debian</category>
    </item>
    <item>
      <title>When you run after the horse in the rabbit whole</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Tue, 01 Aug 2023 15:41:32 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/when-you-run-after-the-horse-in-the-rabbit-whole-5bjk</link>
      <guid>https://forem.com/vaiolabs_io/when-you-run-after-the-horse-in-the-rabbit-whole-5bjk</guid>
      <description>&lt;p&gt;Welcome dear reader, I am Silent-Mobius, AKA Alex M. Schapelle, your faithful &lt;a href="https://warhammer40k.fandom.com/wiki/Servitor" rel="noopener noreferrer"&gt;servitor&lt;/a&gt; that continues to lead with examples of learning of new topics with trials and errors.&lt;/p&gt;

&lt;p&gt;As mentioned in our &lt;a href="https://dev.to/otomato_io/learn-redis-or-how-devops-had-to-do-back-end-work-4fi"&gt;previous encounter&lt;/a&gt;, I have started to dwell into world of databases, by exploring two main types which are NoSQL and RDBMS, mainly talking about MySQL and Redis. About why I am doing this, we'll explore later, as on this  entry we'll mostly discuss the architecture as mentioned before  and according to table of content: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Learn Redis With Project&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Roadmap Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project&lt;/td&gt;
&lt;td&gt;Create architecture&lt;/td&gt;
&lt;td&gt;We are Here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Create application and Version control&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Learn basics of Redis and implement with application&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Micro Services&lt;/td&gt;
&lt;td&gt;Set all local development env with docker-compose&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration to K8S&lt;/td&gt;
&lt;td&gt;Setup k8s manifests and generate helm chart&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let create a small diagram that will illustrate what we are going to create:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rhb9dxhhqvqyy0fkli7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rhb9dxhhqvqyy0fkli7.png" alt="Image description" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll be using docker containers to pack our application, and deploy the packed images into container registry. Within Gilab-CI we'll work on our code, and in case it will pass, it will start new pipeline that will deploy on test network with docker compose the scaled application, Redis-cluster and PostgreSQL-cluster.&lt;/p&gt;

&lt;p&gt;There will be configuration files for Redis to store data  with SQL server and in term, SQL server with be saving data to volume that will be saved under backed up volume... it seems there will be a lot of configuration to be done, either with &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;Bash&lt;/code&gt; or &lt;code&gt;Ansible&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The architecture is inspired by &lt;a href="https://twitter.com/alexxubyte" rel="noopener noreferrer"&gt;Alex Xu&lt;/a&gt; book named &lt;a href="https://www.amazon.com/gp/product/B08CMF2CQF/ref=as_li_qf_asin_il_tl?ie=UTF8&amp;amp;tag=sandordargo-20&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=B08CMF2CQF&amp;amp;linkId=6bd98a7b06a1165368754af945bae169" rel="noopener noreferrer"&gt;System Design Interview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see there are a lot of things to setup, create, manage, provide and deploy, thus here is a list of things that I am going to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Language: &lt;code&gt;Python&lt;/code&gt;, mostly due to the development can be fast and in this case I'd prefer to focus on learning DB and Cache part more then learning new programming language.&lt;/li&gt;
&lt;li&gt;Version Control: &lt;code&gt;Git&lt;/code&gt;, the application is not going to be that big, in addition today git is the de facto the best choice for code version control, which is also incorporated within CI&lt;/li&gt;
&lt;li&gt;CI : &lt;code&gt;Gitlab-CI&lt;/code&gt;, Because my github account got locked and the support suggested to destroy the account but not open it for me, thus they lost me as a customer.&lt;/li&gt;
&lt;li&gt;RDBMS: &lt;code&gt;PostGreSQL&lt;/code&gt;, mostly to master the automation of main and secondary installation with &lt;code&gt;Python&lt;/code&gt; as well as auto-database setup or connection with new instance.&lt;/li&gt;
&lt;li&gt;NoSQL: &lt;code&gt;Redis&lt;/code&gt;, to learn the caching mechanism provided by Alex's book&lt;/li&gt;
&lt;li&gt;Micro-Services: &lt;code&gt;Docker&lt;/code&gt; and &lt;code&gt;Docker Compose&lt;/code&gt;, for only development purposes, eventually we'll create k8s deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although I've been working as IT professional for 15 years, and have been working on these systems separately, It never occurred to me that I need to connect them by myself, mostly because we used to work with waterfall methodology and guilt, along side new application version was dropped down at us to handle by development team. Our Dev team were cool guys and were always there to help, but lack of knowledge and experience of high-level programming languages made it very hard to determine to whom we should consult for aid.&lt;br&gt;
When idea to learn &lt;em&gt;enough programming to do tasks popped up&lt;/em&gt;, though it was there for some time, with it came uncertain choice: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Perl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ruby&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Python&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Node.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which one to use ?&lt;/p&gt;

&lt;p&gt;I chose &lt;code&gt;Ruby&lt;/code&gt; which in long run, was somewhat incorrect choice, and moving to python from it was not hard but a very long and confusing journey.&lt;br&gt;
Today I stumble to same dilemma, whether to use &lt;code&gt;Go&lt;/code&gt; or &lt;code&gt;Rust&lt;/code&gt;, to which I've chosen &lt;code&gt;Go&lt;/code&gt;... but this is for another article.&lt;/p&gt;

&lt;p&gt;All the other automation I've done, was mostly with &lt;code&gt;shell&lt;/code&gt; or &lt;code&gt;Bash&lt;/code&gt;, with Linux Built-in tools, which eventually turned into &lt;code&gt;Cloud-init&lt;/code&gt;, &lt;code&gt;Puppet and&lt;/code&gt;Ansible`, thus burdening myself with SQL or NoSQL, was never the issue for me, to what I somewhat regret.&lt;br&gt;
Thus this is where I start to learn ... and hope you will learn with me. No matter what, Please Do Try To Enjoy &lt;/p&gt;

&lt;p&gt;Till next time&lt;/p&gt;

</description>
      <category>python</category>
      <category>redis</category>
      <category>mysql</category>
      <category>docker</category>
    </item>
    <item>
      <title>Learn Redis Or How DevOps Had To Do Back-End Work</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Sat, 22 Jul 2023 16:03:01 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/learn-redis-or-how-devops-had-to-do-back-end-work-4fi</link>
      <guid>https://forem.com/vaiolabs_io/learn-redis-or-how-devops-had-to-do-back-end-work-4fi</guid>
      <description>&lt;p&gt;Welcome dear reader, I am Silent-Mobius, AKA Alex M. Schapelle, your devoted mechanical puppet that will lead with example of going through the learning of new topic.&lt;/p&gt;

&lt;p&gt;As part of trying to understand back-end developers suffering, I have devised a plan to embark onto journey of building  python based micro-service application with local development on docker-compose and stage/prod deployment to Kubernetes with helm chart.&lt;/p&gt;

&lt;p&gt;Yet, all that we already know how to do. What is missing database interaction, which I would like to get better at. Thus I have decided to learn Redis and to develop with it my home page application on : &lt;a href="https://aschapelle.com" rel="noopener noreferrer"&gt;My Web-Site&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned I have a plan that looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Learn Redis With Project&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project&lt;/td&gt;
&lt;td&gt;Create architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Create application and Version control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Learn basics of Redis and implement with application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Micro Services&lt;/td&gt;
&lt;td&gt;Set all local development env with docker-compose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration to K8S&lt;/td&gt;
&lt;td&gt;Setup k8s manifests and generate helm chart&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This will be for starters. Hope that this makes you hyped as I am at the moment. Thus follow my example and do try to have some fun.&lt;/p&gt;

</description>
      <category>database</category>
      <category>python</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Manage Calendar &amp; Address Book Micro-services</title>
      <dc:creator>Alex M. Schapelle</dc:creator>
      <pubDate>Tue, 28 Mar 2023 21:04:31 +0000</pubDate>
      <link>https://forem.com/vaiolabs_io/manage-calendar-address-book-micro-services-pj1</link>
      <guid>https://forem.com/vaiolabs_io/manage-calendar-address-book-micro-services-pj1</guid>
      <description>&lt;p&gt;Greetings gentle reader. Gratitude for returning to update your insights on various topics. I am Silent-Mobius, also known as Alex M. Schapelle, walking and babbling computer droid.&lt;/p&gt;

&lt;p&gt;Within my short time my of existence, on this blue planet, I have learned that in case you are not paying for product, then you are product yourself... while that being true of my digital existence, much of services I use, are financed by me. Mainly due to &lt;a href="https://wh40k.lexicanum.com/wiki/Abominable_Intelligence" rel="noopener noreferrer"&gt;AI not being fully trusted&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Much of the services we use today, are seamlessly connected to one or more cloud providers, such as Google or Microsoft. Simple things, such calendar and address book are standardized by corporations which govern our quality of life, and we hook into the network of infinite computing grid of processing power.&lt;/p&gt;

&lt;p&gt;When considering applications, almost any endpoint device, such as laptop or phone, can provide client to be used as mail, calendar and so on, yet problem with those are that there is no backing up those endpoint applications... unless once again you use cloud provider... que: enter &lt;a href="https://radicale.org/v3.html" rel="noopener noreferrer"&gt;radicale&lt;/a&gt;&lt;br&gt;
Radicale is calendar and phone back-end application that uses CardDav and CalDav protocols. These are extension of the WebDav, a HTTP-based protocol for data manipulation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation for this effort
&lt;/h2&gt;

&lt;p&gt;For a very long period of time, I wanted to create my own cloud, based on simple services such as mail, calendar, contacts and many others which Google and Microsoft provide so graciously . &lt;br&gt;
Based on my knowledge of Linux OS distributions, with addition of constant search of interesting Open-Source projects, combined with my studies of &lt;strong&gt;micro-service&lt;/strong&gt; architectures, I wish to build eco-system that can enable me, the use of cloud, without using cloud-based providers.&lt;br&gt;
Although &lt;strong&gt;this project does not &lt;code&gt;builds&lt;/code&gt;&lt;/strong&gt; cloud serving platform out of thin air, yet it brings one step closer to building essential tools, which will enable us build my own cloud one day in the future, just like GNU and Linux Kernel were combined in early 90's.&lt;br&gt;
This project is an experiment, which will lead me and you gentle reader, to something new, and hopefully, we'll enjoy our journey through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;You can find environment of deployment that I have created based of the existing projects, mainly &lt;em&gt;nginx&lt;/em&gt; for being secured load-balancer serving as a connector to a &lt;em&gt;radicale&lt;/em&gt; CalDav/CardDav server. It is all managed with docker compose to be a POC, but also can be swapped with helm charts later to be deployed to K8s. The whole implementation saved at &lt;a href="https://gitlab.com/silent-mobius/calendar-addressbook-server-deployment" rel="noopener noreferrer"&gt;gitlab&lt;/a&gt; and you are more then welcome to visit, suggest, open issues and add additional features that did not think about, by myself.... please use &lt;code&gt;Merge Request&lt;/code&gt; do to all the above suggested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── docker-compose.prod.yml
├── docker-compose.yml
├── gunicorn.conf
├── nginx.conf
├── radicale.conf
├── Dockerfile.cal
├── Dockerfile.https
├── LICENSE
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;access.txt&lt;/code&gt; file, with the password for radicale container, is required to create calendar image.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application is structured as two container &lt;em&gt;micro-services&lt;/em&gt;, one for secure connection with &lt;code&gt;nginx&lt;/code&gt; web server that uses &lt;code&gt;https&lt;/code&gt; protocol that passes the communication to &lt;code&gt;radicale&lt;/code&gt; server that manages the calendar and address book data. It uses external volume backed up on &lt;code&gt;raid 50&lt;/code&gt; storage. &lt;code&gt;Raid 50&lt;/code&gt; is secured storage service provided by local ISP, to which only I and ISP have access.&lt;/p&gt;

&lt;p&gt;Each container is build with its dedicated &lt;code&gt;Dockerfile&lt;/code&gt;, and every container uses its own dedicated application configuration file. As mentioned, docker compose is in charge of handling the local run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope that this little fun project was an inspiration for you to go on adventure of your own with any software there is for your needs. One last for me to suggest would be: Do Try To Have Some Fun.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>docker</category>
      <category>microservices</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
