<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xml" href="https://www.embedded.pub/feed.xslt.xml"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.2">Jekyll</generator><link href="https://www.embedded.pub/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.embedded.pub/" rel="alternate" type="text/html" /><updated>2024-09-16T19:06:27+00:00</updated><id>https://www.embedded.pub/feed.xml</id><title type="html">Embedded Insights</title><subtitle>Dive into Embedded Linux, Buildroot, Yocto, C programming and Open Source. Your gateway to hands-on learning in the realm of Embedded Systems.</subtitle><author><name>Nayab Sayed</name></author><entry><title type="html">pause() System Call in C - With Examples</title><link href="https://www.embedded.pub/linux/man2/pause.html" rel="alternate" type="text/html" title="pause() System Call in C - With Examples" /><published>2024-02-29T00:00:00+00:00</published><updated>2024-02-29T00:00:00+00:00</updated><id>https://www.embedded.pub/linux/man2/pause</id><content type="html" xml:base="https://www.embedded.pub/linux/man2/pause.html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>The <code class="language-plaintext highlighter-rouge">pause()</code> system call is used to make the calling process or thread sleep until one of the following events occurs:</p>

<ul>
  <li>The calling process receives the signal whose default behaviour is to kill the process. (OR)</li>
  <li>The execution of the signal handler is completed</li>
</ul>

<p>In both the cases, the pause() system call returns <strong>-1</strong>.</p>

<p><a href="/assets/linux/man2/pause.png"><img src="/assets/linux/man2/pause.png" alt="/assets/linux/man2/pause.png" title="pause() systemc call in C" /></a></p>

<h2 id="behaviour-when-the-process-catches-a-signal">Behaviour when the process catches a signal</h2>

<p>Let’s examine the following program.</p>

<p><strong>file:</strong> pause.c</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
        <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">pause</span><span class="p">();</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Pause returned with %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ret</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compile the program using:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc pause.c <span class="nt">-o</span> pause
</code></pre></div></div>
<p>Run the program with <code class="language-plaintext highlighter-rouge">./pause</code>. The program sleeps at the line <code class="language-plaintext highlighter-rouge">ret = pause();</code>. From another terminal, send signals to this process using the kill command.</p>

<p>Examples:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">kill</span> <span class="nt">-SIGKILL</span> <span class="sb">`</span>pidof pause<span class="sb">`</span>	<span class="c"># Kills the process</span>
OR
<span class="nb">kill</span> <span class="nt">-SIGCHLD</span> <span class="sb">`</span>pidof pause<span class="sb">`</span>	<span class="c"># Won't have any effect</span>
</code></pre></div></div>

<p>The signals <code class="language-plaintext highlighter-rouge">SIGCHLD</code>, <code class="language-plaintext highlighter-rouge">SIGCONT</code>, <code class="language-plaintext highlighter-rouge">SIGSTOP</code> won’t terminate the process, as their default behavior is not set to do so. Additionally, the program does not register signal handlers for these signals, so the pause() system call won’t return upon catching these signals.</p>

<p>However, the pause() function returns when it receives signals with default behaviors set to terminate the process, such as SIGKILL, SIGTERM, etc. For more information on signals and their default behaviors, please run the <code class="language-plaintext highlighter-rouge">man 7 signal</code> command.</p>

<h2 id="behavior-when-the-process-finishes-executing-the-signal-handler">Behavior when the process finishes executing the signal handler</h2>

<p>Let’s examine the following program.</p>

