<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Karolis Šarapnickis</title>
    <description>The latest articles on Forem by Karolis Šarapnickis (@karolis_sh).</description>
    <link>https://forem.com/karolis_sh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F202678%2Fc5b102e7-da70-4729-99b9-9962999f5ff3.jpg</url>
      <title>Forem: Karolis Šarapnickis</title>
      <link>https://forem.com/karolis_sh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/karolis_sh"/>
    <language>en</language>
    <item>
      <title>A Practical Shell Scripting Introduction for JavaScript Engineers</title>
      <dc:creator>Karolis Šarapnickis</dc:creator>
      <pubDate>Sat, 06 Nov 2021 13:53:10 +0000</pubDate>
      <link>https://forem.com/karolis_sh/a-practical-shell-scripting-introduction-for-javascript-engineers-2fbo</link>
      <guid>https://forem.com/karolis_sh/a-practical-shell-scripting-introduction-for-javascript-engineers-2fbo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Compact rundown though shell basics focusing on practical use cases in JavaScript projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When developing scripts, I always had a tendency to go for Node.js instead of shell, even for relatively simple things. Shell scripting has always been challenging for me, until I dedicated some time in learning the basics. Now I understand that, when used correctly, shell scripts can really simplify the logic. So, here are some core concepts and practical use cases that you can learn and hopefully apply in your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Commands
&lt;/h2&gt;

