<?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: Raunak Ramakrishnan</title>
    <description>The latest articles on Forem by Raunak Ramakrishnan (@rrampage).</description>
    <link>https://forem.com/rrampage</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%2F35035%2Ff095885d-5235-4d65-8998-55c42b8764d4.jpg</url>
      <title>Forem: Raunak Ramakrishnan</title>
      <link>https://forem.com/rrampage</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rrampage"/>
    <language>en</language>
    <item>
      <title>Level up your S3 skills by playing this game!</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Thu, 04 Jun 2020 16:47:33 +0000</pubDate>
      <link>https://forem.com/rrampage/level-up-your-s3-skills-by-playing-this-game-23a8</link>
      <guid>https://forem.com/rrampage/level-up-your-s3-skills-by-playing-this-game-23a8</guid>
      <description>&lt;p&gt;The best way to learn a skill is through deliberate practice! &lt;br&gt;
&lt;a href="http://s3game-level1.s3-website.us-east-2.amazonaws.com/"&gt;S3 Game&lt;/a&gt; is an awesome game made by &lt;a href="https://www.linkedin.com/in/vpantyukhin/"&gt;Vasily Pantyukhin&lt;/a&gt; which walks you through various features of S3 from beginner to fairly advanced.&lt;/p&gt;
&lt;h3&gt;
  
  
  What you will need:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A browser (duh!)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html"&gt;aws cli&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;CLICK &lt;a href="http://s3game-level1.s3-website.us-east-2.amazonaws.com/"&gt;HERE&lt;/a&gt; TO PLAY!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each level consists of finding a "treasure" object and getting to the next level using the secret code in the "treasure".&lt;/p&gt;

&lt;p&gt;Go ahead and play this game. Each level contains multiple hints with links to S3 API documentation.&lt;/p&gt;

&lt;p&gt;Below is a walk through you can refer to if you are stuck on any level. Make sure that you try for a bit before seeing here :)&lt;/p&gt;
&lt;h2&gt;
  
  
  Walk through (Spoilers)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;a href="http://s3game-level1.s3-website.us-east-2.amazonaws.com/level1.html"&gt;Level 1&lt;/a&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Solution:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List the objects in bucket&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://s3game-level1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Visit the &lt;a href="http://s3game-level1.s3-website.us-east-2.amazonaws.com/treasure1"&gt;treasure object&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level2.s3.us-east-2.amazonaws.com/level2-748l6b6xwzl6.html"&gt;Level 2&lt;/a&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Solution:
&lt;/h4&gt;

&lt;p&gt;Just get the treasure2 object either using browser or aws s3 : &lt;a href="https://s3game-level2.s3.us-east-2.amazonaws.com/treasure2"&gt;https://s3game-level2.s3.us-east-2.amazonaws.com/treasure2&lt;/a&gt;&lt;br&gt;
Make sure to save the Access and Secret key somewhere&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level3.s3.us-east-2.amazonaws.com/level3-76qp7mlpzyg1.html"&gt;Level 3&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Create an AWS profile "tmp" with the access and secret key obtained from previous level. You will need to use this for almost every level from here on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; AWS Access Key ID
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; AWS Secret Access Key
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Default region name - us-east-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Solution:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://s3game-level3 &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://s3game-level3/treasure3_has_no_secret_code &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="nb"&gt;cat &lt;/span&gt;treasure3_has_no_secret_code
&lt;span class="c"&gt;# The object data itself does not have the secret code. It is present in the metadata&lt;/span&gt;
aws s3api head-object &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level3 &lt;span class="nt"&gt;--key&lt;/span&gt; treasure3_has_no_secret_code &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level4-k73045aztqln.s3.us-east-2.amazonaws.com/level4.html"&gt;Level 4&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s3game-level4-k73045aztqln.s3.us-east-2.amazonaws.com/level4-hint2.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List the bucket ..&lt;/span&gt;
&lt;span class="c"&gt;# get the file&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://s3game-level4-k73045aztqln/treasure4_also_has_no_secret_code &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="c"&gt;# looks like the data is empty&lt;/span&gt;
aws s3api head-object &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level4-k73045aztqln &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp &lt;span class="nt"&gt;--key&lt;/span&gt; treasure4_also_has_no_secret_code
&lt;span class="c"&gt;# ... so is the metadata. Let's try object tags as mentioned in hint&lt;/span&gt;
aws s3api get-object-tagging &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level4-k73045aztqln &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp &lt;span class="nt"&gt;--key&lt;/span&gt; treasure4_also_has_no_secret_code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway:
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Object in S3, including its metadata, is immutable. When you edit object's metadata, you are actually overwriting the object with a copy of itself, with its metadata modified. &lt;br&gt;
In contrast, tags are subresources. They are managed separately and can be modified without modifying the object itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level5-8v95e5rv7z4i.s3.us-east-2.amazonaws.com/level5.html"&gt;Level 5&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s3game-level5-8v95e5rv7z4i.s3.us-east-2.amazonaws.com/level5-hint2.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s3game-level5-8v95e5rv7z4i.s3.us-east-2.amazonaws.com/level5-hint3.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s3game-level5-8v95e5rv7z4i.s3.us-east-2.amazonaws.com/level5-hint4.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We are listing all versions of objects as the hint says that the object is not present in its current version&lt;/span&gt;
aws s3api list-object-versions &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level5-8v95e5rv7z4i &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="c"&gt;# Get the specific version of treasure5_is_deleted using version-id from previous call&lt;/span&gt;
aws s3api get-object &lt;span class="nt"&gt;--bucket&lt;/span&gt; &lt;span class="s1"&gt;'s3game-level5-8v95e5rv7z4i'&lt;/span&gt; &lt;span class="nt"&gt;--key&lt;/span&gt; treasure5_is_deleted &lt;span class="nt"&gt;--version-id&lt;/span&gt; &lt;span class="s1"&gt;'344PQOyFqocF0TI66MbLynNNdQqHfBz3'&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp treasure5_is_deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;S3 versioning keeps multiple variants of an object in the same bucket.&lt;br&gt;
If you enable versioning for a bucket, S3 automatically generates a unique version ID for the object being stored.&lt;br&gt;
In one bucket you can have two objects with the same key, but different version IDs.&lt;br&gt;
Check if versioning is enabled using: &lt;code&gt;aws s3api get-bucket-versioning --bucket my-bucket&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level6-vjv45x1gux81.s3.us-east-2.amazonaws.com/level6.html"&gt;Level 6&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s3game-level6-vjv45x1gux81.s3.us-east-2.amazonaws.com/level6-hint2.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We need to get a gzipped object using S3 select&lt;/span&gt;
aws s3api list-objects &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level6-vjv45x1gux81 &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="c"&gt;# Now, do the select on s3select.csv.gz&lt;/span&gt;
aws s3api &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-object-content&lt;/span&gt; &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level6-vjv45x1gux81 &lt;span class="nt"&gt;--key&lt;/span&gt; s3select.csv.gz &lt;span class="nt"&gt;--expression&lt;/span&gt; &lt;span class="s2"&gt;"SELECT s.Answer FROM s3object s WHERE Category = 'TREASURE'"&lt;/span&gt; &lt;span class="nt"&gt;--expression-type&lt;/span&gt; sql &lt;span class="nt"&gt;--input-serialization&lt;/span&gt; &lt;span class="s1"&gt;'{"CSV": {"FileHeaderInfo": "USE", "FieldDelimiter": ";"}, "CompressionType": "GZIP"}'&lt;/span&gt; &lt;span class="nt"&gt;--output-serialization&lt;/span&gt; &lt;span class="s1"&gt;'{"CSV": {}}'&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp treasure6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level7-zhovpo4j8588.s3.us-east-2.amazonaws.com/level7.html"&gt;Level 7&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s3game-level7-zhovpo4j8588.s3.us-east-2.amazonaws.com/level7-hint2.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get 'somethingstrange' from the bucket&lt;/span&gt;
aws s3api get-object &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level7-zhovpo4j8588 &lt;span class="nt"&gt;--key&lt;/span&gt; somethingstrange &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp t7
&lt;span class="nb"&gt;cat &lt;/span&gt;t7
&lt;span class="c"&gt;# Visit the pre-signed URL in the file to get URL for next level&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway
&lt;/h4&gt;