<p><strong>file:</strong> pause_sigaction.c</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="nf">signal_handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">signal</span><span class="p">)</span>
<span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"Signal %d caught</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">signal</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
        <span class="k">struct</span> <span class="n">sigaction</span> <span class="n">act</span><span class="p">;</span>
        <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

        <span class="n">act</span><span class="p">.</span><span class="n">sa_handler</span> <span class="o">=</span>  <span class="n">signal_handler</span><span class="p">;</span>
        <span class="n">sigaction</span><span class="p">(</span><span class="n">SIGCONT</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">act</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">pause</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="n">ret</span><span class="p">)</span>
                <span class="n">printf</span><span class="p">(</span><span class="s">"Process exited</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A signal handler has been registered for the signal SIGCONT. When we pass this signal to the process, the <em>signal_handler</em> function is called. In this case, the pause() returns when the signal_handler completes execution. This holds true for all signals, whether the default behavior of the signal is to terminate the process or not.</p>

<p>Let’s compile the program with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc pause_sigaction.c <span class="nt">-o</span> pause_sigaction
</code></pre></div></div>
<p>Execute the program with <code class="language-plaintext highlighter-rouge">./pause_sigaction</code> in one terminal and in other terminal run the following command to send SIGCONT signal to the process.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">kill</span> <span class="nt">-SIGCONT</span> <span class="sb">`</span>pidof pause_sigaction<span class="sb">`</span>
</code></pre></div></div>

<p>The pause() returns, and the signal number is printed in the signal_handler(), after which the process exits.</p>

<p>Replace SIGCONT with SIGALRM, whose default behaviour is to terminate the process, in the above program. Re-compile and run the program. Pass the SIGALRM signal to the process using the kill command. The same behaviour can be observed.</p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="man2" /><summary type="html"><![CDATA[Introduction The pause() system call is used to make the calling process or thread sleep until one of the following events occurs:]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/man2/pause.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/man2/pause.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Shellcheck - A Static Analysis Tool for Shell Scripts - Introduction</title><link href="https://www.embedded.pub/linux/tools/shellcheck.html" rel="alternate" type="text/html" title="Shellcheck - A Static Analysis Tool for Shell Scripts - Introduction" /><published>2024-02-25T00:00:00+00:00</published><updated>2024-02-25T00:00:00+00:00</updated><id>https://www.embedded.pub/linux/tools/shellcheck</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/shellcheck.html"><![CDATA[<p>ShellCheck is a static analysis tool, or linter, for shell scripts. It detects various types of errors, provides suggestions, and issues warnings for shell scripts. ShellCheck identifies syntax issues, semantic problems that may cause shell scripts to behave unexpectedly, and other corner cases.</p>

<p>Different examples of poorly written shell code are presented in the following sections. The utilization of ShellCheck to identify errors, offer suggestions, and issue warnings in these examples is detailed.</p>

<p>The currently supported shells include: <strong>bash</strong>, <strong>dash</strong> and <strong>ksh</strong>.</p>

<p><a href="/assets/linux/tools/shellcheck.png"><img src="/assets/linux/tools/shellcheck.png" alt="/assets/linux/tools/shellcheck.png" title="ShellCheck - A shell script static analysis tool" /></a></p>

<h2 id="installation">Installation</h2>
<p>To install ShellCheck on Ubuntu/Debian-based Linux systems, use the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>shellcheck
</code></pre></div></div>
<h2 id="usage-of-shellcheck-with-bad-code-examples">Usage of Shellcheck with bad code examples</h2>
<p>Create a demo directory to practice the ShellCheck tool with the following commands:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> ~/shellcheck_demo
<span class="nb">cd</span> ~/shellcheck_demo
</code></pre></div></div>
<h3 id="checking-quotes">Checking quotes</h3>
<p>Here is a shell script named <code class="language-plaintext highlighter-rouge">quotes.sh</code> that contains various poorly written examples:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre><span class="c">#!/bin/bash</span>

<span class="c"># Example 1</span>
print_seed<span class="o">()</span> <span class="o">{</span>
    <span class="nb">cat</span> <span class="nv">$1</span>
<span class="o">}</span>

<span class="nb">echo</span> <span class="s2">"animal mammal dinner hot now yesterday"</span> <span class="o">&gt;</span> <span class="s2">"Seed Phrase"</span>

print_seed <span class="s2">"Seed Phrase"</span>

<span class="c"># Example 2</span>
<span class="nb">touch </span>file1.txt file2.txt
find ./ <span class="nt">-name</span> <span class="k">*</span>.txt

<span class="c"># Example 3</span>
<span class="nb">touch</span> <span class="s2">"~/myfile.txt"</span>

<span class="c"># Example 4</span>
<span class="nb">echo</span> <span class="s1">'The PATH is $PATH'</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>Attempt to execute this script and observe if the output aligns with your expectations.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span> +x ./quotes.sh
./quotes.sh
</code></pre></div></div>
<h4 id="checking-the-script-with-shellcheck">Checking the script with shellcheck</h4>
<p>Now, let’s identify the issues in the above script using the shellcheck command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcheck quotes.sh
</code></pre></div></div>
<p>Here is the report:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>In quotes.sh line 5:
    cat $1
        ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
    cat "$1"


In quotes.sh line 14:
find ./ -name *.txt
              ^---^ SC2061 (warning): Quote the parameter to -name so the shell won't interpret it.
              ^-- SC2035 (info): Use ./*glob* or -- *glob* so names with dashes won't become options.


In quotes.sh line 17:
touch "~/myfile.txt"
       ^----------^ SC2088 (warning): Tilde does not expand in quotes. Use $HOME.


In quotes.sh line 20:
echo 'The PATH is $PATH'
     ^-----------------^ SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.

For more information:
  https://www.shellcheck.net/wiki/SC2061 -- Quote the parameter to -name so t...
  https://www.shellcheck.net/wiki/SC2088 -- Tilde does not expand in quotes. ...
  https://www.shellcheck.net/wiki/SC2016 -- Expressions don't expand in singl...
</code></pre></div></div>
<h4 id="analyzing-above-report">Analyzing above report</h4>
<p>The output provides a clear explanation of the identified issues. Nevertheless, let’s delve into the details for a better understanding:</p>

<p class="info"><br />In the example 1 - line 5: $1 should be in quotes.<br />
In the example 2 - line 14: Wrap <em>*.txt</em> in the quotes.<br />
In the example 3 - line 17: Tilde won’t exapand inside the double quotes. We can use $HOME <br />
In the example 4 - line 20: $PATH won’t expand in single quotes. Use double quoes.</p>

<p>Here is the updated quotes.sh script after addressing the errors/warnings pointed out by the shell script tool:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre><span class="c">#!/bin/bash</span>

<span class="c"># Example 1</span>
print_seed<span class="o">()</span> <span class="o">{</span>
    <span class="nb">cat</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
<span class="o">}</span>

<span class="nb">echo</span> <span class="s2">"animal mammal dinner hot now yesterday"</span> <span class="o">&gt;</span> <span class="s2">"Seed Phrase"</span>

print_seed <span class="s2">"Seed Phrase"</span>

<span class="c"># Example 2</span>
<span class="nb">touch </span>file1.txt file2.txt
find ./ <span class="nt">-name</span> <span class="s2">"*.txt"</span>

<span class="c"># Example 3</span>
<span class="nb">touch</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/myfile.txt"</span>

<span class="c"># Example 4</span>
<span class="nb">echo</span> <span class="s2">"The PATH is </span><span class="nv">$PATH</span><span class="s2">"</span>
</pre></td></tr></tbody></table></code></pre></figure>

<h2 id="checking-conditionals">Checking conditionals</h2>
<p>Here is the <code class="language-plaintext highlighter-rouge">conditionals.sh</code> script with examples illustrating various conditional-related issues.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="code"><pre><span class="c">#!/bin/bash</span>

<span class="c"># Example 1</span>
<span class="nv">n</span><span class="o">=</span>2
<span class="k">if</span> <span class="o">[[</span> n <span class="o">!=</span> 2 <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"n is not 2"</span><span class="p">;</span>
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"n is 2"</span><span class="p">;</span>
<span class="k">fi</span>

<span class="c">## `[[ n != 2 ]]` returns true always. And echo statement will not print.</span>

<span class="c"># Example 2</span>
<span class="nb">touch </span>file1.txt

<span class="k">if</span> <span class="o">[[</span> <span class="nt">-e</span> <span class="k">*</span>.txt <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"file1.txt present"</span>
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"file1.txt not present"</span>
<span class="k">fi</span>

<span class="c"># Example 3</span>
<span class="nv">n</span><span class="o">=</span>3
<span class="k">if</span> <span class="o">[[</span> <span class="k">${</span><span class="nv">n</span><span class="k">}</span><span class="o">==</span>2 <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"n is 2"</span><span class="p">;</span>
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"n is not 2"</span><span class="p">;</span>
<span class="k">fi</span>

<span class="c"># Example 4</span>

<span class="nv">n</span><span class="o">=</span><span class="s2">""</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$n</span><span class="s2"> "</span> <span class="o">]]</span><span class="p">;</span><span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"n is not empty"</span>
<span class="k">else
    </span><span class="nb">echo</span> <span class="s2">"n is empty"</span>
<span class="k">fi</span>
</pre></td></tr></tbody></table></code></pre></figure>

<h4 id="running-shellcheck-on-the-script">Running shellcheck on the script</h4>
<p>Run the script and verify if the output aligns with expectations</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcheck conditionals.sh
</code></pre></div></div>
<p>Here is the analysis:</p>

<p class="info"><br />In example 1 - line 5: It should be <code class="language-plaintext highlighter-rouge">$n</code> instead of n.<br />
In example 2 - line 16: <em>-e</em> can’t be used with <em>*.txt</em>. Either use file path or use for loop to check all the *.txt files.<br />
In example 3 - line 24: There should be spaces around the comparison operator.<br />
In example 4 - line 33: The if condition is always true regardless of n value because there is a space inside the quotes. Remove it.<br /></p>

<p>Shellcheck can identify various types of conditional issues, including the following.</p>
<ul>
  <li>Comparing numerical values with strings</li>
  <li>Using logical operators inside brackets.</li>
  <li>Accidental backgrounds and piping <em>[[ condition1 ]] &amp; [[ condition 2 ]] | [[ condition 3 ]]</em></li>
</ul>

<h3 id="checking-syntax-errors">Checking syntax errors</h3>
<p>Here are a few examples of syntax issues in shell scripts. Refer to the comments for the corresponding fixes.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>n <span class="o">=</span> 42                          <span class="c"># Spaces shouldn't be there around = operator while assignments</span>
<span class="nv">$n</span><span class="o">=</span>42                           <span class="c"># $ should not be used when assigning a value to a variable</span>

<span class="c"># Shouldn't use $ with loop variable (i). Following is wrong</span>
<span class="k">for</span> <span class="nv">$i</span> <span class="k">in</span> <span class="o">{</span>1..10<span class="o">}</span><span class="p">;</span><span class="k">do</span>
    <span class="c"># Do something here</span>
<span class="k">done

</span><span class="nv">n</span><span class="o">=</span>1
num<span class="nv">$n</span><span class="o">=</span><span class="s2">"36"</span>                      <span class="c"># Use arrays instead</span>

<span class="nv">arr</span><span class="o">=(</span>1, 2, 3<span class="o">)</span>                   <span class="c"># Commas can't be used when defining arrays</span>
<span class="nb">echo</span> <span class="nv">$arr</span><span class="o">[</span>14]                   <span class="c"># Missing {} in array references</span>

<span class="k">else if </span>condition<span class="p">;</span> <span class="k">then</span> ..      <span class="c"># Using 'else if' instead of 'elif'</span>

func<span class="p">;</span> func<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> <span class="s2">"hello world; }     # Using function before definition
</span></code></pre></div></div>
<h3 id="checking-protability-between-shells">Checking protability between shells</h3>
<p>Here are a few examples that may run without issues in one shell variant but pose problems in others. Shellcheck does a good job of detecting these issues.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="o">{</span>1..10<span class="o">}</span>                    <span class="c"># Works in bash and ksh. Doesn't work in sh or dash</span>
<span class="nb">local </span><span class="nv">var</span><span class="o">=</span>2                     <span class="c"># local keyword is undefined in sh</span>
</code></pre></div></div>
<h3 id="miscellaneous-checking">Miscellaneous checking</h3>
<p>Following are few more bad examples:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'Don'</span>t <span class="k">do </span>it<span class="s1">'              # Three apostrophes. Unclosed single quote.
cat file1.txt | grep word       # cat is unnecessary. Use - grep word file1.txt
echo "Today date is `date`"     # Use $ instead of backticks for date command
echo $(( $a + 2 ))              # Don'</span>t use <span class="nv">$ </span>on variables inside the <span class="k">$((</span>..<span class="k">))</span><span class="nb">.</span>
                                <span class="c"># Might not work in all shells.</span>
<span class="nb">rm</span> <span class="nt">-rf</span> <span class="s2">"</span><span class="nv">$PROJECTROOT</span><span class="s2">/"</span><span class="k">*</span>         <span class="c"># Warns user the possibility of removing root directory if PROJECTROOT is empty</span>

</code></pre></div></div>
<h2 id="getting-additional-help-on-shellcheck">Getting additional help on shellcheck</h2>
<h3 id="the-shellcheck-help-command">The shellcheck help command</h3>
<p>The <code class="language-plaintext highlighter-rouge">shellcheck --help</code> command gives the brief info and options supported for the shellcheck tool.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shellcheck <span class="nt">--help</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Usage: shellcheck [OPTIONS...] FILES...
  -a                  --check-sourced            Include warnings from sourced files
  -C[WHEN]            --color[=WHEN]             Use color (auto, always, never)
  -i CODE1,CODE2..    --include=CODE1,CODE2..    Consider only given types of warnings
  -e CODE1,CODE2..    --exclude=CODE1,CODE2..    Exclude types of warnings
  -f FORMAT           --format=FORMAT            Output format (checkstyle, diff, gcc, json, json1, quiet, tty)
                      --list-optional            List checks disabled by default
                      --norc                     Don't look for .shellcheckrc files
  -o check1,check2..  --enable=check1,check2..   List of optional checks to enable (or 'all')
  -P SOURCEPATHS      --source-path=SOURCEPATHS  Specify path when looking for sourced files ("SCRIPTDIR" for script's dir)
  -s SHELLNAME        --shell=SHELLNAME          Specify dialect (sh, bash, dash, ksh)
  -S SEVERITY         --severity=SEVERITY        Minimum severity of errors to consider (error, warning, info, style)
  -V                  --version                  Print version information
  -W NUM              --wiki-link-count=NUM      The number of wiki links to show, when applicable
  -x                  --external-sources         Allow 'source' outside of FILES
                      --help                     Show this usage summary and exit
</code></pre></div></div>
<p>We can make shellcheck ignore certain error codes using the option –exclude=CODE1,CODE2… Useful while deploying the shellcheck in some build system.</p>

<h3 id="report-from-the-shellcheck-output">Report from the shellcheck output</h3>
<p>If you review the Shellcheck output for the quotes.sh script, each error, warning, or suggestion is accompanied by a URL at the end of the report for additional reference. It looks something like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>For more information:
  https://www.shellcheck.net/wiki/SC2061 -- Quote the parameter to -name so t...
  https://www.shellcheck.net/wiki/SC2088 -- Tilde does not expand in quotes. ...
  https://www.shellcheck.net/wiki/SC2016 -- Expressions don't expand in singl...
</code></pre></div></div>
<p>Feel free to open those URLs in the browser and read the detailed info about the issue there.</p>

<h3 id="page-consisting-of-all-error-codes">Page consisting of all error codes</h3>
<p>You can find the all shellcheck error codes <a href="https://gist.github.com/nicerobot/53cee11ee0abbdc997661e65b348f375">here</a>. If this link is broken, you can find the modified web page link <a href="https://github.com/koalaman/shellcheck/wiki/Checks">here</a></p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[ShellCheck is a static analysis tool, or linter, for shell scripts. It detects various types of errors, provides suggestions, and issues warnings for shell scripts. ShellCheck identifies syntax issues, semantic problems that may cause shell scripts to behave unexpectedly, and other corner cases.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/shellcheck.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/shellcheck.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">USB Drive or SD Card Partitioning Using fdisk Utility</title><link href="https://www.embedded.pub/linux/tools/fdisk-partitioning.html" rel="alternate" type="text/html" title="USB Drive or SD Card Partitioning Using fdisk Utility" /><published>2024-02-19T00:00:00+00:00</published><updated>2024-02-19T00:00:00+00:00</updated><id>https://www.embedded.pub/linux/tools/fdisk-partitioning</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/fdisk-partitioning.html"><![CDATA[<p>In this tutorial, we’ll explore the process of creating partitions for a hard disk drive (HDD), USB drive, or micro SD card using the Linux tool <strong>fdisk</strong>. Additionally, we’ll establish a file system within these partitions using another tool called <strong>mkfs</strong>.</p>

<p>Let’s generate two partitions: the first utilizing the <em>fat32</em> filesystem and the second utilizing the <em>ext4</em> filesystem. This partition combination is commonly employed for constructing a fully bootable operating system. The fat32 partition is designated for storing bootloader-related files, while the ext4 filesystem is employed for housing Linux files.</p>

<p><a href="/assets/linux/tools/fdisk-partitioning.png"><img src="/assets/linux/tools/fdisk-partitioning.png" alt="/assets/linux/tools/fdisk-partitioning.png" title="SD card or USB drive partitioning using fdisk utility" /></a></p>

<h2 id="insert-the-usb-drive--sd-card-reader">Insert the USB drive / SD card reader</h2>

<p>When you insert a USB drive or SD card reader into the system’s USB port, it’s usually identified as <code class="language-plaintext highlighter-rouge">sdX</code> (e.g., sda, sdb), while an SD card appears as <code class="language-plaintext highlighter-rouge">mmcblkX</code> (e.g., mmcblk0). To identify the USB device from the kernel log, run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl  <span class="nt">-ke</span>
</code></pre></div></div>

<p>Correspondingly, partitions are created in the format sdXY (e.g., sdb1, sdc1) or mmcblkXpY (e.g., mmcblk0p1) respectively.</p>

<p>Check connected storage devices using the <code class="language-plaintext highlighter-rouge">lsblk</code> command. A typical output might look like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sdc           8:32   1  14.8G  0 disk
<span class="sb">`</span><span class="nt">-sdc1</span>        8:33   1  14.8G  0 part
nvme0n1     259:0    0 476.9G  0 disk
|-nvme0n1p1 259:1    0   512M  0 part /boot/efi
|-nvme0n1p2 259:2    0 475.5G  0 part /
<span class="sb">`</span><span class="nt">-nvme0n1p3</span> 259:3    0   976M  0 part <span class="o">[</span>SWAP]
</code></pre></div></div>
<p>Here is another one:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sda           8:0    0 223.6G  0 disk
├─sda1        8:1    0   512M  0 part /boot/efi
├─sda2        8:2    0  93.1G  0 part /
├─sda3        8:3    0   7.5G  0 part <span class="o">[</span>SWAP]
└─sda4        8:4    0 122.5G  0 part
sr0          11:0    1  1024M  0 rom
mmcblk0     179:0    0    29G  0 disk
└─mmcblk0p1 179:1    0    29G  0 part /media/nayab/8D39-59F7
</code></pre></div></div>
<h3 id="storage-device-names-in-linux">Storage device names in Linux</h3>
<p>Typical naming of storage devices are as follows:</p>

<table>
  <thead>
    <tr>
      <th>Storage device</th>
      <th>Linux device (ex:)</th>
      <th>Partitions (ex:)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Hard disk drive</td>
      <td>sdX (sda, sdb etc.)</td>
      <td>sdXY (sda1, sdb2 etc)</td>
    </tr>
    <tr>
      <td>USB flash drive</td>
      <td>sdX (sda, sdb etc.)</td>
      <td>sdXY (sda1, sdb2 etc)</td>
    </tr>
    <tr>
      <td>NVMe SSD</td>
      <td>nvmeX (nvme0, nvme1 etc.)</td>
      <td>nvmeXnYpZ (nvme0n1p1, nvme1n2p2 etc.)</td>
    </tr>
    <tr>
      <td>Micro SD card (SDHC)</td>
      <td>mmcblkX (mmcblk0, mmcblk1 etc.)</td>
      <td>mmcblkXpY (mmcblk0p1, mmcblk1p3 etc.)</td>
    </tr>
    <tr>
      <td>Micro SD card (USB)</td>
      <td>sdX (sda, sdb etc.)</td>
      <td>sdXY (sda1, sdb2 etc)</td>
    </tr>
  </tbody>
</table>

<h2 id="unmount-the-partitions">Unmount the partitions</h2>
<p>Before using the fdisk tool, ensure that the storage device partitions are unmounted.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>umount /dev/&lt;device_partition&gt;
</code></pre></div></div>
<p>or</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo umount /dev/mmcblk0p1
</code></pre></div></div>
<h2 id="partitioning-with-fdisk">Partitioning with fdisk</h2>
<p>Now run the fdisk command with the device name.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>fdisk /dev/&lt;dev_name&gt;
</code></pre></div></div>
<p>Replace <em>&lt;dev_name&gt;</em> with USB device name (ex: /dev/sdb or /dev/mmcblk0).</p>

<h3 id="delete-partitions">Delete partitions</h3>
<p>Press <code class="language-plaintext highlighter-rouge">p</code> to display the available partitions. Type <code class="language-plaintext highlighter-rouge">d</code> multiple times until all partitions are deleted, then type <code class="language-plaintext highlighter-rouge">p</code> again to confirm the changes.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Welcome to fdisk <span class="o">(</span>util-linux 2.39.3<span class="o">)</span><span class="nb">.</span>
Changes will remain <span class="k">in </span>memory only, <span class="k">until </span>you decide to write them.
Be careful before using the write command.


Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: p
Disk /dev/mmcblk0: 29.81 GiB, 32010928128 bytes, 62521344 sectors
Units: sectors of 1 <span class="k">*</span> 512 <span class="o">=</span> 512 bytes
Sector size <span class="o">(</span>logical/physical<span class="o">)</span>: 512 bytes / 512 bytes
I/O size <span class="o">(</span>minimum/optimal<span class="o">)</span>: 512 bytes / 512 bytes
Disklabel <span class="nb">type</span>: dos
Disk identifier: 0x00000000

Device         Boot Start     End Sectors  Size Id Type
/dev/mmcblk0p1 <span class="k">*</span>     2048   34815   32768   16M  c W95 FAT32 <span class="o">(</span>LBA<span class="o">)</span>
/dev/mmcblk0p2      34816 1083391 1048576  512M 83 Linux

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: d
Partition number <span class="o">(</span>1,2, default 2<span class="o">)</span>:

Partition 2 has been deleted.

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: d
Selected partition 1
Partition 1 has been deleted.

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: d
No partition is defined yet!

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: p

Disk /dev/mmcblk0: 29.81 GiB, 32010928128 bytes, 62521344 sectors
Units: sectors of 1 <span class="k">*</span> 512 <span class="o">=</span> 512 bytes
Sector size <span class="o">(</span>logical/physical<span class="o">)</span>: 512 bytes / 512 bytes
I/O size <span class="o">(</span>minimum/optimal<span class="o">)</span>: 512 bytes / 512 bytes
Disklabel <span class="nb">type</span>: dos
Disk identifier: 0x00000000

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>:
</code></pre></div></div>
<h3 id="create-fat32-partition">Create FAT32 partition</h3>
<p>Now, let’s create a primary partition of 1GB to store bootloader files. Press <code class="language-plaintext highlighter-rouge">n</code> followed by <code class="language-plaintext highlighter-rouge">p</code> for primary partition. Press <code class="language-plaintext highlighter-rouge">Enter</code> for the default <em>Fist sector</em> followed by <code class="language-plaintext highlighter-rouge">+1G</code> when asked for <em>Last sector</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: n
Partition <span class="nb">type
   </span>p   primary <span class="o">(</span>0 primary, 0 extended, 4 free<span class="o">)</span>
   e   extended <span class="o">(</span>container <span class="k">for </span>logical partitions<span class="o">)</span>
Select <span class="o">(</span>default p<span class="o">)</span>: p
Partition number <span class="o">(</span>1-4, default 1<span class="o">)</span>:
First sector <span class="o">(</span>2048-62521343, default 2048<span class="o">)</span>:
Last sector, +/-sectors or +/-size<span class="o">{</span>K,M,G,T,P<span class="o">}</span> <span class="o">(</span>2048-62521343, default 62521343<span class="o">)</span>: +1G

Created a new partition 1 of <span class="nb">type</span> <span class="s1">'Linux'</span> and of size 1 GiB
</code></pre></div></div>
<p>Change the partition type to FAT32 by typing <em>t</em> and then selecting <em>b</em>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: t
Selected partition 1
Hex code or <span class="nb">alias</span> <span class="o">(</span><span class="nb">type </span>L to list all<span class="o">)</span>: b
Changed <span class="nb">type </span>of partition <span class="s1">'Linux'</span> to <span class="s1">'W95 FAT32'</span><span class="nb">.</span>
</code></pre></div></div>
<h3 id="create-linux-partition">Create Linux partition</h3>
<p>Create another partition with the remaining size. Type <code class="language-plaintext highlighter-rouge">n</code> and keep pressing <code class="language-plaintext highlighter-rouge">Enter</code> until the prompt repeats. Then type <code class="language-plaintext highlighter-rouge">t</code>, followed by <code class="language-plaintext highlighter-rouge">2</code> for the partition number, and set the Hex code to <code class="language-plaintext highlighter-rouge">83</code> when prompted to specify the Linux type.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: n
Partition <span class="nb">type
   </span>p   primary <span class="o">(</span>1 primary, 0 extended, 3 free<span class="o">)</span>
   e   extended <span class="o">(</span>container <span class="k">for </span>logical partitions<span class="o">)</span>
Select <span class="o">(</span>default p<span class="o">)</span>:

Using default response p.
Partition number <span class="o">(</span>2-4, default 2<span class="o">)</span>:
First sector <span class="o">(</span>2099200-62521343, default 2099200<span class="o">)</span>:
Last sector, +/-sectors or +/-size<span class="o">{</span>K,M,G,T,P<span class="o">}</span> <span class="o">(</span>2099200-62521343, default 62521343<span class="o">)</span>:

Created a new partition 2 of <span class="nb">type</span> <span class="s1">'Linux'</span> and of size 28.8 GiB.

Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>:


Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>:


Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: t
Partition number <span class="o">(</span>1,2, default 2<span class="o">)</span>: 2
Hex code or <span class="nb">alias</span> <span class="o">(</span><span class="nb">type </span>L to list all<span class="o">)</span>: 83


Changed <span class="nb">type </span>of partition <span class="s1">'Linux'</span> to <span class="s1">'Linux'</span><span class="nb">.</span>
</code></pre></div></div>
<h3 id="write-changes-to-device">Write changes to device</h3>
<p>Type <code class="language-plaintext highlighter-rouge">w</code> to save the partition changes to the disk.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: w

The partition table has been altered.
Calling ioctl<span class="o">()</span> to re-read partition table.
Syncing disks.
</code></pre></div></div>
<p>Verify the newly written partition information with the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>fdisk /dev/&lt;dev_name&gt;
</code></pre></div></div>
<p>Here is an example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 29.81 GiB, 32010928128 bytes, 62521344 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device         Boot   Start      End  Sectors  Size Id Type
/dev/mmcblk0p1         2048  2099199  2097152    1G  b W95 FAT32
/dev/mmcblk0p2      2099200 62521343 60422144 28.8G 83 Linux
</code></pre></div></div>
<h2 id="build-file-system-with-mkfs-tool">Build file system with mkfs tool</h2>
<p>Build <em>fat32</em> filesystem for partition 1:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mkfs.vfat /dev/mmcblk0p1 <span class="nt">-n</span> boot
</code></pre></div></div>
<p>Build <em>Linux</em> filesystem for partition 2:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mkfs.ext4 /dev/mmcblk0p2 <span class="nt">-L</span> rootfs
</code></pre></div></div>
<h2 id="check-the-partitions">Check the partitions</h2>
<p>Remove the USB/Card device and then reinsert it to verify the partitions using the <em>lsblk</em> command.</p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[In this tutorial, we’ll explore the process of creating partitions for a hard disk drive (HDD), USB drive, or micro SD card using the Linux tool fdisk. Additionally, we’ll establish a file system within these partitions using another tool called mkfs.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/fdisk-partitioning.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/fdisk-partitioning.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">b4 Tool for Code Contributors</title><link href="https://www.embedded.pub/opensource/tools/b4-contributors.html" rel="alternate" type="text/html" title="b4 Tool for Code Contributors" /><published>2024-02-18T07:23:49+00:00</published><updated>2024-02-18T07:23:49+00:00</updated><id>https://www.embedded.pub/opensource/tools/b4-contributors</id><content type="html" xml:base="https://www.embedded.pub/opensource/tools/b4-contributors.html"><![CDATA[<p>The b4 tool offers features that simplify the process for code contributors submitting patches. Currently, it is increasingly utilized in the Linux kernel development workflow.</p>

<p>You can install b4 tool in the Debian based Linux systems with the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>b4
</code></pre></div></div>

<p>Below are the commands illustrating the development workflow for developers.</p>

<p><a href="/assets/opensource/tools/b4-tool-contributors.png"><img src="/assets/opensource/tools/b4-tool-contributors.png" alt="b4 tool for code contributors" /></a></p>

<h2 id="b4-prep">b4 prep</h2>

<h3 id="creating-separate-work-branch">Creating separate work branch</h3>

<p>b4 assumes that you create a new branch before starting to work on a patch (series). To create a branch for your work:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">-n</span> &lt;patch_series_name&gt;
</code></pre></div></div>

<p>You can also create a branch from a specific commit ID.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">-n</span> &lt;patch_series_name&gt; <span class="nt">-f</span> &lt;commit_id&gt;
</code></pre></div></div>

<p>These commands create a new branch and checkout to newly created branch automatically. Now, as usual, you modify and create commits using standard Git commands like <code class="language-plaintext highlighter-rouge">git add</code>, <code class="language-plaintext highlighter-rouge">git commit</code>, <code class="language-plaintext highlighter-rouge">git commit --amend</code>, etc.</p>

<h3 id="preparing-the-cover-letter">Preparing the cover letter</h3>

<p>The following command can be used to prepare the cover letter. For single commit submissions, you can simply delete the first line that starts with <em>EDITME</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">--edit-cover</span>
</code></pre></div></div>

<p>This command can also be utilized to edit the list of recipients for the patch series. See the next section for details.</p>

<h3 id="retrieve-recipients-email-addresses">Retrieve recipients’ email addresses</h3>

<p>Linux kernel developers used to execute the script <em>get_maintainer.pl</em> against the patch to retrieve the recipients’ email addresses to which the patch needs to be sent. Then, they would manually use these email addresses as arguments to the <code class="language-plaintext highlighter-rouge">git send-email</code> command to send the patches to the list. The following command simplifies the process of gathering the relevant addresses from the commits themselves.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">--auto-to-cc</span>
</code></pre></div></div>

<p>If your project lacks a MAINTAINERS file or any b4 configuration at its core, you may not find a list of recipient emails from the above command. In that case, refer to the last section.</p>

<h3 id="set-the-email-subject-prefixes">Set the email subject prefixes</h3>

<p>You may want to add a prefix such as <em>RFC</em> or <em>RESEND</em> to the email subject. Use the following command to set the prefix. By default, b4 prep adds the prefixes <em>PATCH</em> and a version number such as <em>v2</em> or <em>v3</em>. These default prefixes cannot be removed.”</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">--set-prefixes</span> <span class="s2">"RFC RESEND"</span>
</code></pre></div></div>

<p>You can reset the prefixes with:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">--set-prefixes</span> <span class="s2">""</span>
</code></pre></div></div>
<h2 id="b4-send">b4 send</h2>

<h3 id="verify-the-patch-before-sending">Verify the patch before sending</h3>

<p>Here are a few commands you can try to verify before sending the patch to the list.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Writes raw messages to /tmp/presend directory.</span>
b4 send <span class="nt">-o</span> /tmp/presend

<span class="c"># Send the patch only to yourself. The the e-mail looks like as if you sent to the actual list of recipients.</span>
b4 send <span class="nt">--reflect</span>
</code></pre></div></div>

<h3 id="sending-the-patch">Sending the patch</h3>

<p>Execute the following command to send the patch to the list.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 send
</code></pre></div></div>

<h3 id="addressing-review-comments-and-sending-the-next-patch-version">Addressing review comments and sending the next patch version</h3>

<p>Once b4 has sent patch v1 to the list, it increments the current version number by 1, and you can continue working on the patch based on the received review comments. As usual, modify the files, use commands like <em>git add</em>, <em>git commit –amend</em>, etc. Now, run <code class="language-plaintext highlighter-rouge">b4 prep --edit-cover</code> again to write the changes in the current version. b4 maintains a template for changes in the current version and also remembers the version changes history, so you don’t have to copy-paste every time you send a new iteration of the patch. Verify the patch, once ready resend it using <code class="language-plaintext highlighter-rouge">b4 send</code>.</p>

<p>If, for some reason, you want to resend the same patch, you can do so without incrementing the version number by using the following command with b4.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 send <span class="nt">--resend</span> v2 <span class="c"># v&lt;version_number&gt;</span>
</code></pre></div></div>

<h2 id="b4-trailers">b4 trailers</h2>

<p>If someone has provided a <code class="language-plaintext highlighter-rouge">Reviewed-by</code> or <code class="language-plaintext highlighter-rouge">Acked-by</code> or any other tag, you can gather all those trailers into your commit using the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 trailers <span class="nt">-u</span>
</code></pre></div></div>

<p>This command is applicable only when the project utilizes an archived mailing list service such as https://lore.kernel.org/. It retrieves trailers from the archive.</p>

<p>Some popular projects leveraging this service include Linux, Buildroot, and certain Yocto meta layers.</p>

<h2 id="cleaning-up">Cleaning up</h2>

<p>After your patch is merged into the upstream, you can delete the development branch with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b4 prep <span class="nt">--cleanup</span> &lt;branch_name&gt;
</code></pre></div></div>

<h2 id="a-simple-b4-config-file">A simple b4 config file</h2>

<p>Here is a sample <code class="language-plaintext highlighter-rouge">.b4-config</code> file that can be placed in the root directory of your project. This example utilizes the Gmail SMTP server to send patches using b4.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>b4]
  prep-cover-strategy <span class="o">=</span> branch-description
  send-no-patatt-sign <span class="o">=</span> <span class="nb">yes</span>
<span class="c"># If your project doesn't have MAINTAINERS file, use send-series-to or</span>
<span class="c"># send-series-cc to add recipients email or list address</span>
  send-series-to <span class="o">=</span> &lt;e-mail_id&gt;
  send-series-cc <span class="o">=</span> &lt;e-mail_id&gt;

<span class="o">[</span>sendemail]
  smtpServer <span class="o">=</span> smtp.gmail.com
  smtpServerPort <span class="o">=</span> 587
  smtpEncryption <span class="o">=</span> tls
  smtpUser <span class="o">=</span> &lt;gmail_id&gt;
  smtpPass <span class="o">=</span> appPassword
</code></pre></div></div>

<h2 id="references">References</h2>
<ul>
  <li><a href="https://b4.docs.kernel.org/en/latest/contributor/overview.html#">Linux Kernel b4 docs</a></li>
  <li><a href="https://www.youtube.com/watch?v=wTpQYM08_Yg">Do more with lore and b4 - Video</a></li>
</ul>]]></content><author><name>Nayab Sayed</name></author><category term="opensource" /><category term="tools" /><summary type="html"><![CDATA[The b4 tool offers features that simplify the process for code contributors submitting patches. Currently, it is increasingly utilized in the Linux kernel development workflow.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/opensource/tools/b4-tool-contributors.png" /><media:content medium="image" url="https://www.embedded.pub/assets/opensource/tools/b4-tool-contributors.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Speeding Up the Buildroot Build Process</title><link href="https://www.embedded.pub/linux/build/buildroot/tips/speed-up-buildroot-build.html" rel="alternate" type="text/html" title="Speeding Up the Buildroot Build Process" /><published>2023-10-28T17:48:43+00:00</published><updated>2023-10-28T17:48:43+00:00</updated><id>https://www.embedded.pub/linux/build/buildroot/tips/speed-up-buildroot-build</id><content type="html" xml:base="https://www.embedded.pub/linux/build/buildroot/tips/speed-up-buildroot-build.html"><![CDATA[<p>I frequently need to build a fresh Buildroot target image, and it can be quite time-consuming, particularly when dealing with toolchain-related changes that necessitate starting from scratch.</p>

<p>According to Buildroot’s documentation, there are few ways to expedite the build process for the Buildroot system. The analysis that follows was conducted by building a target image for the Raspberry Pi 4 using it’s default configuration on a 16 thread AMD machine.
<a href="/assets/linux/build/buildroot/tips/speedup-buildroot-build.png"><img src="/assets/linux/build/buildroot/tips/speedup-buildroot-build.png" alt="/assets/linux/build/buildroot/tips/speedup-buildroot-build.png" title="Speeding up buildroot build" /></a></p>

<p>The typical steps for building an embedded Linux image for the Raspberry Pi 4 using Buildroot are as follows:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://gitlab.com/buildroot.org/buildroot.git
<span class="nb">cd </span>buildroot/
make raspberrypi4_64_defconfig
make <span class="nt">-j</span><span class="sb">`</span><span class="nb">nproc</span><span class="sb">`</span>
</code></pre></div></div>
<p>The build process took approximately <em>37m12s</em> to complete.</p>
<h2 id="speeding-up-the-initial-build">Speeding up the initial build</h2>
<h3 id="using-top-level-parallel-build">Using top level parallel build</h3>
<p>By default, using <em>make -jN</em> isn’t effective in Buildroot. However, there’s an experimental feature that can be enabled to make it effective. To do this, run <em>make menuconfig</em>, search for the string <em>BR2_PER_PACKAGE_DIRECTORIES</em>, enable it, and save the configuration.</p>

<p>Now, run <em>make clean &amp;&amp; make -j`nproc`</em> to perform a top-level parallel build.</p>

<p>The build process took approximately <em>26m7s</em> to complete. For this testing purpose, intentionally I deleted download directory so that all the sources will be downloaded again.</p>
<h3 id="using-the-external-sdk">Using the external SDK</h3>
<p>You have the option to instruct Buildroot to use an external toolchain. If you don’t have one available, Buildroot can even create one for you.</p>
<h4 id="buildroot-sdk-creation-steps">Buildroot SDK creation steps</h4>
<ul>
  <li>First, Be sure to make a record of the toolchain settings from <em>make menuconfig</em> -&gt; <em>Toolchain</em>. You can also take a screenshot for future reference.</li>
  <li>In the <em>System configuration</em> -&gt; <em>Init system</em> section, choose <em>None</em>.</li>
  <li>In the <em>System configuration</em> -&gt; <em>/bin/sh</em> section, choose <em>none</em>.</li>
  <li>Disable <em>Target packages</em> -&gt; <em>Busybox</em> section.</li>
  <li>Disable <em>File system images</em> -&gt; <em>tar the root filesystem</em></li>
  <li>Run <em>make sdk</em></li>
</ul>

<p>The SDK/toolchain will be generated in the <em>output/images</em> directory. In my case, it’s located at <em>output/images/aarch64-buildroot-linux-gnu_sdk-buildroot.tar.gz</em>. Make sure to copy this file to another location.
<a href="/assets/linux/build/buildroot/tips/raspbeeryPiToolChainConfig.png"><img src="/assets/linux/build/buildroot/tips/raspbeeryPiToolChainConfig.png" alt="Raspberry Pi 4 Buildroot Toolchain Configuration" title="Raspberry Pi 4 Buildroot Toolchain Configuration" /></a></p>
<h4 id="using-the-external-toolchain">Using the external toolchain</h4>
<p>Go to <em>make menuconfig</em> -&gt; <em>Toolchain</em>,</p>
<ul>
  <li>Set <em>Toolchain type</em> to <em>External toolchain</em></li>
  <li>Set <em>Toolchain</em> to <em>Custom toolchain</em></li>
  <li>Set <em>Toolchain origin</em> to <em>Toolchain to be downloaded and installed</em></li>
  <li>Set <em>Toolchain URL</em> to the SDK downloaded path. In my case it is: <em>file:///home/nayab/aarch64-buildroot-linux-gnu_sdk-buildroot.tar.gz</em></li>
  <li>Set <em>External toolchain gcc version</em> -&gt; Taken from above step. (ex: 11.x)</li>
  <li>Set <em>External toolchain kernel headers series</em> -&gt; Taken from above step. (ex: 5.10.x)</li>
  <li>Set <em>External toolchain C library</em> -&gt; Taken from above step (ex: glibc)</li>
  <li>Set <em>Toolchain has C++ support?</em> -&gt; Taken from above step. (ex: Enabled in my case)</li>
  <li>Set <em>Toolchain has RPC support?</em> -&gt; Disabled. <!--BR2_TOOLCHAIN_EXTERNAL_INET_RPC--></li>
</ul>

<p>After pointing Buildroot to the external toolchain, run the command <em>make clean &amp;&amp; make -j`nproc`</em> .The build process took approximately <em>14m47s</em> to complete. For this testing purpose, intentionally I deleted download directory before running <em>make</em> command.</p>
<h2 id="speeding-up-incrementalparallel-builds">Speeding up incremental/parallel builds</h2>
<h3 id="using-the-compiler-cache-ccache">Using the compiler cache (ccache)</h3>
<p>To enable <em>ccache</em>, navigate to <em>make menuconfig</em> -&gt; <em>Build options</em> -&gt; <em>Enable compiler cache</em>. With ccache enabled, the build process stores object files created from source files in the default cache directory <em>$HOME/.buildroot-ccache</em>. Any subsequent or incremental builds with ccache enabled will reduce build time nicely.</p>

<p>In my case, when I initiated an incremental build using the commands <em>make clean</em> and <em>make -j`nproc`</em>, the entire build process only took 5 minutes and 24 seconds. That’s incredibly fast. Now also, the <em>dl</em> directory was deleted manually before building.</p>

<p>Note that, <em>make clean</em> won’t delete compiler ccache directory. This need to be deleted manually if you want to get rid of it.</p>

<p>The compiler cache can be shared among multiple parallel builds, resulting in a significant reduction in build times, no matter how many builds are concurrently taking place.</p>
<h3 id="re-using-the-download-directory">Re-using the download directory</h3>
<p>This is especially useful when you need to build for multiple targets simultaneously. In Buildroot, there’s a configuration option, <em>BR2_DL_DIR</em>, where you can set the value to use a shared downloads path for all target builds. I configured this to use the downloads directory where all the files were already downloaded.</p>

<p>The build process took approximately <em>3m4s</em> to complete.</p>
<h3 id="sharing-the-buildroot-source-tree">Sharing the Buildroot source tree</h3>
<p>Buildroot <em>Building out of tree</em> feature lets you construct images for multiple targets using the same Buildroot source tree. This way source cloning (ex: git clone) time will be saved.</p>

<p>For instance, assuming the current working directory is the Buildroot source tree:</p>

<p>In one Terminal tab, run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>rpi<span class="p">;</span> make <span class="nv">O</span><span class="o">=</span>rpi raspberrypi4_64_defconfig
</code></pre></div></div>
<p>In another Terminal tab, run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>mchp<span class="p">;</span> make <span class="nv">O</span><span class="o">=</span>mchp microchip_sam9x60ek_mmc_defconfig
</code></pre></div></div>
<p>Now there are two output directories, named <em>rpi</em> and <em>mchp</em>, for each target, all utilizing the same Buildroot source tree.</p>
<h2 id="comparison-table">Comparison table</h2>

<table>
  <thead>
    <tr>
      <th>BR2_PER_PACKAGE_DIRECTORIES</th>
      <th>make -j`nproc`</th>
      <th>SDK</th>
      <th>ccache</th>
      <th>Downloads</th>
      <th>Build Time</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Disabled</td>
      <td>Yes</td>
      <td>Compile</td>
      <td>Disabled</td>
      <td>NA</td>
      <td>37m12s</td>
    </tr>
    <tr>
      <td>Enabled</td>
      <td>Yes</td>
      <td>Compile</td>
      <td>Disabled</td>
      <td>NA</td>
      <td>26m7s</td>
    </tr>
    <tr>
      <td>Enabled</td>
      <td>Yes</td>
      <td>External</td>
      <td>Disabled</td>
      <td>NA</td>
      <td>14m47s</td>
    </tr>
    <tr>
      <td>Enabled</td>
      <td>Yes</td>
      <td>External</td>
      <td>Enabled</td>
      <td>NA</td>
      <td>5m24s</td>
    </tr>
    <tr>
      <td>Enabled</td>
      <td>Yes</td>
      <td>External</td>
      <td>Enabled</td>
      <td>Available</td>
      <td>3m4s</td>
    </tr>
  </tbody>
</table>

<h2 id="miscellaneous">Miscellaneous</h2>
<ul>
  <li>Investing in better hardware can significantly reduce build times. Consider getting a faster SSD and increasing RAM.</li>
  <li>Building within a virtual machine can lead to notably poor performance.</li>
</ul>

<h2 id="references">References</h2>
<ul>
  <li><a href="https://buildroot.org/downloads/manual/manual#faq-speeding-up-build">https://buildroot.org/downloads/manual/manual#faq-speeding-up-build</a></li>
  <li><a href="https://buildroot.org/downloads/manual/manual.html#top-level-parallel-build">https://buildroot.org/downloads/manual/manual.html#top-level-parallel-build</a></li>
  <li><a href="https://buildroot.org/downloads/manual/manual.html#build-toolchain-with-buildroot">https://buildroot.org/downloads/manual/manual.html#build-toolchain-with-buildroot</a></li>
  <li><a href="https://buildroot.org/downloads/manual/manual.html#ccache">https://buildroot.org/downloads/manual/manual.html#ccache</a></li>
  <li><a href="https://buildroot.org/downloads/manual/manual.html#download-location">https://buildroot.org/downloads/manual/manual.html#download-location</a></li>
  <li><a href="https://buildroot.org/downloads/manual/manual.html#_building_out_of_tree">https://buildroot.org/downloads/manual/manual.html#_building_out_of_tree</a></li>
</ul>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="build" /><category term="buildroot" /><category term="tips" /><summary type="html"><![CDATA[I frequently need to build a fresh Buildroot target image, and it can be quite time-consuming, particularly when dealing with toolchain-related changes that necessitate starting from scratch.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/build/buildroot/tips/speedup-buildroot-build.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/build/buildroot/tips/speedup-buildroot-build.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Installing Flatpak Applications on Linux Distributions</title><link href="https://www.embedded.pub/linux/tools/installing-flatpak-app.html" rel="alternate" type="text/html" title="Installing Flatpak Applications on Linux Distributions" /><published>2023-09-27T15:23:00+00:00</published><updated>2023-09-27T15:23:00+00:00</updated><id>https://www.embedded.pub/linux/tools/installing-flatpak-app</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/installing-flatpak-app.html"><![CDATA[<p>Flatpak is a packaging format specifically designed to enable applications to run seamlessly on any Linux distribution, be it Debian, Fedora, OpenSUSE, Arch, or other family of Linux distributions.</p>

<p>The initial Flatpak setup process varies for each family of Linux distributions. However, once set up, the procedure for downloading, installing, and using Flatpak apps is consistent across all distributions.</p>

<p>This post illustrates the process for Debian/Ubuntu-based Linux distributions. For other distributions, please refer to <a href="https://flathub.org/setup">https://flathub.org/setup</a>.
<a href="/assets/linux/tools/install-flatpak.png"><img src="/assets/linux/tools/install-flatpak.png" alt="Installing Flatpak Apps in Linux Distributions" /></a></p>
<h2 id="installing-flatpak">Installing flatpak</h2>

<p>Installing Flatpak on Debian/Ubuntu is straightforward. Simply use the ‘apt’ command to install Flatpak.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt <span class="nb">install </span>flatpak
</code></pre></div></div>
<h2 id="installing-software-manager-plugin">Installing software manager plugin</h2>
<p>Install the plugin to search for Flatpak apps directly from the Software Center.</p>

<p>For those using the KDE desktop environment, use the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>plasma-discover-backend-flatpak
</code></pre></div></div>
<p>For those using the GNOME desktop environment, use the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>gnome-software-plugin-flatpak
</code></pre></div></div>
<h2 id="add-flatpak-app-repositories">Add flatpak app repositories</h2>
<p>Adding the Flatpak repositories is crucial because they host Flatpak apps, allowing you to download apps from these repositories. You can add multiple Flatpak repositories and choose which one to use when downloading packages.</p>

<p>The most popular flatpak repository out there is <em>Flathub</em>. To add Flathub to your list of Flatpak repositories, use this command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak remote-add <span class="nt">--if-not-exists</span> flathub https://dl.flathub.org/repo/flathub.flatpakrepo
</code></pre></div></div>

<p>Besides Flathub, there are other popular repositories as well. Please find below a table of popular Flatpak repositories and the corresponding commands to add them:</p>

<table>
  <thead>
    <tr>
      <th>Flatpak repo</th>
      <th>Command to add</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>kdeapps</td>
      <td>flatpak remote-add –if-not-exists kdeapps https://distribute.kde.org/kdeapps.flatpakrepo</td>
    </tr>
    <tr>
      <td>fedora</td>
      <td>flatpak remote-add –if-not-exists fedora oci+https://registry.fedoraproject.org</td>
    </tr>
    <tr>
      <td>gnome-nightly</td>
      <td>flatpak remote-add –if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo</td>
    </tr>
    <tr>
      <td>appcenter</td>
      <td>flatpak remote-add –if-not-exists –user appcenter https://flatpak.elementary.io/repo.flatpakrepo</td>
    </tr>
  </tbody>
</table>

<h2 id="finding-installing-and-unistalling-the-flatpak-app">Finding, installing and unistalling the flatpak app</h2>
<p>After adding the repositories, the most convenient way to discover and install Flatpak apps is through your system’s software center. For KDE, use ‘Discover,’ and for GNOME, use ‘GNOME Software Center.’</p>

<p>Simply search for your desired app, and once the results are displayed, click on the ‘Install’ button in the app list. You can easily identify Flatpak packages by the Flatpak symbol located at the top right corner of the list items. You can uninstall a Flatpak package in the same manner.</p>
<h2 id="using-the-flatpak-cli">Using the flatpak cli</h2>
<p>You can also utilize a command-line interface (CLI) for Flatpak, enabling you to perform all of the aforementioned tasks and a wide range of additional functions.</p>

<p>Here are a few essential Flatpak commands:</p>
<h3 id="see-the-list-of-added-flatpak-remote-repositories">See the list of added flatpak remote repositories</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak remotes <span class="nt">--columns</span><span class="o">=</span>name,url
</code></pre></div></div>
<h3 id="add-the-flatpak-remote-repository">Add the flatpak remote repository</h3>
<p>See <a href="#add-flatpak-app-repositories">Add Flatpak repostories</a> section.</p>
<h3 id="remove-the-flatpak-remote-repository">Remove the flatpak remote repository</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak remote-delete &lt;remote_name&gt;
</code></pre></div></div>
<p>An ex: <code class="language-plaintext highlighter-rouge">flatpak remote-delete flathub</code></p>
<h3 id="list-available-software-packages-on-the-remote">List available software packages on the remote</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak remote-ls &lt;remote_name&gt;
</code></pre></div></div>
<h3 id="search-for-an-app-in-the-repositories">Search for an app in the repositories:</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak search &lt;search_pattern&gt; <span class="nt">--columns</span><span class="o">=</span>name,application,description
</code></pre></div></div>
<p>As an example, let’s locate the Microsoft Teams package and install it. Execute the following command to search for <em>teams</em> using Flatpak:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak search teams <span class="nt">--columns</span><span class="o">=</span>name,application,description
</code></pre></div></div>
<p>The output may be extensive, but we have successfully identified the accurate entry for Microsoft Teams:</p>

<table>
  <thead>
    <tr>
      <th>Name                  </th>
      <th>   Application ID                        </th>
      <th>        Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>teams-for-linux      </td>
      <td>    com.github.IsmaelMartinez.teams_for_linux</td>
      <td>    Unofficial Microsoft Teams client for Linux using Electron</td>
    </tr>
  </tbody>
</table>

<p>Please make a note of the <em>Application ID</em> provided above. We will be using this value in the subsequent commands. For <em>teams-for-linux</em>, the <em>Application ID</em> is <em>com.github.IsmaelMartinez.teams_for_linux</em>.</p>
<h3 id="install-the-app">Install the app</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak <span class="nb">install</span> &lt;Application ID&gt;
</code></pre></div></div>
<p>To install the Microsoft Teams:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak <span class="nb">install </span>com.github.IsmaelMartinez.teams_for_linux
</code></pre></div></div>
<h3 id="run-the-application">Run the application</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak run &lt;Application ID&gt;
</code></pre></div></div>
<h3 id="see-installed-applications">See installed applications</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak list
</code></pre></div></div>
<h3 id="uninstall-the-applicaiton">Uninstall the applicaiton</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak uninstall &lt;Application ID&gt;
</code></pre></div></div>
<h3 id="update-the-packages-to-latest-versions">Update the packages to latest versions</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>flatpak update
</code></pre></div></div>

<p>Please refer <a href="https://docs.flatpak.org/en/latest/flatpak-command-reference.html">Flatpak Command Line Reference</a> for full list of commands.</p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[Flatpak is a packaging format specifically designed to enable applications to run seamlessly on any Linux distribution, be it Debian, Fedora, OpenSUSE, Arch, or other family of Linux distributions.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/install-flatpak.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/install-flatpak.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Managing Remote Terminal Sessions with Tmux</title><link href="https://www.embedded.pub/linux/tools/tmux-manage-remote-sessions.html" rel="alternate" type="text/html" title="Managing Remote Terminal Sessions with Tmux" /><published>2023-09-09T16:43:29+00:00</published><updated>2023-09-09T16:43:29+00:00</updated><id>https://www.embedded.pub/linux/tools/tmux-manage-remote-sessions</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/tmux-manage-remote-sessions.html"><![CDATA[<p>I primarily work on my remote system, using it as my build system to compile images for my target development boards. I prefer to keep alive my remote session for several reasons:</p>

<ol>
  <li>The build process can take hours to complete, and if my internet connection is interrupted, the shell session may be disrupted, potentially causing the build to fail.</li>
  <li>I would like to power off my local systems and return later to monitor the compilation progress.</li>
  <li>I intend to resume my work right where I left off.</li>
</ol>

<p>Fortunately, there exists a Linux tool called <strong><em>tmux</em></strong>, which can accomplish much more than the requirements I initially had in mind.</p>

<p><a href="/assets/linux/tools/tmux-manage-remote-session.png"><img src="/assets/linux/tools/tmux-manage-remote-session.png" alt="Tmux Manage Remote Sessions" /></a></p>

<p>Tmux serves as a terminal multiplexer, enabling you to create and manage multiple shell sessions within a single local system terminal or within a single remote SSH connection. Especially during an SSH session, you don’t need to start another SSH connection to have two terminals open side by side on the remote server.</p>

<p>Let’s explore how to utilize tmux for the management of terminal sessions.</p>
<h2 id="starting-a-new-session">Starting a new session</h2>
<p>Launch the terminal on your local system or log in to your remote server via SSH. To create a tmux session, employ the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux new <span class="nt">-s</span> &lt;sessionName&gt;
</code></pre></div></div>
<p>An example of this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux new <span class="nt">-s</span> buildroot_build
</code></pre></div></div>
<h2 id="detaching-a-tmux-session">Detaching a tmux session</h2>
<p>Pressing <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">d</code> will terminate a tmux session. To detach from the current session while keeping it running, use the following key sequence:  <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">d</code></p>

<h2 id="list-the-tmux-sessions">List the tmux sessions</h2>
<p>The command <code class="language-plaintext highlighter-rouge">tmux ls</code> displays all the tmux sessions currently running on the system.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tmux <span class="nb">ls  
</span>buildroot_build: 1 windows <span class="o">(</span>created Sat Sep  9 21:29:31 2023<span class="o">)</span>  
yocto_build: 1 windows <span class="o">(</span>created Sat Sep  9 21:29:59 2023<span class="o">)</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">buildroot_build</code> and <code class="language-plaintext highlighter-rouge">yocto_build</code> are two tmux sessions alive.</p>
<h2 id="attaching-to-a-tmux-session">Attaching to a tmux session</h2>
<p>From the output of the <code class="language-plaintext highlighter-rouge">tmux ls</code> command, you can identify all the tmux session names. To attach to a specific tmux session and resume your work from where you left off, use the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux a <span class="nt">-t</span> &lt;sessionName&gt;
</code></pre></div></div>
<p>Let’s say one of tmux session name is <code class="language-plaintext highlighter-rouge">yocto_build</code> then to attach to that terminal session, use the command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tmux a <span class="nt">-t</span> yocto_build
</code></pre></div></div>

<h2 id="splitting-the-terminal-pane">Splitting the Terminal pane</h2>
<p>This is the best part of working with tmux. If you prefer not to disrupt your current terminal session and need another terminal session on your remote system, you can achieve this without initiating a new SSH session.</p>

<p>To split the terminal pane vertically, press the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">%</code> ( <code class="language-plaintext highlighter-rouge">Shift</code>+<code class="language-plaintext highlighter-rouge">5</code>)</p>

<p>To split the terminal pane horizontally, press the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">"</code> (<code class="language-plaintext highlighter-rouge">Shift</code>+<code class="language-plaintext highlighter-rouge">'</code>).</p>

<p><a href="/assets/linux/tools/tmux/tmux-split-pane.png"><img src="/assets/linux/tools/tmux/tmux-split-pane.png" alt="Tmux split panes" /></a></p>
<h3 id="switching-between-the-panes">Switching between the panes</h3>
<p>Employ <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> in conjunction with the arrow keys to navigate between panes.</p>
<ul>
  <li>To move the cursor to the right pane, use <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <strong>→</strong> (Right Arrow).</li>
  <li>To move the cursor to the left pane, use <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <strong>←</strong> (Left Arrow).</li>
  <li>To move the cursor to the top pane, use <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <strong>↑</strong> (Up Arrow)</li>
  <li>To move the cursor to the bottom pane, use <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <strong>↓</strong> (Down Arrow)</li>
</ul>

<h3 id="resizing-the-panes">Resizing the panes</h3>
<p>Hold <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code>, don’t release it and hold one of the arrow keys.</p>
<h2 id="creating-new-window">Creating new window</h2>
<p>Use the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">c</code>.</p>
<h3 id="switching-between-windows">Switching between windows</h3>
<p>Use the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">n</code> to move to next window. And use <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code> followed by <code class="language-plaintext highlighter-rouge">p</code> to move to previous window.</p>
<h2 id="scrolling-in-tmux">Scrolling in tmux</h2>
<p>By default, in tmux, mouse scrolling or Page Up/Down keys <em>do not work</em>. To enable scrolling, press <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">b</code>, followed by <code class="language-plaintext highlighter-rouge">[</code>. Now you can use the <em>vim</em> editor navigation keys (<code class="language-plaintext highlighter-rouge">j</code>, <code class="language-plaintext highlighter-rouge">k</code>, <code class="language-plaintext highlighter-rouge">l</code>, <code class="language-plaintext highlighter-rouge">h</code>, <code class="language-plaintext highlighter-rouge">g</code> etc.) or simple <em>arrow keys</em> and <em>PageUp/Down</em> keys to navigate around terminal text.</p>

<p class="warning">While in scrolling mode, you can’t use any other keys</p>
<h3 id="quit-scrolling">Quit scrolling</h3>
<p>Press <code class="language-plaintext highlighter-rouge">q</code> to quit scrolling.</p>

<p>I hope this tutorial is helpful. For more information, you can refer to the man page by using the command <code class="language-plaintext highlighter-rouge">man tmux</code>.</p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[I primarily work on my remote system, using it as my build system to compile images for my target development boards. I prefer to keep alive my remote session for several reasons:]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/tmux-manage-remote-session.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/tmux-manage-remote-session.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Creating Blog Post Feature Image Using Inkscape</title><link href="https://www.embedded.pub/linux/tools/blog-post-feature-image-inkscape.html" rel="alternate" type="text/html" title="Creating Blog Post Feature Image Using Inkscape" /><published>2023-09-07T17:39:27+00:00</published><updated>2023-09-07T17:39:27+00:00</updated><id>https://www.embedded.pub/linux/tools/blog-post-feature-image-inkscape</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/blog-post-feature-image-inkscape.html"><![CDATA[<p>Inkscape is an SVG image editor. We utilize Inkscape to create SVG images and subsequently export them to the PNG format for inclusion in web pages. Let’s begin with generating a feature image for the blog using Inkscape.</p>

<p><a href="/assets/linux/tools/blog-feature-image-inkscape.png"><img src="/assets/linux/tools/blog-feature-image-inkscape.png" alt="Blog Feature Image using Inkscape" /></a></p>
<h2 id="installing-inkscape">Installing Inkscape</h2>
<p>To install Inkscape on Debian/Ubuntu-based systems, execute the following command in the terminal:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt <span class="nb">install </span>inkscape
</code></pre></div></div>

<h2 id="starting-the-app">Starting the app</h2>
<p>Launch the Inkscape application from the Applications launcher. In the <code class="language-plaintext highlighter-rouge">Quick Setup</code> tab, you’ll find three fields to configure. I prefer the <em>Dark Canvas</em>, so I’ve changed it to that and saved the configuration. Click on <code class="language-plaintext highlighter-rouge">Thanks</code> in the <code class="language-plaintext highlighter-rouge">Supported by You</code> tab. In the <code class="language-plaintext highlighter-rouge">Time to Draw</code> tab, click the <code class="language-plaintext highlighter-rouge">New Document</code> button to start drawing an SVG image.</p>

<!--
[![Inkscape welcome screen](https://i.imgur.com/e9KbXXC.gif)](https://i.imgur.com/e9KbXXC.gif)
-->
<p><a href="/assets/linux/tools/feature-img/inkscape-welcome.gif"><img src="/assets/linux/tools/feature-img/inkscape-welcome.gif" alt="Inkscape welcome screen" /></a></p>
<h2 id="draw-a-rectangular-region">Draw a rectangular region</h2>

<p>The recommended dimensions for a blog post feature image are <em>1200x628</em> pixels. Let’s create a rectangular region with those dimensions. The steps are as follows:</p>

<p class="info">Click on the images to expand the view.</p>

<hr />
<ul>
  <li>Click on the Rectangle icon located in the toolbox on the left side (Shortcut - <code class="language-plaintext highlighter-rouge">R</code>).
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-010.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-010.png" alt="Inkscape rectangle icon in toolbox" /></a></li>
</ul>

<hr />
<ul>
  <li>Draw a rectangle of any size by dragging the mouse on the canvas.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-020.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-020.png" alt="Draw rectangle on Inkscape canvas" /></a></li>
</ul>

<hr />
<ul>
  <li>You’ll find the Width and Height parameters in the Tool Controls Bar. Manually enter the width as <em>1200</em> and the height as <em>628</em> as shown in the below picture.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-030.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-030.png" alt="Change dimensions inkscape rectangle" /></a></li>
</ul>

<hr />
<ul>
  <li>Resize the Canvas page to match the drawing. This ensures that when you save the image, it will have exact dimensions of the rectangle you’ve drawn. You can use the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">Shift</code>+<code class="language-plaintext highlighter-rouge">R</code> to do it automatically or follow the below procedure.</li>
  <li>Go to <em>File -&gt; Document Preperties… -&gt; Resize page to drawing or selection (Ctrl+Shift+R)</em>
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-adjust-canvas.gif"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-adjust-canvas.gif" alt="Inkscape adjust canvas to match drawing" /></a></li>
</ul>

<h2 id="choose-color-and-gradient">Choose color and gradient</h2>
<ul>
  <li>You can change the color of your rectangle by selecting one of the colors from the palette below. 
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-070.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-070.png" alt="Change rectangular region color" /></a></li>
</ul>

<hr />
<ul>
  <li>I’ve chosen the green color, as you can see in the picture below. Let’s apply the Mesh gradient to the rectangle.</li>
  <li>Open the <em>Fill and Stroke</em> panel by pressing the shortcut <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">Shift</code>+<code class="language-plaintext highlighter-rouge">F</code>.  Alternatively, you can open the same by clicking on <em>Object</em> -&gt; <em>Fill and Stroke…</em> from the menu.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-080.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-080.png" alt="Navigate Fill and Stroke pane" /></a></li>
</ul>

<hr />
<ul>
  <li>Once the <em>Fill and Stroke</em> pane is opened, click on the <em>Mesh gradient</em> icon.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-090.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-090.png" alt="Apply Mesh Gradient" /></a></li>
</ul>

<hr />
<ul>
  <li>As you can see the picture has turned out nicely. I’ve also adjusted the Blur effect to be 10%, as you can see in the bottom right.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-100.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-100.png" alt="Inkscape image blur" /></a></li>
</ul>

<hr />
<ul>
  <li>Navigate to the ‘Stroke style’ tab in the ‘Fill and Stroke’ pane. Change the width to 0.5.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-110.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-110.png" alt="Inkscape border width" /></a></li>
</ul>

<h2 id="add-the-images">Add the images</h2>
<ul>
  <li>Drag the images onto the canvas that you want to add to the feature image. Inkscape works seamlessly with SVG images. I imported ‘inkscape.svg’ onto the canvas, and during import, I selected the option ‘<em>Include SVG Image as editable object(s) in the current file</em>’.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-120.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-120.png" alt="Inkscape import svg" /></a></li>
</ul>

<hr />
<ul>
  <li>The image may be difficult to see if it’s small. However, you can adjust the dimensions of the image in the ‘<em>Tool Controls Bar</em>’. Use the ‘Select’ tool (Shortcut <code class="language-plaintext highlighter-rouge">S</code>) to drag and adjust the image’s position.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-adjust-import-image.gif"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-adjust-import-image.gif" alt="Import image adjust dimentions" /></a></li>
</ul>

<h2 id="add-the-text">Add the text</h2>
<ul>
  <li>Now it’s time to add the post title to the image. Select the Text icon (Shortcut <code class="language-plaintext highlighter-rouge">T</code>).
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-150.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-150.png" alt="Inkscape text icon" /></a></li>
</ul>

<hr />
<ul>
  <li>Click on the canvas where you want your blog post title to appear. Type the title. Pressing <code class="language-plaintext highlighter-rouge">Ctrl</code>+<code class="language-plaintext highlighter-rouge">A</code> now selects the whole title. You can change the font properties, such as font type, font size, etc., from the <em>Tool Controls bar</em>. I’ve discovered a few fonts that I believe will look appealing for the titles. <em>Chilanka font</em>, <em>Dyuthi</em>, <em>Liberation Serif</em>, <em>Noto Serif Display</em> and <em>Purisa</em>.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-160.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-160.png" alt="Inkscape add text to canvas" /></a></li>
</ul>

<hr />
<ul>
  <li>To move the text to the desired location on the canvas, employ the select tool, click on the title, and then drag it to the desired position.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-170.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-170.png" alt="Inkscape drag the text" /></a></li>
</ul>

<hr />
<ul>
  <li>Let’s enhance the text now. In Inkscape, fonts have both a ‘<em>Fill</em>’ and ‘<em>Stroke</em>.’ We can change the ‘<em>Fill</em>’ color by clicking on a color (I used 50% grey) from the palette. To modify the ‘<em>Stroke</em>’ color, press and hold the <code class="language-plaintext highlighter-rouge">Shift</code> key and then click on a color (I used 80% grey).</li>
  <li>Additionally, in the ‘<em>Stroke style</em>’ section of the ‘<em>Fill and Stroke</em>’ pane, we can fine-tune the ‘<em>Width</em>’ and ‘<em>Dashes</em>’ for further decoration.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-180.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-180.png" alt="Inkscape text fill and stroke" /></a></li>
</ul>

<h2 id="add-brand">Add brand</h2>
<ul>
  <li>You can also import PNG images onto the canvas, although SVG images are recommended. If you choose to import a PNG image, select <strong>Image DPI:</strong> as <strong>From file</strong> and set the <strong>Image Rendering Mode</strong> to <strong>None (auto)</strong>.</li>
  <li>I have my blog address as a PNG image, which represents my brand. I’ve positioned it in one corner of the canvas.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-brand-position.gif"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-brand-position.gif" alt="Inkscape import image" /></a></li>
</ul>

<h2 id="export-to-png-image">Export to png image</h2>
<ul>
  <li>Finally, go to ‘File’ -&gt; ‘Export PNG Image’ -&gt; ‘Export As…’ from the <code class="language-plaintext highlighter-rouge">Export PNG Image</code> pane.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-export-png.gif"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-export-png.gif" alt="Inkscape export svg to png 1" /></a></li>
</ul>

<h2 id="the-final-blog-feature-image">The final blog feature image</h2>
<ul>
  <li>Here is the final blog post feature image generated using the above steps in Inkscape.
<a href="/assets/linux/tools/feature-img/inkscape-feature-image-999.png"><img src="/assets/linux/tools/feature-img/inkscape-feature-image-999.png" alt="Inkscape final feature image" /></a></li>
</ul>

<h2 id="resetting-the-inkscape">Resetting the inkscape</h2>
<p>Navigate to Edit -&gt; Preferences -&gt; System -&gt; Click on <code class="language-plaintext highlighter-rouge">Reset Preferences</code></p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[Inkscape is an SVG image editor. We utilize Inkscape to create SVG images and subsequently export them to the PNG format for inclusion in web pages. Let’s begin with generating a feature image for the blog using Inkscape.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/blog-feature-image-inkscape.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/blog-feature-image-inkscape.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Auto Send RSS Feed Updates to Your Inbox with rss2email</title><link href="https://www.embedded.pub/linux/tools/rss-to-email.html" rel="alternate" type="text/html" title="Auto Send RSS Feed Updates to Your Inbox with rss2email" /><published>2023-08-27T11:12:55+00:00</published><updated>2023-08-27T11:12:55+00:00</updated><id>https://www.embedded.pub/linux/tools/rss-to-email</id><content type="html" xml:base="https://www.embedded.pub/linux/tools/rss-to-email.html"><![CDATA[<p>I follow a lot of tech blogs and YouTube channels, and I used to subscribe to them all via email. This was convenient, but not all blogs offer email subscription (such as <a href="https://bootlin.com/">bootlin.com</a>), and some people don’t want to submit their email addresses for privacy reasons.</p>

<p>Most blogs offer RSS or Atom feeds, which allow you to subscribe without giving out your email address. However, you still need a feed aggregator to scan for updates. A good option is to use the rss2email utility, which can deliver all of your blog/Youtube channel updates directly to your inbox. You can even set up rss2email to run as a system daemon, so it will automatically scan for updates at regular intervals.</p>

<p>This post will show you how to install, configure, and run rss2email as a system daemon on Ubuntu. This will allow rss2email to scan for feed updates at regular intervals and deliver them to your inbox.</p>

<p><img src="/assets/linux/tools/rss2email-post.png" alt="Send Web feeds such as RSS/Atom to you E-Mail" /></p>

<h2 id="installing-rss2email">Installing rss2email</h2>
<p>To install rss2email utility on Debain/Ubuntu based systems, run the following command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>apt <span class="nb">install </span>rss2email sendmail
</code></pre></div></div>
<p>From this point onwards, we will be running commands as the root user. Otherwise, we may encounter problems when configuring rss2email as a daemon later on.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>su -
</code></pre></div></div>
<h2 id="add-recipient-e-mail-address">Add recipient e-mail address</h2>
<p>This is the e-mail address that will receive all the feed updates from rss2email utility. This step is one time configuration.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2e new &lt;recipient_mail_id&gt; 
</code></pre></div></div>
<h2 id="configuring-the-rss2email">Configuring the rss2email</h2>
<p>Edit the configuration file  <em>$HOME/.config/rss2email.cfg</em> as follows.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vi <span class="nv">$HOME</span>/.config/rss2email.cfg
</code></pre></div></div>

<p>In the <em>from</em> field, I use my Gmail address as the <em>sender_mail_id</em>. This is different from the <em>recipient_mail_id</em> mentioned above. Therefore, when there is a blog update, you will receive an email to the <em>recipient_mail_id</em> that appears to have come from the <em>sender_mail_id</em></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from <span class="o">=</span> &lt;sender_email_id&gt;
force-form <span class="o">=</span> True
to <span class="o">=</span> &lt;recipient_mail_id&gt;
</code></pre></div></div>
<h2 id="configuring-smtp-settings-to-send-the-email-through-rss2email">Configuring SMTP settings to send the email through rss2email</h2>
<p>Let’s use <em>ssmtp</em> utility to configure SMTP settings on Ubuntu. First, let’s install the <em>sstmp</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>ssmtp
</code></pre></div></div>

<p>Edit the ssmtp configuration file <em>/etc/ssmtp/ssmtp.conf</em> according to your email provider’s SMTP settings. As I have been using Gmail as my <em>sender_mail_id</em>, the configuration looks like the following:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">root</span><span class="o">=</span>&lt;your_gmail_id&gt;
<span class="nv">mailhub</span><span class="o">=</span>smtp.gmail.com:587
<span class="nv">AuthUser</span><span class="o">=</span>&lt;your_gmail_id&gt;
<span class="nv">AuthPass</span><span class="o">=</span>&lt;gmail_pass or app_pass&gt;
<span class="nv">UseTLS</span><span class="o">=</span>YES
<span class="nv">UseSTARTTLS</span><span class="o">=</span>YES
</code></pre></div></div>
<p>If you have <strong>two-factor authentication (2FA)</strong> enabled for your Gmail account, you may need to <a href="https://support.google.com/accounts/answer/185833?hl=en"><strong>create an app password</strong></a> to use with rss2email.</p>
<h2 id="using-the-rss2email">Using the rss2email</h2>
<p>Let’s learn how to add a blog feed to rss2email, so it can scan for new blog posts and send you updates in your email.</p>

<p>You can find RSS/Atom feed URL of any blog/YouTube using <a href="https://zapier.com/blog/how-to-find-rss-feed-url/">this guide</a>. Once you get the URL of the feed, use the following command to add it to rss2email.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2e add &lt;feedName&gt; &lt;feedURL&gt;
</code></pre></div></div>
<p>Give the <em>feedName</em>  a value such as name of the blog. An example is give below.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2e add NayabSDBlog https://www.nayab.dev/feed.xml
</code></pre></div></div>
<p>You can add as many feeds as you like using the same command.</p>
<h2 id="scan-for-new-blog-posts">Scan for new blog posts</h2>
<p>Once you are satisfied with the number of feeds you have added, you can start sending all feed updates to your inbox by running the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2e run
</code></pre></div></div>
<p>Beware that if the feed has many posts, you may receive a lot of emails.</p>

<p>If your RSS feed has a lot of posts, and you don’t want to receive all of them in your inbox, run the following command. This command only needs to be run once per addition of blog feeds. And any subsequent blog/YouTube updates, you will get by running above command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2e run <span class="nt">--no-send</span> <span class="c"># Just scans but won't send e-mails.</span>
</code></pre></div></div>
<h2 id="create-a-systemd-timer-for-automatic-periodic-updates">Create a systemd timer for automatic periodic updates</h2>
<p>We can use systemd timers to get periodic updates from the rss2email daemon service. To do this, we first need to create a systemd service file that the systemd timer can use.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> <span class="o">&lt;&lt;</span> <span class="no">EOF</span><span class="sh"> &gt;&gt; /lib/systemd/system/rss2email.service
[Unit]
Description=Fetches RSS feeds and send them to email
Wants=rss2email.timer

[Service]
ExecStart=/usr/bin/r2e run

[Install]
WantedBy=multi-user.target
</span><span class="no">EOF
</span></code></pre></div></div>
<p>Enable the rss2email service with the below command. This step is optional as we invoke this service anyways with the systemd timers.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl <span class="nb">enable </span>rss2email.service
</code></pre></div></div>

<p>This creates a symbolic link <em>/etc/systemd/system/multi-user.target.wants/rss2email.service</em> that points to the target file in <em>/lib/systemd/system/rss2email.service</em>. This ensures that the service will be started when the system boots.</p>

<p>Now, let’s write a <em>rss2email.timer</em> file.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> <span class="o">&lt;&lt;</span> <span class="no">EOF</span><span class="sh"> &gt;&gt; /lib/systemd/system/rss2email.timer
[Unit]
Description=calling rss2email peridically
Requires=rss2email.service

[Timer]
Unit=rss2email.service
OnCalendar=*-*-* 00/6:00:00

[Install]
WantedBy=timers.target
</span><span class="no">EOF
</span></code></pre></div></div>
<p>Start and enable the timer with the following commands. Enabling timer will start the service when the system boots.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl start rss2email.timer
systemctl <span class="nb">enable </span>rss2email.timer
</code></pre></div></div>
<p>The above <em>rss2email.timer</em> invokes the <em>rss2email.service</em> for every 6 hours. You can see that from the line <em>OnCalendar=*-*-* 00/6:00:00</em></p>

<p>Once the timer triggers the rss2email service, all the blog and YouTube channel updates that you have enrolled with rss2email will be automatically sent to your inbox.</p>

<p>You can read more about systemd timer <a href="https://opensource.com/article/20/7/systemd-timers">here</a></p>
<h2 id="commands-for-troubleshooting">Commands for troubleshooting</h2>
<h3 id="checking-the-servicetimer-status">Checking the service/timer status</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl status rss2email.service
systemctl status rss2email.timer
</code></pre></div></div>
<h3 id="checking-the-servicetimer-logs">Checking the service/timer logs</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-u</span> rss2email.service
journalctl <span class="nt">-u</span> rss2email.timer
</code></pre></div></div>
<p>You can read more about journalctl <a href="https://www.loggly.com/ultimate-guide/using-journalctl/">here</a></p>
<h3 id="commands-to-start-and-stop-the-services">Commands to start and stop the services</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For rss2email.service</span>
systemctl start rss2email.service
systemctl stop rss2email.service

<span class="c"># For rss2email.timer</span>
systemctl start rss2email.timer
systemctl stop rss2email.timer
</code></pre></div></div>
<h2 id="example-logs-of-rss2emailservice">Example logs of rss2email.service</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Aug 15 05:39:39 dosing r2e[9960]: 2023-08-15 05:39:39,720 <span class="o">[</span>INFO] fetch NayabSDBlog <span class="o">(</span>https://www.nayab.dev/feed.xml -&gt; basha@nayab.dev<span class="o">)</span>
Aug 15 05:39:39 dosing r2e[9960]: 2023-08-15 05:39:39,766 <span class="o">[</span>INFO] process NayabSDBlog <span class="o">(</span>https://www.nayab.dev/feed.xml -&gt; basha@nayab.dev<span class="o">)</span>
Aug 15 05:39:39 dosing r2e[9960]: 2023-08-15 05:39:39,769 <span class="o">[</span>INFO] send message <span class="k">for </span>NayabSDBlog <span class="o">(</span>https://www.nayab.dev/feed.xml -&gt; basha@nayab.dev<span class="o">)</span>
Aug 15 05:39:39 dosing sSMTP[9964]: Creating SSL connection to host
Aug 15 05:39:40 dosing sSMTP[9964]: SSL connection using ECDHE_RSA_AES_256_GCM_SHA384
Aug 15 05:39:42 dosing sSMTP[9964]: Sent mail <span class="k">for </span>root@dosing <span class="o">(</span>221 2.0.0 closing connection p21-20020aa78615000000b00687260020b1sm8792938pfn.72 - gsmtp<span class="o">)</span> <span class="nv">uid</span><span class="o">=</span>0 <span class="nv">username</span><span class="o">=</span>root <span class="nv">outbytes</span><span class="o">=</span>1450
Aug 15 05:39:42 dosing r2e[9960]: 2023-08-15 05:39:42,880 <span class="o">[</span>INFO] send message <span class="k">for </span>NayabSDBlog <span class="o">(</span>https://www.nayab.dev/feed.xml -&gt; basha@nayab.dev<span class="o">)</span>
Aug 15 05:39:42 dosing sSMTP[9969]: Creating SSL connection to host
Aug 15 05:39:43 dosing sSMTP[9969]: SSL connection using ECDHE_RSA_AES_256_GCM_SHA384
Aug 15 05:39:45 dosing sSMTP[9969]: Sent mail <span class="k">for </span>root@dosing <span class="o">(</span>221 2.0.0 closing connection k17-20020aa78211000000b0063b898b3502sm8800095pfi.153 - gsmtp<span class="o">)</span> <span class="nv">uid</span><span class="o">=</span>0 <span class="nv">username</span><span class="o">=</span>root <span class="nv">outbytes</span><span class="o">=</span>1298
Aug 15 05:39:45 dosing r2e[9960]: 2023-08-15 05:39:45,891 <span class="o">[</span>INFO] send message <span class="k">for </span>NayabSDBlog <span class="o">(</span>https://www.nayab.dev/feed.xml -&gt; basha@nayab.dev<span class="o">)</span>
Aug 15 05:39:45 dosing sSMTP[9970]: Creating SSL connection to host
</code></pre></div></div>
<h2 id="running-rss2email-on-ubuntu-server">Running rss2email on Ubuntu server</h2>
<p>There are several benefits to running rss2email on a cloud server. First, it is more scalable. If you want to subscribe to a large number of RSS feeds, or if you want to have rss2email scan for updates more frequently, a cloud server will be able to handle the load. Second, it is more reliable. A cloud server is less likely to experience outages than a personal computer.</p>

<p>If you are looking to register for a cloud provider, <a href="https://www.embedded.pub/digitalocean">Digitalocean</a> is great option. You get $200 credit over 60 days period.</p>

<h2 id="references">References</h2>
<p><a href="https://www.linuxbabe.com/ubuntu/install-use-rss2email-ubuntu-18-04">https://www.linuxbabe.com/ubuntu/install-use-rss2email-ubuntu-18-04</a>
<a href="https://www.freedesktop.org/software/systemd/man/systemd.time.html">https://www.freedesktop.org/software/systemd/man/systemd.time.html</a>
<a href="https://unix.stackexchange.com/questions/126786/systemd-timer-every-15-minutes">https://unix.stackexchange.com/questions/126786/systemd-timer-every-15-minutes</a>
<a href="https://silentlad.com/systemd-timers-oncalendar-(cron)-format-explained">https://silentlad.com/systemd-timers-oncalendar-(cron)-format-explained</a></p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="tools" /><summary type="html"><![CDATA[I follow a lot of tech blogs and YouTube channels, and I used to subscribe to them all via email. This was convenient, but not all blogs offer email subscription (such as bootlin.com), and some people don’t want to submit their email addresses for privacy reasons.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/tools/rss2email-post.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/tools/rss2email-post.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Colorize Terminal Text with Escape Sequences in Linux</title><link href="https://www.embedded.pub/linux/misc/escape-codes.html" rel="alternate" type="text/html" title="Colorize Terminal Text with Escape Sequences in Linux" /><published>2023-08-20T04:38:52+00:00</published><updated>2023-08-20T04:38:52+00:00</updated><id>https://www.embedded.pub/linux/misc/escape-codes</id><content type="html" xml:base="https://www.embedded.pub/linux/misc/escape-codes.html"><![CDATA[<h2 id="escape-sequence-in-linux">Escape sequence in Linux</h2>
<p>ANSI escape codes can be used to style the output of <em>echo</em> or <em>printf</em>. An escape code is a sequence of characters start with an <code class="language-plaintext highlighter-rouge">ESC</code>(033 in Octal representation) character, followed by second character in the ASCII range 64 to 95. This sequence can be of different length.</p>

<p><img src="/assets/linux/misc/escape-codes.png" alt="Terminal text styling with escape codes" /></p>

<p>The general format of escape code for styling the terminal text is -</p>

<p><code class="language-plaintext highlighter-rouge">ESC</code> <code class="language-plaintext highlighter-rouge">[</code> <code class="language-plaintext highlighter-rouge">{attr1};{attr2};....{attrn)m</code>.</p>

<p>The ASCII equivalent of <code class="language-plaintext highlighter-rouge">ESC</code> character is <em>033(in Octal)</em> or <em>0x1b(in Hexadecimal)</em>. We use 033 because it works for all operating systems.</p>

<p>Some examples for escape codes are -</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'\033[0m'       #Reset text
'\033[0;33m'    #Yello color text
'\033[42m'      #Green background
'\033[1;42m'    #Bold text with Green background
</code></pre></div></div>
<p>Note that above escape code sequeces ends with <code class="language-plaintext highlighter-rouge">m</code> and there is no <code class="language-plaintext highlighter-rouge">;</code> before that.</p>

<p>If we examine the code ‘\033[1;42m’,</p>

<table>
  <thead>
    <tr>
      <th>\033</th>
      <th>[</th>
      <th>1</th>
      <th>;</th>
      <th>42</th>
      <th>m</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Octal value of ESC char.</td>
      <td>left square bracket</td>
      <td>Attribute 1 (bold)</td>
      <td>Divider</td>
      <td>Attribute 2 (Green)</td>
      <td>Ending Char</td>
    </tr>
  </tbody>
</table>

<h2 id="usage-with-echo">Usage with <em>echo</em></h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="nt">-e</span> <span class="s1">'\033[1;42m'</span>This is text with green background
</code></pre></div></div>
<p>Don’t forget to use <em>-e</em> option along with <em>echo</em> command. Any text following the above code sequence will print with green background color.</p>
<h2 id="usage-with-printf">Usage with <em>printf</em></h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">printf</span> <span class="s1">'\033[1;42m'</span>This is text with green background
</code></pre></div></div>
<h2 id="text-formatting">Text formatting</h2>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Escape Code</th>
      <th>Text Style</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>‘\033[0;31m’</td>
      <td>Regular</td>
    </tr>
    <tr>
      <td>1</td>
      <td>‘\033[1;31m’</td>
      <td>Bold</td>
    </tr>
    <tr>
      <td>2</td>
      <td>‘\033[2;31m’</td>
      <td>Low Intensity</td>
    </tr>
    <tr>
      <td>3</td>
      <td>‘\033[3;31m’</td>
      <td>Italic</td>
    </tr>
    <tr>
      <td>4</td>
      <td>‘\033[4;31m’</td>
      <td>Underline</td>
    </tr>
    <tr>
      <td>5</td>
      <td>‘\033[5;31m’</td>
      <td>Blinking</td>
    </tr>
    <tr>
      <td>6</td>
      <td>‘\033[6;31m’</td>
      <td>Reverse</td>
    </tr>
    <tr>
      <td>7</td>
      <td>‘\033[7;31m’</td>
      <td>Background</td>
    </tr>
    <tr>
      <td>8</td>
      <td>‘\033[8;31m’</td>
      <td>Invisible</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/linux/misc/terminal-text-decoration.png" alt="Terminal text decoration with escape codes" /></p>

<h2 id="text-color">Text Color</h2>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Escape Code</th>
      <th>Text Color</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>30</td>
      <td>‘\033[0;30m’</td>
      <td>Black</td>
    </tr>
    <tr>
      <td>31</td>
      <td>‘\033[0;31m’</td>
      <td>Red</td>
    </tr>
    <tr>
      <td>32</td>
      <td>‘\033[0;32m’</td>
      <td>Green</td>
    </tr>
    <tr>
      <td>33</td>
      <td>‘\033[0;33m’</td>
      <td>Yello</td>
    </tr>
    <tr>
      <td>34</td>
      <td>‘\033[0;34m’</td>
      <td>Blue</td>
    </tr>
    <tr>
      <td>35</td>
      <td>‘\033[0;35m’</td>
      <td>Magenta</td>
    </tr>
    <tr>
      <td>36</td>
      <td>‘\033[0;36m’</td>
      <td>Cyan</td>
    </tr>
    <tr>
      <td>37</td>
      <td>‘\033[0;37m’</td>
      <td>White</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/linux/misc/terminal-text-color.png" alt="Terminal text color with escape codes" /></p>

<h2 id="background-color">Background color</h2>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Escape Code</th>
      <th>Background Color</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>40</td>
      <td>‘\033[0;40m’</td>
      <td>Black</td>
    </tr>
    <tr>
      <td>41</td>
      <td>‘\033[0;41m’</td>
      <td>Red</td>
    </tr>
    <tr>
      <td>42</td>
      <td>‘\033[0;42m’</td>
      <td>Green</td>
    </tr>
    <tr>
      <td>43</td>
      <td>‘\033[0;43m’</td>
      <td>Yello</td>
    </tr>
    <tr>
      <td>44</td>
      <td>‘\033[0;44m’</td>
      <td>Blue</td>
    </tr>
    <tr>
      <td>45</td>
      <td>‘\033[0;45m’</td>
      <td>Magenta</td>
    </tr>
    <tr>
      <td>46</td>
      <td>‘\033[0;46m’</td>
      <td>Cyan</td>
    </tr>
    <tr>
      <td>47</td>
      <td>‘\033[0;47m’</td>
      <td>White</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/linux/misc/terminal-text-bg-color.png" alt="Terminal text with Background Color" /></p>

<h2 id="random-text-stype-attributes">Random text stype attributes</h2>

<p>One or more attributes can be clubbed together for more styling.</p>

<p><img src="/assets/linux/misc/random-text-attributes.png" alt="Terminal text with Random Text attributes" /></p>

<h2 id="a-simple-color-echo-solution-for-shell-scripts">A simple color echo solution for shell scripts</h2>

<p>Save the following code in a file, let’s say <em>cecho.sh</em></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cecho<span class="o">()</span> <span class="o">{</span>
	<span class="nb">local </span><span class="nv">code</span><span class="o">=</span><span class="s2">"</span><span class="se">\0</span><span class="s2">33["</span>
	<span class="k">case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="k">in
		</span>black  <span class="p">|</span> bk<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">0;30m"</span><span class="p">;;</span>
		red    <span class="p">|</span>  r<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;31m"</span><span class="p">;;</span>
		green  <span class="p">|</span>  g<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;32m"</span><span class="p">;;</span>
		yellow <span class="p">|</span>  y<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;33m"</span><span class="p">;;</span>
		blue   <span class="p">|</span>  b<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;34m"</span><span class="p">;;</span>
		purple <span class="p">|</span>  p<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;35m"</span><span class="p">;;</span>
		cyan   <span class="p">|</span>  c<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">1;36m"</span><span class="p">;;</span>
		gray   <span class="p">|</span> gr<span class="p">)</span> <span class="nv">color</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">0;37m"</span><span class="p">;;</span>
		<span class="k">*</span><span class="p">)</span> <span class="nb">local </span><span class="nv">text</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
			<span class="k">esac</span>
			<span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$text</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">local </span><span class="nv">text</span><span class="o">=</span><span class="s2">"</span><span class="nv">$color$2</span><span class="k">${</span><span class="nv">code</span><span class="k">}</span><span class="s2">0m"</span>
			<span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="nv">$text</span><span class="s2">"</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Including the above file in any shell script will allow us to print color text on terminal.</p>

<p>Let’s say file <code class="language-plaintext highlighter-rouge">display.sh</code> has the following content.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nb">.</span> /path/to/cecho.sh

cecho red <span class="s2">"This is red text"</span>
</code></pre></div></div>
<p>Now executing second shell script will display output in red color.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bash display.sh
</code></pre></div></div>
<p><img src="/assets/linux/misc/cecho-red-text.png" alt="Color text on terminal using Shell script" /></p>
<h2 id="references">References</h2>
<p><a href="http://misc.flogisoft.com/bash/tip_colors_and_formatting">bash:tip_colors_and_formatting</a></p>

<p><a href="http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux">Stackoverflow: Change echo output</a></p>

<p><a href="http://www.termsys.demon.co.uk/vtansi.htm">Terminal color escape sequences</a></p>]]></content><author><name>Nayab Sayed</name></author><category term="linux" /><category term="misc" /><summary type="html"><![CDATA[Escape sequence in Linux ANSI escape codes can be used to style the output of echo or printf. An escape code is a sequence of characters start with an ESC(033 in Octal representation) character, followed by second character in the ASCII range 64 to 95. This sequence can be of different length.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.embedded.pub/assets/linux/misc/escape-sequences.png" /><media:content medium="image" url="https://www.embedded.pub/assets/linux/misc/escape-sequences.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>