&lt;p&gt;Here is a list of some of the more common shell commands that you'd encounter in JS projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;echo&lt;/code&gt; - prints text terminal window (e.g., &lt;code&gt;echo Build is complete!&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Files and folders:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mkdir&lt;/code&gt; creates directories (e.g. create directories recursively &lt;code&gt;mkdir -p dist/code&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rm&lt;/code&gt; - removes files or directories (e.g. forcibly and recursively remove &lt;code&gt;dist&lt;/code&gt; directory - &lt;code&gt;rm -rf dist&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cp&lt;/code&gt; copy files and directories (e.g., &lt;code&gt;cp -f dist/404/index.html dist/404.html&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mv&lt;/code&gt; move or rename files or directories (e.g., &lt;code&gt;mv -f gen/robots.txt gen/manifest.json dist&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tar&lt;/code&gt; - archiving utility (e.g., create a gzipped archive and write it to a file - &lt;code&gt;tar -czf bundle.tar.gz dist/&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more commands (&lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, etc.), but when encountered you can look the up in the manual pages (e.g., &lt;code&gt;man tar&lt;/code&gt;). There's also a very nifty community-driven tool called &lt;a href="https://tldr.sh/"&gt;tldr&lt;/a&gt;, that aims to simplify the beloved &lt;a href="https://en.wikipedia.org/wiki/Man_page"&gt;man pages&lt;/a&gt; with practical examples (e.g., &lt;code&gt;tldr tar&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Operators
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Command Chaining Operators
&lt;/h3&gt;

&lt;p&gt;Usage of a single command is rarely enough, so here some chaining operators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; (the AND operator) - executes second command only if the first one &lt;strong&gt;succeeds&lt;/strong&gt; (e.g., &lt;code&gt;yarn &amp;amp;&amp;amp; yarn build &amp;amp;&amp;amp; yarn publish&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;;&lt;/code&gt; (the semicolon operator) - runs several commands, despite if previous one succeeded or not (e.g., &lt;code&gt;yarn build &amp;amp;&amp;amp; mv -f gen/sitemap.xml dist; echo Build done!&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more shell operators, but these and &lt;code&gt;npm-run-all&lt;/code&gt; should cover the majority of your chaining needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output &lt;code&gt;&amp;gt;&lt;/code&gt; and Output Append &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; Operators
&lt;/h3&gt;

&lt;p&gt;Both, output &lt;code&gt;&amp;gt;&lt;/code&gt; and output append &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; operators redirects content to a destination, but only &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; appends to the target. E.g., creating a &lt;code&gt;.env&lt;/code&gt; file in your CI pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PORT=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PRODUCTION_PORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"API_URL=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PRODUCTION_API_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Command Substitution
&lt;/h2&gt;

&lt;p&gt;Command substitution is a mechanism by which the shell performs a given set of commands and then exchanges their output in the place of the commands. E.g., combine Node.js script evaluation and command substitution to have JavaScript output in shell environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;Version - &lt;span class="si"&gt;$(&lt;/span&gt;node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"console.log(require('./package.json').version)"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conditional Statements
&lt;/h2&gt;

&lt;p&gt;Just like JavaScript, shell scripts can have &lt;code&gt;if&lt;/code&gt; statements. They can be written as both multi and single line statements. E.g., performing an optimized &lt;code&gt;yarn&lt;/code&gt; install for CI environment only:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$CI&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;yarn &lt;span class="nt"&gt;--cache-folder&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/.yarn &lt;span class="nt"&gt;--prefer-offline&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;yarn
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;Environment variables are a common way of passing dynamically configurable values. Here are some use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configurable environment values with defaults&lt;/strong&gt; - e.g., optional &lt;code&gt;PORT&lt;/code&gt; environment variable with defaults from npm config:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"srcipts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serve -l ${PORT:-$npm_package_config_port}"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reusing &lt;code&gt;.env&lt;/code&gt; file in shell sessions&lt;/strong&gt; - e.g., a localhost release script for Lerna project that loads &lt;code&gt;.env&lt;/code&gt;, and performs some necessary checks:
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .env&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; +a

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$GH_TOKEN&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🚨 Missing GH_TOKEN env variable"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;npm &lt;span class="nb"&gt;whoami&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🚨 Not logged in to npm"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;git checkout main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn release
&lt;span class="k"&gt;else
    &lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🧹 Working directory not clean"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Shell scripting is a powerful and elegant way to perform some common operations. Dedicate some time and give it a proper try - it's a versatile skill to have at your tool belt. This blog post scratches only the surface of what's possible, so here are some resources for further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dylanaraps/pure-bash-bible"&gt;github.com/dylanaraps/pure-bash-bible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mywiki.wooledge.org/BashGuide"&gt;mywiki.wooledge.org/BashGuide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Manage Multiple SSH Keys for GitHub, GitLab, etc.</title>
      <dc:creator>Karolis Šarapnickis</dc:creator>
      <pubDate>Sun, 12 Sep 2021 17:15:56 +0000</pubDate>
      <link>https://forem.com/karolis_sh/how-to-manage-multiple-ssh-keys-for-github-gitlab-etc-4f98</link>
      <guid>https://forem.com/karolis_sh/how-to-manage-multiple-ssh-keys-for-github-gitlab-etc-4f98</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Short tutorial on how to structure projects and setup multi-user Git SSH workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When using a single machine with multiple git accounts, you might encounter some obstacles with SSH setup. The easiest way to achieve a multi-user setup is to structure git repositories by respective directories, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;projects
├── work
│   ├── enterprise-fiz-buz
│   └── ...
└── personal
    ├── karolis.sh
    └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This short tutorial will help you set up SHH for such workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a new SSH key
&lt;/h2&gt;

&lt;p&gt;To generate a new SSH key, use the provided template script (or check the &lt;a href="https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh"&gt;docs&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;karolis.sarapnickis@work.com
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/id_rsa_work
ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="nv"&gt;$EMAIL&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$SSH_FILE&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-K&lt;/span&gt; &lt;span class="nv"&gt;$SSH_FILE&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🔽 PUBLIC KEY BELOW 🔽"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$SSH_FILE&lt;/span&gt;.pub
pbcopy &amp;lt; &lt;span class="nv"&gt;$SSH_FILE&lt;/span&gt;.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's left is to add the SSH key to your &lt;a href="https://github.com/settings/keys"&gt;GitHub&lt;/a&gt;/&lt;a href="https://gitlab.com/-/profile/keys"&gt;GitLab&lt;/a&gt;/etc. account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-user Git SSH setup
&lt;/h2&gt;

&lt;p&gt;The general idea is that you use specific &lt;a href="https://git-scm.com/docs/git-config.html#Documentation/git-config.txt-coresshCommand"&gt;ssh command&lt;/a&gt; based on your working directory with the help of &lt;a href="https://git-scm.com/docs/git-config.html#_includes"&gt;git includes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;~/.gitconfig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;name = Karolis Šarapnickis&lt;/span&gt;
  &lt;span class="s"&gt;email = pastas.k@gmail.com&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;sshCommand = ssh -i ~/.ssh/id_rsa&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;default = current&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;includeIf "gitdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;~/projects/work/"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;path = ~/.gitconfig.work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;~/.gitconfig.work&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;email = karolis.sarapnickis@work.com&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="s"&gt;sshCommand = ssh -i ~/.ssh/id_rsa_work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Appropriate SSH setup will be used based on directory location, no extra actions are needed.&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>github</category>
      <category>gitlab</category>
    </item>
  </channel>
</rss>