&lt;p&gt;Pre-signed URLs are a powerful feature of S3. From the &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A presigned URL is generated by an AWS user who has access to the object. The generated URL is then given to the unauthorized user. The presigned URL can be entered in a browser or used by a program or HTML webpage. The credentials used by the presigned URL are those of the AWS user who generated the URL.&lt;/p&gt;

&lt;p&gt;A presigned URL remains valid for a &lt;strong&gt;limited period of time&lt;/strong&gt; which is specified when the URL is generated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level8-v6g8tp7ra2ld.s3.us-east-2.amazonaws.com/level8.html"&gt;Level 8&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List objects&lt;/span&gt;
aws s3api list-objects &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level8-v6g8tp7ra2ld &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;span class="c"&gt;# Visit the treasure file using the cloudfront URL&lt;/span&gt;
curl &lt;span class="s1"&gt;'https://d2suiw06vujwz3.cloudfront.net/treasure8_CDN'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can easily create a Cloudfront distribution backed by an S3 bucket&lt;/li&gt;
&lt;li&gt;In such cases, you can restrict public access for the objects in the bucket as they can be accessed using Cloudfront&lt;/li&gt;
&lt;li&gt;Ensure that your bucket does not allow unprivileged users to list all objects in the bucket&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/level9.html"&gt;Level 9&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/level9-hint2.html"&gt;Hint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bucket has a policy which checks that any request for "arn:aws:s3:::s3game-level9-781xtls2quvy/treasure9_referer" has the referer string "&lt;a href="http://s3game.treasure"&gt;http://s3game.treasure&lt;/a&gt;"&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;

&lt;p&gt;All we need to do is curl with a --refer given in policy&lt;br&gt;
curl '&lt;a href="https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/treasure9_referer"&gt;https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/treasure9_referer&lt;/a&gt;' --refer '&lt;a href="http://s3game.treasure"&gt;http://s3game.treasure&lt;/a&gt;'&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level10-gac6tf83erp6.s3.us-east-2.amazonaws.com/level10.html"&gt;Level 10&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Here, we need to fetch an object which is in Infrequent Access storage.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We can use the powerful query param of aws cli to just fetch those objects which are in infrequent access storgae&lt;/span&gt;
aws s3api list-objects &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level10-gac6tf83erp6 &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Contents[?StorageClass == `STANDARD_IA`]'&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Amazon S3 offers a range of storage classes designed for different use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard for general-purpose storage of frequently accessed data&lt;/li&gt;
&lt;li&gt;Intelligent-Tiering for data with unknown or changing access patterns&lt;/li&gt;
&lt;li&gt;Standard-Infrequent Access (Standard-IA) and One Zone-Infrequent Access (One Zone-IA) for long-lived, but less frequently accessed data&lt;/li&gt;
&lt;li&gt;Glacier and Glacier Deep Archive for long-term archive&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://s3game-level11-djq30a807iyq.s3.us-east-2.amazonaws.com/level11.html"&gt;Level 11&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Here we need to fetch an object which has been encrypted using client side encryption and uploaded to S3. This means that we can not fetch the object unless we have the encryption key.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The encryption key is given in the hint&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;--sse-c&lt;/span&gt; &lt;span class="s1"&gt;'AES256'&lt;/span&gt; &lt;span class="nt"&gt;--sse-c-key&lt;/span&gt; &lt;span class="s1"&gt;'UkXp2s5v8y/B?E(H+MbPeShVmYq3t6w9'&lt;/span&gt; &lt;span class="s1"&gt;'s3://s3game-level11-djq30a807iyq/treasure11_encryption'&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Alternate way using aws s3api. Here we also need to give md5 of encryption key as additional integrity check&lt;/span&gt;
aws s3api get-object &lt;span class="nt"&gt;--bucket&lt;/span&gt; s3game-level11-djq30a807iyq &lt;span class="nt"&gt;--key&lt;/span&gt; treasure11_encryption &lt;span class="nt"&gt;--sse-customer-key&lt;/span&gt; &lt;span class="s1"&gt;'UkXp2s5v8y/B?E(H+MbPeShVmYq3t6w9'&lt;/span&gt; &lt;span class="nt"&gt;--sse-customer-algorithm&lt;/span&gt; AES256 &lt;span class="nt"&gt;--profile&lt;/span&gt; tmp treasure11_encryption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Takeaway
&lt;/h4&gt;

&lt;p&gt;S3 supports both &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html"&gt;server side&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingClientSideEncryption.html"&gt;client side encryption&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  VICTORY! - &lt;a href="https://s3game-level12-bk0m5ax5n92o.s3.us-east-2.amazonaws.com/level12.html"&gt;Level 12&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Congrats! You have cleared the game!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Practical Python Programming - Online course</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Sat, 30 May 2020 14:47:49 +0000</pubDate>
      <link>https://forem.com/rrampage/practical-python-programming-david-beazley-1c2b</link>
      <guid>https://forem.com/rrampage/practical-python-programming-david-beazley-1c2b</guid>
      <description>&lt;h2&gt;
  
  
  Course Details:
&lt;/h2&gt;

&lt;p&gt;Folks, the legendary David Beazley has released a free, online course on &lt;a href="https://dabeaz-course.github.io/practical-python/Notes/Contents.html"&gt;practical python programming&lt;/a&gt;! It was initially content for an in-person training, now online and free for everyone.&lt;/p&gt;

&lt;p&gt;Course page: &lt;a href="https://dabeaz-course.github.io/practical-python/Notes/Contents.html"&gt;https://dabeaz-course.github.io/practical-python/Notes/Contents.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://dabeaz.com/"&gt;David Beazley&lt;/a&gt; is a very well known member of the Python community. His PyCon talks are extremely interesting and teach you a lot about the workings of Python and building some incredible stuff in 3 hours.&lt;/p&gt;

&lt;p&gt;Some of my favorite talks:&lt;/p&gt;

&lt;h3&gt;
  
  
  Keynote: A Talk Near the Future of Python
&lt;/h3&gt;

&lt;p&gt;Live code a web-assembly interpreter in one hour!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/VUT386_GKI8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Python Concurrency From the Ground Up: LIVE!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://pyvideo.org/pycon-us-2015/python-concurrency-from-the-ground-up-live.html"&gt;A live-coding session&lt;/a&gt; exploring various concurrency models in Python&lt;/p&gt;

&lt;h3&gt;
  
  
  Keynote: Builtin Superheroes
&lt;/h3&gt;

&lt;p&gt;Solve common data  manipulation problems using Python's built-in types.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/lyDLAutA88s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Calculus
&lt;/h3&gt;

&lt;p&gt;Learn lambda calculus and derive the powerful Y-combinator using Python&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pkCLMl0e_0k"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>python</category>
      <category>top7</category>
    </item>
    <item>
      <title>5 NPM and Node tips to make your dev machine safer</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Thu, 28 May 2020 13:39:19 +0000</pubDate>
      <link>https://forem.com/rrampage/5-npm-and-node-tips-to-make-your-machine-safer-3g0l</link>
      <guid>https://forem.com/rrampage/5-npm-and-node-tips-to-make-your-machine-safer-3g0l</guid>
      <description>&lt;p&gt;NPM is used as a convenient cross-platform package manager for &lt;a href="https://hackernoon.com/the-best-of-npm-install-g-9ab9d749eeb1"&gt;a lot of developer tools&lt;/a&gt;. For many tools, the defacto way to install is &lt;strong&gt;&lt;code&gt;npm install -g $TOOL&lt;/code&gt;&lt;/strong&gt;. But installing anything via npm allows it to run untrusted code on your machine.&lt;/p&gt;

&lt;p&gt;Here are a few tips to minimize the risk:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. NEVER run npm as sudo/root
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally"&gt;Node's official documentation&lt;/a&gt; recommends not installing global packages as sudo/root. If you have already installed node through &lt;code&gt;nvm&lt;/code&gt; ignore this step. If you use a system installed &lt;code&gt;node&lt;/code&gt; e.g using Ubuntu's apt-get, read through &lt;strong&gt;&lt;a href="https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md"&gt;this guide&lt;/a&gt;&lt;/strong&gt; for Linux/Mac or &lt;a href="https://github.com/glenpike/npm-g_nosudo"&gt;npm-g-nosudo&lt;/a&gt; which is a shell script for Linux. &lt;/p&gt;

&lt;h4&gt;
  
  
  If you are lazy (like me), here's a summary from the linked guide:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.npm-packages"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm config &lt;span class="nb"&gt;set &lt;/span&gt;prefix &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.npm-packages"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NPM_PACKAGES="${HOME}/.npm-packages"
export PATH="$PATH:$NPM_PACKAGES/bin"
# Preserve MANPATH if you already defined it somewhere in your config.
# Otherwise, fall back to `manpath` so we can inherit from `/etc/manpath`.
export MANPATH="${MANPATH-$(manpath)}:$NPM_PACKAGES/share/man"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Install/Use node using &lt;code&gt;nvm&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally"&gt;Node's official documentation&lt;/a&gt; recommends installing node as an unprivileged user using a node version manager.&lt;/p&gt;

&lt;p&gt;Here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt;. This does not work for Windows, use &lt;a href="https://github.com/coreybutler/nvm-windows"&gt;nvm-windows&lt;/a&gt; which is a totally different project from nvm.

&lt;ul&gt;
&lt;li&gt;Unfortunately, &lt;code&gt;nvm&lt;/code&gt; suffers from the curl pipe to bash install as its main way to install.&lt;/li&gt;
&lt;li&gt;If you have git installed on your machine, you can also directly clone it using the following steps:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd "$HOME" &amp;amp;&amp;amp; git clone https://github.com/nvm-sh/nvm.git .nvm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd "$HOME/.nvm" &amp;amp;&amp;amp; git checkout v0.35.3 &amp;amp;&amp;amp; . nvm.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add to your .bashrc or .zshrc:
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] &amp;amp;&amp;amp; \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] &amp;amp;&amp;amp; \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nvm install --lts&lt;/code&gt; or whichever version of node you need.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvm use node&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To use a node version by default, &lt;code&gt;echo "lts/*" &amp;gt; "$HOME/.nvmrc"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. List all your globally installed npm packages and remove any unnecessary ones
&lt;/h3&gt;

&lt;p&gt;Listing global packages is done with &lt;strong&gt;&lt;code&gt;npm ls -g --depth 0&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Remove any unnecessary packages with &lt;strong&gt;&lt;code&gt;npm uninstall -g $TOOL&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
You can check your shell history/scripts folders to see if you actually use many of the global packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Audit your packages
&lt;/h3&gt;

&lt;p&gt;Run &lt;strong&gt;&lt;code&gt;npm audit&lt;/code&gt;&lt;/strong&gt; in your project regularly to see if &lt;a href="https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities"&gt;any dependencies are vulnerable&lt;/a&gt;. This only works for your development projects, not global packages.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://stackoverflow.com/a/53619858"&gt;A (hacky) way&lt;/a&gt; to &lt;code&gt;npm audit&lt;/code&gt;  global packages:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm&lt;/code&gt;. The last line will show the folder of the global npm packages e.g &lt;code&gt;$HOME/.npm-packages/lib/node_modules/npm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;$HOME/.npm-packages/lib&lt;/code&gt; and run &lt;code&gt;npm init -y&lt;/code&gt; and then run &lt;code&gt;npm i --package-lock-only&lt;/code&gt;. These steps are required as &lt;code&gt;npm audit&lt;/code&gt; checks for &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Now run &lt;code&gt;npm audit&lt;/code&gt;. Remove any dependencies which have high or too many moderate vulnerabilities. These could either be malicious or unmaintained tools.&lt;/li&gt;
&lt;li&gt;Remove the &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; after the audit &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Use &lt;code&gt;npx&lt;/code&gt; to run executables
&lt;/h3&gt;

&lt;p&gt;Many times, it is not necessary to have a tool installed globally e.g &lt;code&gt;create-react-app&lt;/code&gt;. Node 6+ comes with &lt;code&gt;npx&lt;/code&gt; which allows you to temporarily download and run scripts. The benefits of using &lt;code&gt;npx&lt;/code&gt; over &lt;code&gt;npm install -g&lt;/code&gt; are beautifully explained in &lt;a href="https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b"&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A gist of the article:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Calling npx  when  isn’t already in your $PATH will automatically install a package with that name from the npm registry for you, and invoke it. When it’s done, the installed package won’t be anywhere in your globals, so you won’t have to worry about pollution in the long-term.&lt;/p&gt;

&lt;p&gt;This feature is ideal for things like generators, too. Tools like yeoman or create-react-app only ever get called once in a blue moon. &lt;strong&gt;By the time you run them again, they’ll already be far out of date, so you end up having to run an install every time you want to use them anyway.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Bonus : Use Deno for developer tools
&lt;/h3&gt;

&lt;p&gt;I think a project like &lt;a href="https://deno.land/"&gt;deno&lt;/a&gt; with good sandbox capabilities and &lt;a href="https://deno.land/manual/getting_started/permissions"&gt;limited permisisons&lt;/a&gt; is the best choice for a lot of developer tools currently made using Node. Read &lt;a href="https://www.jeremymorgan.com/blog/programming/what-is-deno/"&gt;this post&lt;/a&gt; for more details on why everyone is talking about Deno.&lt;/p&gt;

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

&lt;p&gt;Does this solve all security issues of &lt;code&gt;node&lt;/code&gt;/&lt;code&gt;npm&lt;/code&gt; on your machine? No! There are a &lt;a href="https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident"&gt;lot&lt;/a&gt; &lt;a href="https://blog.npmjs.org/post/185397814280/plot-to-steal-cryptocurrency-foiled-by-the-npm"&gt;of&lt;/a&gt; &lt;a href="https://blog.npmjs.org/post/175824896885/incident-report-npm-inc-operations-incident-of"&gt;ways&lt;/a&gt; in which a malicious attacker can compromise your machine/project. This only prevents a bad npm tool from getting root access and removes globally installed npm tools with known insecure dependencies.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>react</category>
      <category>security</category>
    </item>
    <item>
      <title>Webhook to auto-deploy on git push to Github</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Mon, 25 May 2020 18:13:21 +0000</pubDate>
      <link>https://forem.com/rrampage/webhook-to-auto-deploy-on-git-push-to-github-330i</link>
      <guid>https://forem.com/rrampage/webhook-to-auto-deploy-on-git-push-to-github-330i</guid>
      <description>&lt;h2&gt;
  
  
  What is a webhook?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Webhook"&gt;webhook&lt;/a&gt; is an endpoint on your server which allows you to execute a particular task. Webhooks are usually triggered by some event. A good use-case for a webhook is running tests on a dedicated test server or deploying your latest &lt;code&gt;master&lt;/code&gt; branch to staging/production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.github.com/webhooks/"&gt;Github&lt;/a&gt; / &lt;a href="https://docs.gitlab.com/ee/user/project/integrations/webhooks.html"&gt;Gitlab&lt;/a&gt; / Bitbucket allow you to specify a webhook URL in your repository settings. Github triggers the webhook which sends the event data on every push.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/adnanh/webhook"&gt;Webhook&lt;/a&gt; server
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/adnanh/webhook"&gt;Webhook&lt;/a&gt; is a very useful golang project which runs any script you specify when a particular endpoint is hit. &lt;/p&gt;

&lt;p&gt;Download and extract the binary for your operating system from the &lt;a href="https://github.com/adnanh/webhook/releases"&gt;releases page&lt;/a&gt;. For Linux, it is &lt;a href="https://github.com/adnanh/webhook/releases/download/2.7.0/webhook-linux-amd64.tar.gz"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The program takes as config a &lt;strong&gt;&lt;code&gt;hooks.json&lt;/code&gt;&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello-world"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"execute-command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/user/scripts/hello.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command-working-directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/user/webhook"&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;p&gt;Replace &lt;code&gt;user&lt;/code&gt; with the username of your linux user.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hello.sh&lt;/code&gt; script.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Make the script executable by running &lt;strong&gt;&lt;code&gt;chmod +x hello.sh&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start webhook server as &lt;strong&gt;&lt;code&gt;webhook -hooks hooks.json -hotreload -logfile webhooks.log&lt;/code&gt;&lt;/strong&gt;. The server will run on port 9000 by default. You can check if everything is working by running &lt;strong&gt;&lt;code&gt;curl http://localhost:9000/hooks/hello-world&lt;/code&gt;&lt;/strong&gt;. This will print "Hello!" in the log file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy script
&lt;/h3&gt;

&lt;p&gt;For the purpose of this post, I'll assume the script is called &lt;strong&gt;&lt;code&gt;deploy&lt;/code&gt;&lt;/strong&gt; and is at location &lt;code&gt;/home/user/scripts/deploy&lt;/code&gt;. This script will vary depending on your tech stack and the complexity of your CI process.&lt;/p&gt;

&lt;p&gt;A simple example &lt;code&gt;deploy&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# If you have a build server which creates binary/jar/artifact&lt;/span&gt;
wget &lt;span class="s1"&gt;'ARTIFACT_URL'&lt;/span&gt;
&lt;span class="c"&gt;# Else, git pull and build on the server itself&lt;/span&gt;
&lt;span class="c"&gt;# Assuming this script stops old instance of your code and starts a new instance with latest artifact &lt;/span&gt;
restart-service.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration to run deploy script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deploy-from-git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"execute-command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/user/scripts/deploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command-working-directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/user/scripts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trigger-rule"&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;"and"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"match"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payload-hash-sha1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"secret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MyTotallySecretString"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parameter"&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;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"X-Hub-Signature"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="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;"match"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refs/heads/master"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parameter"&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;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ref"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="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="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="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;trigger-rule&lt;/strong&gt; in config above will ensure that the script is only triggered when header from Github request contains &lt;strong&gt;"X-Hub-Signature"&lt;/strong&gt; with a secret string and the push has occured in master branch.&lt;/p&gt;

&lt;p&gt;Make sure that the secret string ("secret" : "MyTotallySecretString") is randomly generated. This secret will need to be entered in Github settings as well.&lt;/p&gt;

&lt;p&gt;For Gitlab and Bitbucket, example hook config can be found on repo page &lt;a href="https://github.com/adnanh/webhook/blob/master/docs/Hook-Examples.md"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Expose your webhook server safely to the internet
&lt;/h3&gt;

&lt;p&gt;There are 2 ways of exposing the webhook server to github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proxy using Nginx&lt;/li&gt;
&lt;li&gt;Via a tunnel e.g by downloading &lt;a href="https://ngrok.com/product"&gt;ngrok&lt;/a&gt; and then running &lt;code&gt;ngrok http 9000&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Nginx configuration
&lt;/h4&gt;

&lt;p&gt;Preferably use HTTPS for your domain with Nginx. A good tutorial &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example Nginx config (HTTPS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream webhook {
    server localhost:9000;
}

server {
    listen 443 ssl http2;
        server_name YOUR.DOMAIN.COM;
    ssl_certificate YOUR_CERT_CHAIN; # e.g /etc/letsencrypt/live/DOMAIN/fullchain.pem;
    ssl_certificate_key YOUR_CERT_KEY; # e.g /etc/letsencrypt/live/DOMAIN/privkey.pem;
    include /etc/nginx/options-ssl-nginx.conf;
    ssl_dhparam /etc/nginx/ssl-dhparams.pem;
        location ~ ^/hooks/(.+)$ {
        proxy_pass http://webhook;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add your webhook URL to Github
&lt;/h3&gt;

&lt;p&gt;Go to the settings page of your Github repo then click on Webhook. Enter the URL of your webhook server. If using Nginx, it should be something like &lt;code&gt;https://YOUR.DOMAIN.COM/hooks/deploy-from-git&lt;/code&gt;. Make sure you select content type as &lt;code&gt;application/json&lt;/code&gt; and secret to the secret you generated earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Create a systemd user service for webhook (Linux)
&lt;/h3&gt;

&lt;p&gt;Create a systemd unit file with path &lt;strong&gt;/home/user/.config/systemd/user/webhook.service&lt;/strong&gt; . This service does not require sudo/root permissions and can be run by the unprivileged user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
AssertPathExists=/home/user/scripts

[Service]
WorkingDirectory=/home/user/scripts
ExecStart=/home/user/scripts/webhook -hooks hooks.json -hotreload -logfile webhooks.log
Restart=always
PrivateTmp=true
NoNewPrivileges=true

[Install]
WantedBy=default.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do &lt;code&gt;systemctl --user daemon-reload&lt;/code&gt; and &lt;code&gt;systemctl --user start webhook.service&lt;/code&gt;. You can &lt;code&gt;systemctl --user enable webhook.service&lt;/code&gt; to ensure that the service always runs when your machine is booted.&lt;/p&gt;

</description>
      <category>git</category>
      <category>linux</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Bash function to add TILs from the command line</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Sat, 23 May 2020 12:42:20 +0000</pubDate>
      <link>https://forem.com/rrampage/bash-function-to-easily-add-tils-4d51</link>
      <guid>https://forem.com/rrampage/bash-function-to-easily-add-tils-4d51</guid>
      <description>&lt;p&gt;Here's a snippet I use in my &lt;strong&gt;&lt;code&gt;.bashrc&lt;/code&gt;&lt;/strong&gt; file to quickly write down and review TILs (Today I learned):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TIL_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/my-notes-repo/til.md"&lt;/span&gt;
til &lt;span class="o"&gt;()&lt;/span&gt; 
&lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="c"&gt;# checks if the function has been called without any argument&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nv"&gt;$1&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="c"&gt;# opens the file in my editor, setting the cursor to the last line&lt;/span&gt;
        &lt;span class="c"&gt;# useful to review latest entries or to write a longer entry&lt;/span&gt;
        vim + &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TIL_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="c"&gt;# adds a line with today's date, a TAB and all arguments supplied ("$@")&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"- &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%F'&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TIL_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to use:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;til&lt;/code&gt;&lt;/strong&gt; to open the file. I use this to review what I learned today  or if I need to write a longer, multiline entry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;til CONTENT&lt;/code&gt;&lt;/strong&gt; to append a line to the file

&lt;ul&gt;
&lt;li&gt;e.g &lt;code&gt;til grep --line-buffered to immediately print especially when tailing files&lt;/code&gt; will add this: &lt;code&gt;- 2020-05-23:   grep --line-buffered to immediately print especially when tailing files&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;h3&gt;
  
  
  Explanation on the function
&lt;/h3&gt;

&lt;p&gt;In case you missed the comments in the function, here's an explanation of what the various lines do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;if [[ -z $1 ]];&lt;/code&gt;&lt;/strong&gt; checks if the function has been called without any arguments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;vim + "$TIL_FILE"&lt;/code&gt;&lt;/strong&gt; opens the file in vim (my preferred editor), setting the cursor to the last line of the file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;echo -e "- $tdate:\t$@" &amp;gt;&amp;gt; "$TIL_FILE";&lt;/code&gt;&lt;/strong&gt; adds a line with today's date, a TAB and all arguments supplied ("$@") to &lt;code&gt;til&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>productivity</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Setting display brightness on Linux from the command line</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Tue, 19 May 2020 16:53:48 +0000</pubDate>
      <link>https://forem.com/rrampage/setting-display-brightness-on-linux-from-the-command-line-4amg</link>
      <guid>https://forem.com/rrampage/setting-display-brightness-on-linux-from-the-command-line-4amg</guid>
      <description>&lt;p&gt;I auto-adjust the brightness on my display using a &lt;a href="https://en.wikipedia.org/wiki/Cron"&gt;cron&lt;/a&gt; which runs at 7 pm everyday.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xrandr &lt;span class="nt"&gt;--output&lt;/span&gt; eDP-1 &lt;span class="nt"&gt;--brightness&lt;/span&gt; 0.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets the brightness to 90% of maximum brightness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Linux Display environments in a cron
&lt;/h3&gt;

&lt;p&gt;The above command works when run from my terminal. But when run on a cron, it does not produce any effect. We need to explicitly mention the "display number" as an environment variable &lt;code&gt;DISPLAY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;8 19 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;DISPLAY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;:0 xrandr &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; eDP-1 &lt;span class="nt"&gt;--brightness&lt;/span&gt; 0.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How to get the display number of your monitor?
&lt;/h4&gt;

&lt;p&gt;Running &lt;code&gt;xrandr&lt;/code&gt; will give you a lot of output like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384
eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, the display number is &lt;code&gt;:0&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Adjusting backlight brightness vs perceived brightness
&lt;/h4&gt;

&lt;p&gt;If &lt;code&gt;xrandr&lt;/code&gt; is unable to find backlight, it only changes "perceived" brightness i.e it does &lt;a href="https://wiki.archlinux.org/index.php/backlight#Color_correction"&gt;software color correction&lt;/a&gt;. If we want to save battery, we will need to reduce the backlight brightness.&lt;/p&gt;

&lt;p&gt;In Linux, the backlights can be found in &lt;code&gt;/sys/class/backlight&lt;/code&gt;. In my case, it was &lt;code&gt;/sys/class/backlight/intel_backlight&lt;/code&gt;. In this folder, there are many files like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actual_brightness
max_brightness
brightness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;max_brightness&lt;/code&gt; shows highest possible level of brightness for the display. We can adjust the value in &lt;code&gt;brightness&lt;/code&gt; file to reduce backlight brightness.&lt;br&gt;
Here's what I do to adjust it: &lt;code&gt;echo 1800 &amp;gt; /sys/class/backlight/intel_backlight/brightness&lt;/code&gt; (in root crontab)&lt;/p&gt;

&lt;p&gt;Unlike the xrandr command, this does not require setting any DISPLAY variable in the cron file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Hummer12007/brightnessctl"&gt;brightnessctl&lt;/a&gt; is an easy to use tool which integrates well with systemd. It is also available in the package managers of various distributions like Debian, Ubuntu, Arch Linux.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>todayilearned</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Git Tagging Tutorial</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Thu, 22 Nov 2018 11:39:51 +0000</pubDate>
      <link>https://forem.com/rrampage/git-tags-from-command-line-103l</link>
      <guid>https://forem.com/rrampage/git-tags-from-command-line-103l</guid>
      <description>&lt;p&gt;I read a post on &lt;a href="https://dev.to/zellwk/git-tags--37a"&gt;dev.to&lt;/a&gt; which shows how to create git tags using GUI-based git clients. I think that tags are useful to know even when using the git cli.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are tags
&lt;/h3&gt;

&lt;p&gt;Tags are specific points in your code history which are useful to re-visit later e.g&lt;br&gt;
you just released a new version of your app. You can tag the commit as &lt;code&gt;v1.0&lt;/code&gt; using &lt;strong&gt;&lt;code&gt;git tag v1.0&lt;/code&gt;&lt;/strong&gt;. Anytime you want to reproduce bugs encountered on that version,  simply do &lt;strong&gt;&lt;code&gt;git checkout v1.0&lt;/code&gt;&lt;/strong&gt; and investigate.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use &lt;code&gt;git tag&lt;/code&gt; better
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Checkout code to the tag
&lt;/h4&gt;

&lt;p&gt;The tag is linked to the specific commit and not to a branch. When you checkout the tag, git tells you that you are in "detached HEAD" state. Do not worry, all it means is that you need to create a new branch if you want to retain any changes you make after checking out the tag.&lt;/p&gt;

&lt;p&gt;Create a new branch exactly at the commit of the tag using &lt;strong&gt;&lt;code&gt;git checkout -b BRANCH_NAME TAG_NAME&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Make your tag more informational!
&lt;/h4&gt;

&lt;p&gt;You can add more information using &lt;strong&gt;&lt;code&gt;git tag -a TAG_NAME -m 'MESSAGE'&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
The tag information can be viewed without having to checkout the tag using &lt;strong&gt;&lt;code&gt;git show TAG_NAME&lt;/code&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Create tag at a particular commit
&lt;/h4&gt;

&lt;p&gt;You do not always have to be at the HEAD or in the tip of the branch to create a tag. If you want to create tag say 5 commits before HEAD, you can use &lt;code&gt;git log&lt;/code&gt; to get the correct commit hash e.g &lt;strong&gt;&lt;code&gt;git log --pretty=oneline -10&lt;/code&gt;&lt;/strong&gt; which shows the last 10 commits on the current branch.&lt;/p&gt;

&lt;p&gt;Then, create tag using &lt;strong&gt;&lt;code&gt;git tag -a TAG_NAME -m 'MESSAGE' COMMIT_HASH&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  List and Delete tags
&lt;/h4&gt;

&lt;p&gt;Listing all tags is simply: &lt;strong&gt;&lt;code&gt;git tag&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Similarly, delete a tag using &lt;strong&gt;&lt;code&gt;git tag -d TAG_NAME&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Share your tag with others!
&lt;/h4&gt;

&lt;p&gt;The tag created is not pushed to remote automatically. If you want your tags to be used by other contributors too, you need to push them using &lt;strong&gt;&lt;code&gt;git push origin TAG_NAME&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Sign your tags!
&lt;/h4&gt;

&lt;p&gt;If you are working on a major project and want to show without any doubt that you have worked on the release, you can sign it using your GPG private key as &lt;strong&gt;&lt;code&gt;git tag -s TAG_NAME -m 'MESSAGE'&lt;/code&gt;&lt;/strong&gt;. Anyone who runs &lt;strong&gt;&lt;code&gt;git show TAG_NAME&lt;/code&gt;&lt;/strong&gt; on the tag will also see your public key signature along with the tag information. &lt;/p&gt;

&lt;p&gt;They can additionally verify the tag using &lt;strong&gt;&lt;code&gt;git tag -v TAG_NAME&lt;/code&gt;&lt;/strong&gt;. This checks using your public key whether the signature is indeed yours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tags vs Branches
&lt;/h3&gt;

&lt;p&gt;Why use tags when you have branches? Because branches can change and tags are linked to a specific commit. Thus, marking releases with a tag will give you the state of code when the particular software release was done.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Tags are great way to remember specific commits&lt;/li&gt;
&lt;li&gt;It is good to add a message to the tag so that people can easily see why you tagged a particular commit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;The Git book chapters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging" rel="noopener noreferrer"&gt;Tagging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work" rel="noopener noreferrer"&gt;Signing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>linux</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Bash Command Completion - Finding all the cats in your $PATH!</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Thu, 15 Nov 2018 11:50:01 +0000</pubDate>
      <link>https://forem.com/rrampage/bash-command-completion---finding-all-the-cats-in-your-path-2am2</link>
      <guid>https://forem.com/rrampage/bash-command-completion---finding-all-the-cats-in-your-path-2am2</guid>
      <description>&lt;p&gt;Today, I was curious to find out &lt;strong&gt;how many programs ending with &lt;code&gt;cat&lt;/code&gt;&lt;/strong&gt; I had on my system. I remember using &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;zcat&lt;/code&gt; and wanted to know if there are similar programs. Pressing TAB after &lt;code&gt;cat&lt;/code&gt; only gives programs which start with &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;apropos&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/rrampage/getting-help-in-the-terminal-4cmo"&gt;last post&lt;/a&gt;, I had mentioned that apropos is a way to search for what programs are available on your system. The search string for &lt;code&gt;apropos&lt;/code&gt; can be any regex. So, &lt;code&gt;apropos 'cat$'&lt;/code&gt; should solve the problem. &lt;code&gt;cat$&lt;/code&gt; means all words ending with 'cat'&lt;/p&gt;

&lt;p&gt;The output has&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STAILQ_CONCAT (3)     - implementations of singly-linked lists, singly-linked tail queues, lists and tail queues
OPENSSL_strlcat (3ssl) - Memory allocation functions
..
bzcat (1)            - decompresses files to stdout
cat (1)              - concatenate files and print on the standard output
fc-cat (1)           - read font information cache files
gencat (1)           - Generate message catalog

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

&lt;/div&gt;



&lt;p&gt;Clearly, the top 2 do not look like programs. Why is &lt;code&gt;apropos&lt;/code&gt; then returning them?&lt;br&gt;
Let's have a look at the &lt;code&gt;apropos&lt;/code&gt; manual&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;man apropos
&lt;span class="c"&gt;# apropos - search the manual page names and descriptions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;apropos&lt;/code&gt; searches the &lt;code&gt;man&lt;/code&gt; pages. And looks like there are &lt;code&gt;man&lt;/code&gt; pages for other things and not just programs...&lt;/p&gt;

&lt;p&gt;Digging deeper, let's try manual for the &lt;code&gt;man&lt;/code&gt; pages!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;man man
# The table below shows the section numbers of the manual followed by the types of pages they contain.
#       1   Executable programs or shell commands
#       2   System calls (functions provided by the kernel)
#       3   Library calls (functions within program libraries)
#       4   Special files (usually found in /dev)
#       5   File formats and conventions eg /etc/passwd
#       6   Games
#       7   Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
#       8   System administration commands (usually only for root)
#       9   Kernel routines [Non standard]

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

&lt;/div&gt;



&lt;p&gt;Ok. We are interested in are executable programs i.e section 1 of the man pages. &lt;code&gt;apropos&lt;/code&gt; has a way to limit which sections we search using&lt;code&gt;-s&lt;/code&gt; flag.&lt;br&gt;
&lt;strong&gt;&lt;code&gt;apropos -s 1 'cat$'&lt;/code&gt;&lt;/strong&gt; gives us all programs ending with name &lt;code&gt;cat&lt;/code&gt; which have an entry in the man pages but it does not show us any programs which do not have a man page.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. List all programs on your path
&lt;/h3&gt;

&lt;p&gt;The way Bash knows which programs can be called directly by their name (e.g &lt;code&gt;ls&lt;/code&gt;) and not by their full path (e.g &lt;code&gt;/usr/bin/ls&lt;/code&gt;) is by looking at the &lt;code&gt;$PATH&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;** Listing all executable files on path **&lt;/p&gt;

&lt;p&gt;Here's a small bash snippet which lists the executable files in PATH (let's call it &lt;code&gt;paths.sh&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# The directories in $PATH are separated by ":", so we split by it to get individual directories&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;pdir &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s2"&gt;":"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# We `find` all files in the directory which are executable and print the filename&lt;/span&gt;
    find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pdir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-executable&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-printf&lt;/span&gt; &lt;span class="s2"&gt;"%f&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you prefer Python, here's a small Python program for the same (let's call it &lt;code&gt;paths.py&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;path_dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PATH&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Split PATH by ':'
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_dirs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;all_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;path_dirs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Iterable of all files in the directories contained in PATH
&lt;/span&gt;&lt;span class="n"&gt;is_exec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Function to check if a filename is executable
&lt;/span&gt;&lt;span class="n"&gt;execs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_files&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running either our Bash or Python scripts will give us the correct output!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh paths.sh | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'cat$'&lt;/span&gt;
python3 paths.py | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'cat$'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Power of Bash Completion!
&lt;/h3&gt;

&lt;p&gt;When I press TAB TAB after typing a letter, I get a list of suggestions. How does Bash do that? The &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html" rel="noopener noreferrer"&gt;Bash manual&lt;/a&gt; says that it uses &lt;code&gt;complete&lt;/code&gt; and &lt;code&gt;compgen&lt;/code&gt; built-ins for suggesting completions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;compgen&lt;/code&gt; generates completions using a list of words (-W) or list of commands (-c). The latter is of particular interest to us. &lt;code&gt;compgen -c&lt;/code&gt; prints every executable on our path and all shell built-ins and shell-functions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;compgen --help&lt;/code&gt; prints following message:&lt;br&gt;
&lt;code&gt;compgen: compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]&lt;br&gt;
    Display possible completions depending on the options.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The options stand for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a : aliases&lt;/li&gt;
&lt;li&gt;b : shell builtins&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;c : executable commands&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;d : directories in current directory&lt;/li&gt;
&lt;li&gt;e : &lt;strong&gt;export&lt;/strong&gt; variables&lt;/li&gt;
&lt;li&gt;f : files in current directory&lt;/li&gt;
&lt;li&gt;g : groups in system&lt;/li&gt;
&lt;li&gt;j : pending jobs (in background / stopped)&lt;/li&gt;
&lt;li&gt;k : Bash &lt;strong&gt;keywords&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;s : System services&lt;/li&gt;
&lt;li&gt;u : users&lt;/li&gt;
&lt;li&gt;v : All shell variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So &lt;strong&gt;&lt;code&gt;compgen -c | grep 'cat$'&lt;/code&gt;&lt;/strong&gt; should give us every single executable ending with &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Epilogue
&lt;/h3&gt;

&lt;p&gt;Diving into this rabbit-hole has given me a better understanding of how Bash completion works, how apropos finds relevant programs and why man pages are organized into various sections.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>productivity</category>
      <category>python</category>
    </item>
    <item>
      <title>Command-line productivity tips : Getting help in the terminal</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Sun, 11 Nov 2018 18:34:14 +0000</pubDate>
      <link>https://forem.com/rrampage/getting-help-in-the-terminal-4cmo</link>
      <guid>https://forem.com/rrampage/getting-help-in-the-terminal-4cmo</guid>
      <description>&lt;p&gt;The command-line is often a daunting place for beginners. With nothing but a blinking cursor and an unfriendly dark screen staring back at you, despair sets in.&lt;/p&gt;

&lt;p&gt;Here are a few things to do if you are stuck:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. How to find programs for specific tasks
&lt;/h3&gt;

&lt;p&gt;Many times, you want to do a particular task but you do not remember the name of the program which does that. Many shell utilities are not easy to remember at first with their cryptic 2 letter names. &lt;/p&gt;

&lt;p&gt;Worry not, there is a command called &lt;strong&gt;&lt;code&gt;apropos&lt;/code&gt;&lt;/strong&gt; to help you out!&lt;/p&gt;

&lt;p&gt;For example, you want to &lt;strong&gt;show a file with line numbers&lt;/strong&gt;. You know that there is a program but have forgotten its name. You can just type &lt;code&gt;apropos -a line number&lt;/code&gt; to get a list of programs. We use &lt;code&gt;-a&lt;/code&gt; flag so that &lt;code&gt;apropos&lt;/code&gt; will only return those programs which have the words &lt;strong&gt;&lt;code&gt;line&lt;/code&gt; AND &lt;code&gt;number&lt;/code&gt;&lt;/strong&gt; in their description.&lt;/p&gt;

&lt;p&gt;On my computer, it gives the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apropos &lt;span class="nt"&gt;-a&lt;/span&gt; line number
&lt;span class="c"&gt;# Output:&lt;/span&gt;
addr2line &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;        - convert addresses into file names and line numbers.
&lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;               - number lines of files
x86_64-linux-gnu-addr2line &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; - convert addresses into file names and line numbers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 3 programs which have something to do with numbering lines. Let's find out what each of these programs does.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Find out what a program does
&lt;/h3&gt;

&lt;p&gt;Let's have a look at our first candidate &lt;code&gt;addr2line&lt;/code&gt;. &lt;strong&gt;Typing &lt;code&gt;--help&lt;/code&gt; after the command is one way of finding out what a program does&lt;/strong&gt;. It is a convention for command-line programs to print a small help message when you call them with &lt;code&gt;--help&lt;/code&gt;. Some programs also allow do the same on calling with &lt;code&gt;-h&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;addr2line &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;span class="c"&gt;# Output:&lt;/span&gt;
Usage: addr2line &lt;span class="o"&gt;[&lt;/span&gt;option&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;addr&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)]&lt;/span&gt;
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the &lt;span class="nb"&gt;command &lt;/span&gt;line, they will be &lt;span class="nb"&gt;read &lt;/span&gt;from stdin
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok. This does program does something with &lt;code&gt;addresses&lt;/code&gt;, not what we are looking for. Moving on to the next in our list: &lt;code&gt;nl&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;span class="c"&gt;# Output:&lt;/span&gt;
Usage: &lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;OPTION]... &lt;span class="o"&gt;[&lt;/span&gt;FILE]...
Write each FILE to standard output, with line numbers added.
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks like we found our program. Let's try it out. This is our file &lt;code&gt;foo.txt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;foo.txt
&lt;span class="c"&gt;# Output:&lt;/span&gt;
one
two
three

four
five
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;nl &lt;/span&gt;foo.txt
&lt;span class="c"&gt;# Output:&lt;/span&gt;
     1  one
     2  two
     3  three

     4  four
     5  five
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works ok but why is it not numbering blank lines?&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Getting detailed information about a program
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;--help&lt;/code&gt; messages are very concise. If we want to know in detail what a program does, we need to consult the manual or &lt;code&gt;man&lt;/code&gt; pages. These pages are very detailed documentation of what a program does, all its possible options and arguments. Type &lt;code&gt;man nl&lt;/code&gt; and have a look at the information...&lt;/p&gt;

&lt;p&gt;Woah! The terminal screen is filled with information!. You can navigate up and down using the arrow keys and press &lt;code&gt;q&lt;/code&gt; to quit.&lt;/p&gt;

&lt;p&gt;We can see the following in the output:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nt"&gt;-b&lt;/span&gt;, &lt;span class="nt"&gt;--body-numbering&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;STYLE
              use STYLE &lt;span class="k"&gt;for &lt;/span&gt;numbering body lines
&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
STYLE is one of:

       a      number all lines

       t      number only nonempty lines

       n      number no lines

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

&lt;/div&gt;



&lt;p&gt;So, &lt;strong&gt;&lt;code&gt;nl -b a foo.txt&lt;/code&gt;&lt;/strong&gt; will number &lt;strong&gt;all&lt;/strong&gt; lines in foo.txt which is what we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nl -b a foo.txt
# Output:
     1  one
     2  two
     3  three
     4
     5  four
     6  five
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That seems to solve our problem.&lt;/p&gt;

&lt;p&gt;There is also &lt;code&gt;info&lt;/code&gt; command which gives even more detailed usage information. You can try it out using &lt;strong&gt;&lt;code&gt;info nl&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Getting examples for using a program
&lt;/h3&gt;

&lt;p&gt;But what if we just quickly want to get our command to work without having to read a huge wall of text?&lt;/p&gt;

&lt;p&gt;Turns out, there is a nifty utility you can install called &lt;strong&gt;&lt;code&gt;tldr&lt;/code&gt;&lt;/strong&gt;. If you use &lt;code&gt;node&lt;/code&gt; or &lt;code&gt;python&lt;/code&gt; you can install using &lt;code&gt;npm install -g tldr&lt;/code&gt; or &lt;code&gt;pip install tldr&lt;/code&gt; respectively. The &lt;a href="https://tldr.sh/" rel="noopener noreferrer"&gt;tldr page&lt;/a&gt; has a list of other installation options. After installing it, just try out &lt;code&gt;tldr nl&lt;/code&gt; in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tldr &lt;span class="nb"&gt;nl&lt;/span&gt;
&lt;span class="c"&gt;# Output:&lt;/span&gt;
&lt;span class="nb"&gt;nl

  &lt;/span&gt;A utility &lt;span class="k"&gt;for &lt;/span&gt;numbering lines, either from a file, or from standard input.

  - Number non-blank lines &lt;span class="k"&gt;in &lt;/span&gt;a file:
    &lt;span class="nb"&gt;nl &lt;/span&gt;file

....

  - Number all lines including blank lines:
    &lt;span class="nb"&gt;nl&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; a file


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

&lt;/div&gt;



&lt;p&gt;There! We can see the example with easy to understand description.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tldr&lt;/code&gt; is community-driven! People contribute examples for various commands. If your favorite command does not have an entry, you can submit a &lt;a href="https://github.com/tldr-pages/tldr" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;To recap, we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find out possible programs which do particular tasks using &lt;strong&gt;&lt;code&gt;apropos&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Get help information for &lt;strong&gt;&lt;code&gt;$program&lt;/code&gt;&lt;/strong&gt; using &lt;strong&gt;&lt;code&gt;$program --help&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;man $program&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Get examples using &lt;strong&gt;&lt;code&gt;tldr $program&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  PS: What if we are not able to find programs for our tasks
&lt;/h3&gt;

&lt;p&gt;In Section 1, we assume that we will be able to find programs for our task. But many times, we may not have it installed. In such cases, we can search our distribution's package manager e.g &lt;code&gt;apt-get&lt;/code&gt; for Ubuntu or &lt;code&gt;yum&lt;/code&gt; or &lt;code&gt;dnf&lt;/code&gt; for CentOS / Fedora.&lt;/p&gt;

&lt;p&gt;In Ubuntu, we can search all available packages in the repositories using &lt;code&gt;apt-cache search $KEYWORD&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>beginners</category>
      <category>learning</category>
      <category>linux</category>
    </item>
    <item>
      <title>Improving Podcasts on dev.to</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Sat, 10 Nov 2018 07:10:07 +0000</pubDate>
      <link>https://forem.com/rrampage/improving-podcasts-on-devto-42d1</link>
      <guid>https://forem.com/rrampage/improving-podcasts-on-devto-42d1</guid>
      <description>&lt;p&gt;I recently found out that dev.to has a nice &lt;a href="https://dev.to/pod"&gt;podcasts page&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I have some suggestions for better podcast page UX:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ability to &lt;strong&gt;save&lt;/strong&gt; the podcast for later. Podcasts are generally at least 20 minutes long and it may not always be possible to listen right away.&lt;/li&gt;
&lt;li&gt;Upvoting of podcasts using the &lt;strong&gt;heart&lt;/strong&gt; which allows users to discover popular podcasts outside their usual subscriptions.&lt;/li&gt;
&lt;li&gt;Ability to tag podcasts based on content. If users/moderators can add tags to podcasts, it will improve quality of search content.&lt;/li&gt;
&lt;li&gt;A way to suggest podcasts to include on the &lt;a href="https://dev.to/pod"&gt;page&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In general, I think it will be better experience if we can interact with podcast pages in a way similar to articles.&lt;/p&gt;

&lt;p&gt;Finally, this podcast of SEDaily with Leslie Lamport is a great watch for all developers.&lt;br&gt;
&lt;/p&gt;
&lt;div class="podcastliquidtag"&gt;
  &lt;div class="podcastliquidtag__info"&gt;
    &lt;a href="/sedaily/tla-with-leslie-lamport"&gt;
      &lt;h1 class="podcastliquidtag__info__episodetitle"&gt;TLA+ with Leslie Lamport&lt;/h1&gt;
    &lt;/a&gt;
    &lt;a href="/sedaily"&gt;
      &lt;h2 class="podcastliquidtag__info__podcasttitle"&gt;
        Software Engineering Daily
      &lt;/h2&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div id="record-tla-with-leslie-lamport" class="podcastliquidtag__record"&gt;
    &lt;img class="button play-butt" id="play-butt-tla-with-leslie-lamport" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png" alt="play"&gt;
    &lt;img class="button pause-butt" id="pause-butt-tla-with-leslie-lamport" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png" alt="pause"&gt;
    &lt;img class="podcastliquidtag__podcastimage" id="podcastimage-tla-with-leslie-lamport" alt="Software Engineering Daily" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F1%2FlM7fSW24.jpg"&gt;
  &lt;/div&gt;

  &lt;div class="hidden-audio" id="hidden-audio-tla-with-leslie-lamport"&gt;
  
    
    Your browser does not support the audio element.
  
  &lt;div id="progressBar" class="audio-player-display"&gt;
    &lt;a href="/sedaily/tla-with-leslie-lamport"&gt;
      &lt;img id="episode-profile-image" alt="TLA+ with Leslie Lamport" width="420" height="420" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fpodcast%2Fimage%2F1%2FlM7fSW24.jpg"&gt;
      &lt;img id="animated-bars" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fanimated-bars-4e8c57c8b58285fcf7d123680ad8af034cd5cd43b4d9209fe3aab49d1e9d77b3.gif" alt="animated volume bars"&gt;
    &lt;/a&gt;
    &lt;span id="barPlayPause"&gt;
      &lt;img class="butt play-butt" alt="play" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fplaybutt-5e444a2eae28832efea0dec3342ccf28a228b326c47f46700d771801f75d6b88.png"&gt;
      &lt;img class="butt pause-butt" alt="pause" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fpausebutt-bba7cb5f432cfb16510e78835378fa22f45fa6ae52a624f7c9794fefa765c384.png"&gt;
    &lt;/span&gt;
    &lt;span id="volume"&gt;
      &lt;span id="volumeindicator" class="volume-icon-wrapper showing"&gt;
        &lt;span id="volbutt"&gt;
          &lt;img alt="volume" class="icon-img" height="16" width="16" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fvolume-cd20707230ae3fc117b02de53c72af742cf7d666007e16e12f7ac11ebd8130a7.png"&gt;
        &lt;/span&gt;
        &lt;span class="range-wrapper"&gt;
          
        &lt;/span&gt;
      &lt;/span&gt;
      &lt;span id="mutebutt" class="volume-icon-wrapper hidden"&gt;
        &lt;img alt="volume-mute" class="icon-img" height="16" width="16" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fvolume-mute-8f08ec668105565af8f8394eb18ab63acb386adbe0703afe3748eca8f2ecbf3b.png"&gt;
      &lt;/span&gt;
      &lt;span class="speed" id="speed"&gt;1x&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class="buffer-wrapper" id="bufferwrapper"&gt;
      &lt;span id="buffer"&gt;&lt;/span&gt;
      &lt;span id="progress"&gt;&lt;/span&gt;
      &lt;span id="time"&gt;initializing...&lt;/span&gt;
      &lt;span id="closebutt"&gt;×&lt;/span&gt;
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>meta</category>
      <category>discuss</category>
      <category>community</category>
      <category>podcast</category>
    </item>
    <item>
      <title>Git: How to keep your fork updated with remote repository</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Fri, 09 Nov 2018 12:52:41 +0000</pubDate>
      <link>https://forem.com/rrampage/git-how-to-keep-your-fork-updated-with-remote-repository-1g4i</link>
      <guid>https://forem.com/rrampage/git-how-to-keep-your-fork-updated-with-remote-repository-1g4i</guid>
      <description>&lt;p&gt;This is useful when you have forked a repository (repo), cloned it to your local machine and want to keep it in sync with the original repo.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding the remote repo
&lt;/h4&gt;

&lt;p&gt;We can list the remote repositories for our repo with &lt;strong&gt;&lt;code&gt;git remote -v&lt;/code&gt;&lt;/strong&gt; and add the original repo as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add upstream LINK_TO_ORIGINAL_REPO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that it is merely a convention to call it &lt;strong&gt;&lt;code&gt;upstream&lt;/code&gt;&lt;/strong&gt;. You can give any name you want.&lt;/p&gt;

&lt;p&gt;Check that the repo is added to your remote using &lt;strong&gt;&lt;code&gt;git remote -v&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sync with remote
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Check if there are any changes in remote not on your fork using &lt;strong&gt;&lt;code&gt;git fetch upstream&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Checkout whichever branch you are interested ( &lt;strong&gt;&lt;code&gt;git checkout $BRANCH&lt;/code&gt;&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Merge with upstream using: &lt;strong&gt;&lt;code&gt;git merge upstream/$BRANCH&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Push your changes to origin if needed: &lt;strong&gt;&lt;code&gt;git push origin $BRANCH&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Removing the remote repo
&lt;/h4&gt;

&lt;p&gt;If you no longer want to get changes from the remote repo, it is easy to remove it using &lt;strong&gt;&lt;code&gt;git remote remove upstream&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;p&gt;Github's &lt;a href="https://help.github.com/articles/syncing-a-fork/" rel="noopener noreferrer"&gt;help page&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>bash</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
    <item>
      <title>Ensuring that a shell script runs exactly once</title>
      <dc:creator>Raunak Ramakrishnan</dc:creator>
      <pubDate>Tue, 06 Nov 2018 20:10:37 +0000</pubDate>
      <link>https://forem.com/rrampage/ensuring-that-a-shell-script-runs-exactly-once-3d3f</link>
      <guid>https://forem.com/rrampage/ensuring-that-a-shell-script-runs-exactly-once-3d3f</guid>
      <description>&lt;p&gt;Many times, we have shell scripts which perform some important stuff like inserting into database, mailing reports, etc which we want to run exactly one instance of.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter locks!
&lt;/h3&gt;

&lt;p&gt;A simple solution is to create a "lock file" and check if the file exists when the script starts. If the file is already created, it means another instance of that program is running, so we can fail with message "Try again later!". Once the script completes running, it will clean-up and delete the lock file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LOCK_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;a.lock
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOCK_FILE&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="c"&gt;# Lock file already exists, exit the script&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"An instance of this script is already running"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="c"&gt;# Create the lock file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Locked"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOCK_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Do the normal stuff&lt;/span&gt;

&lt;span class="c"&gt;# clean-up before exit&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOCK_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks promising but there are issues with this approach. What happens if the script does not end correctly i.e it exits because of some failure before it reaches the clean-up part of the code? Or if it gets forcibly terminated with &lt;code&gt;Ctrl+C&lt;/code&gt; or &lt;code&gt;kill&lt;/code&gt; command? In both these cases, the created lock file will not be deleted. So next time you run the script, you will always get an error and will have to manually delete the file.&lt;/p&gt;

&lt;p&gt;There is another, more subtle error with the above code. A race condition. If two instances of scripts are started around the same time, it is possible that both of them get past the &lt;code&gt;if [ -f "$LOCK_FILE" ]&lt;/code&gt; because the second instance may reach that part of the code before the first instance is able to create the lock file. Thus, we have more than one instance running.&lt;/p&gt;

&lt;h3&gt;
  
  
  A better lock!
&lt;/h3&gt;

&lt;p&gt;Is there a way to create a lock file which is more robust to race conditions and non-standard termination (&lt;code&gt;Ctrl+C&lt;/code&gt;, &lt;code&gt;kill&lt;/code&gt; command, etc)? Linux offers &lt;code&gt;flock&lt;/code&gt; a utility to manage locks from shell scripts. Using &lt;code&gt;flock&lt;/code&gt;, we can rewrite the above snippet as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LOCK_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;a.lock
&lt;span class="nb"&gt;exec &lt;/span&gt;99&amp;gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOCK_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
flock &lt;span class="nt"&gt;-n&lt;/span&gt; 99 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="c"&gt;# Do stuff and exit!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;exec 99&amp;gt;"$LOCK_FILE"&lt;/code&gt; creates a file descriptor numbered 99 and assigns it to &lt;code&gt;LOCK_FILE&lt;/code&gt;. &lt;a href="https://en.wikipedia.org/wiki/File_descriptor" rel="noopener noreferrer"&gt;File descriptors (fd)&lt;/a&gt;  0, 1, 2 are for &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt; respectively. We are creating new fd with a high number to ensure that it does not clash with numbered fds opened later-on by script.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;flock -n 99 || exit 1&lt;/code&gt; does 2 things. Firstly, it acquires an &lt;code&gt;exclusive&lt;/code&gt; lock on the file descriptor 99 which refers to our &lt;code&gt;LOCK_FILE&lt;/code&gt;. This operation is guaranteed by the linux kernel to be atomic. Secondly, if it fails to acquire the lock, it exits with return code 1. We do not need to worry about any clean up. &lt;code&gt;flock&lt;/code&gt; will automatically release the lock when the script exits regardless of how it terminates. This solves our problem!&lt;/p&gt;

&lt;p&gt;What if I wanted to add a more informational message instead of exiting directly on failure to acquire lock? We can change the line &lt;code&gt;flock -n 99 || exit 1&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flock &lt;span class="nt"&gt;-n&lt;/span&gt; 99
&lt;span class="nv"&gt;RC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Send message and exit&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Already running script. Try again after sometime"&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;p&gt;The flock &lt;a href="http://man7.org/linux/man-pages/man1/flock.1.html" rel="noopener noreferrer"&gt;man page&lt;/a&gt; has an example which you can use to add an exclusive lock to start of any shell script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FLOCKER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exec env &lt;/span&gt;&lt;span class="nv"&gt;FLOCKER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; flock &lt;span class="nt"&gt;-en&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; :
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This boilerplate uses the script file itself as a lock. It works by setting an environment variable &lt;code&gt;$FLOCKER&lt;/code&gt; to script file name and executing the script with its original parameters after acquiring the lock. On failure however, it does not print anything and silently exits.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$0&lt;/code&gt; here stands for name of the script. &lt;code&gt;$@&lt;/code&gt; stands for all arguments passed to the script when it was called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case for me
&lt;/h3&gt;

&lt;p&gt;My team uses a test machine where we deploy multiple branches of a code-base. We need to make sure that exactly one person is building the project at a particular time. The deploy script pulls the specified branch of code from &lt;code&gt;git&lt;/code&gt; and builds the project, deploys the main service and starts ancillary services. The script takes sometime to execute. If someone tries to deploy another branch while a build is ongoing, both can fail.&lt;/p&gt;

&lt;p&gt;With the above snippet, calling the script more than once shows the current branch being built and exits with failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further reading:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flock &lt;a href="http://man7.org/linux/man-pages/man1/flock.1.html" rel="noopener noreferrer"&gt;man page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://mywiki.wooledge.org/BashFAQ/045" rel="noopener noreferrer"&gt;Pitfalls of creating a lock file&lt;/a&gt; like in our initial snippet&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>productivity</category>
      <category>linux</category>
      <category>tips</category>
    </item>
  </channel>
</rss>
