<?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: Inzamam ul Haque</title>
    <description>The latest articles on Forem by Inzamam ul Haque (@iaminziee).</description>
    <link>https://forem.com/iaminziee</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%2F89705%2F8be3a373-b077-4f7d-97d7-b45fc0a7f81b.png</url>
      <title>Forem: Inzamam ul Haque</title>
      <link>https://forem.com/iaminziee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/iaminziee"/>
    <language>en</language>
    <item>
      <title>Hbase 'No protocol version header error'</title>
      <dc:creator>Inzamam ul Haque</dc:creator>
      <pubDate>Wed, 17 Jun 2020 19:51:09 +0000</pubDate>
      <link>https://forem.com/iaminziee/hbase-no-protocol-version-header-error-12fl</link>
      <guid>https://forem.com/iaminziee/hbase-no-protocol-version-header-error-12fl</guid>
      <description>&lt;p&gt;Hi there,&lt;/p&gt;

&lt;p&gt;Earlier today, I faced a problem: I had a task that needed python &lt;a href="https://happybase.readthedocs.io/en/latest/index.html"&gt;happybase&lt;/a&gt; to do the operation on Hbase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--52XNhZFp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://inzamam.dev/media/no_protocol_ver_header.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--52XNhZFp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://inzamam.dev/media/no_protocol_ver_header.png" alt='Error mesage screenshot: "No protocol version header error"'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I received: “No protocol version header error”&lt;/p&gt;

&lt;p&gt;Finally, I resolved this problem after digging up Cloudera docs.&lt;/p&gt;

&lt;p&gt;First of all, I have to declare this before going further: the Hbase thrift server was opened before the above issue happened.&lt;/p&gt;

&lt;p&gt;I searched for this HBase config setting in CM:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hbase.regionserver.thrift.http&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It was checked. In /etc/hbase/conf/hbase-sit.xml, It’s value was ’&lt;em&gt;true’&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I found a link: &lt;a href="https://github.com/wbolster/happybase/issues/161"&gt;&lt;em&gt;https://github.com/wbolster/happybase/issues/161&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a06u35kF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://inzamam.dev/media/thrift_hbase__ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a06u35kF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://inzamam.dev/media/thrift_hbase__ss.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I unchecked it. ( In hbase-sit.xml, it becomes ‘false’ )&lt;/p&gt;

&lt;p&gt;Then restarted Hbase service, and problem got solved&lt;/p&gt;

&lt;p&gt;I saw a lot of people had this issue, so sharing here in the hope it would be helpful.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using Docker to spin-up multiple neo4j server instances on same machine</title>
      <dc:creator>Inzamam ul Haque</dc:creator>
      <pubDate>Fri, 08 May 2020 19:30:26 +0000</pubDate>
      <link>https://forem.com/iaminziee/using-docker-to-spin-up-multiple-neo4j-server-instances-on-same-machine-3nn6</link>
      <guid>https://forem.com/iaminziee/using-docker-to-spin-up-multiple-neo4j-server-instances-on-same-machine-3nn6</guid>
      <description>&lt;p&gt;All those working on neo4j might be aware of the fact that on instance of neo4j server can mount only one database at a time. Many a times we come across situations where we have to setup more than one neo4j database, and for that purpose we have to bring up separate neo4j server instance for each database we need, which involves doing a hell lot of manual steps to download installation tarballs, pushing it to different locations on machine, changing ports in configs files, etc. Here, in situation like this docker comes quit handy.&lt;/p&gt;

&lt;p&gt;The key to using more than one neo4j servers simultaneously is to use different ports for http, https and bolt connections which is quite easy to do with the docker image. For my purpose, I configured neo4j in such a way that it can access the database from a non-default location.&lt;/p&gt;

&lt;p&gt;As using docker is invloved here, I’m assuming you already have docker installed on your linux machine. So, lets get our hands dirty.&lt;/p&gt;

&lt;p&gt;We’ll follow these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pulling the neo4j docker image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker pull neo4j&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Running neo4j docker image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, the neo4j docker image mounts the following folders:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;home: /var/lib/neo4j&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config: /var/lib/neo4j/conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;logs: /var/lib/neo4j/logs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;plugins: /var/lib/neo4j/plugins&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import: /import&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data: /var/lib/neo4j/data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;certificates: /var/lib/neo4j/certificates&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;run: /var/lib/neo4j/run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These directories may correspond to the already existing directories on the system. In my case, I already had a neo4j community server running on my machine so all these locations were there and were being used by the server. Therefore, I had to provide a custom location that would provide the same information. These locations would not be there in your computer if you have not installed the server version and only intending to use the docker image. To my knowledge the most import of the above-mentioned folders are data this is where your actual database will be created/stored, import to put for example CSV files for import, conf to put neo4j.conf file.&lt;/p&gt;

&lt;p&gt;Now, we’re going to run the neo4j docker image taking care of running the server on non-default ports and also creating or mounting the required folders from the desired location.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --detach --name=neo4j-instance-1 --rm \&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--publish=7475:7474 --publish=7476:7473 --publish=7688:7687 \&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--volume=$HOME/neo4j-instance-1/data:/data \&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--volume=$HOME/neo4j-instance-1/import:/import \&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--volume=$HOME/neo4j-instance-1/conf:/conf neo4j&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s break-down the above command.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;docker run …… neo4j&lt;/code&gt; is to run the neo4j docker image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;–-detach&lt;/code&gt; to run the container in the background and return the prompt.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--name=neo4j-instance-1&lt;/code&gt; to give the desired name to the docker instance otherwise docker will choose a random name which might not be very easy to remember if we want to refer to this session in future for some reason.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-–rm&lt;/code&gt; is to delete the docker instance from the list upon session termination. This is useful if we want to reuse the same name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-–publish=7475:7474 -–publish=7476:7473 -–publish=7688:7687&lt;/code&gt; to publish/forward the default http, https and bolt ports to the desired ports. In this case, the http, https and bolt ports will be forwarded to the desired 7475, 7476 and 7687 respectively.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--volume=$HOME/neo4j-instance-1/data:/data \&lt;/code&gt;
&lt;code&gt;--volume=$HOME/neo4j-instance-1/import:/import \&lt;/code&gt;
&lt;code&gt;--volume=$HOME/neo4j-instance-1/conf:/conf&lt;/code&gt; to mount the desired locations for the database creation or access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you are running this command for the first time, it will create the folders mentioned in –volume tag. Otherwise, it will mount the existing folders to the neo4j docker defaults.&lt;/p&gt;

&lt;p&gt;If no error is returned then your neo4j server is running and should have been mapped to the desired ports and folders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Check the docker and neo4j server running status.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To check the current running docker session run &lt;code&gt;docker ps&lt;/code&gt;, whis should give you an output something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;1afa157d9caa neo4j "/sbin... 7473/tcp,... 87/tcp neo4j-instance-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To terminate this session: &lt;code&gt;docker kill neo4j-instance-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can also check the status by using: &lt;code&gt;netstsat -tunlp | grep 7475&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To check neo4j running status: open a web browser and then navigate to&lt;/p&gt;

&lt;p&gt;http://:7475 (or the port that you have used for forwarding in step 2)&lt;/p&gt;

&lt;p&gt;It should display a page like the one below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YEn2bpZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/neo4j1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YEn2bpZR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/neo4j1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change the bolt port to 7688 (or the port that you have used for forwarding in step 2), use user/password as neo4j/neo4j and click connect. Set new password in next screen.&lt;/p&gt;

&lt;p&gt;It should connect you to your default graph.db database which should look something like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ikZLDfVN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/neo4j2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ikZLDfVN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/neo4j2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>neo4j</category>
      <category>docker</category>
      <category>graphdb</category>
      <category>data</category>
    </item>
    <item>
      <title>Optimization essentials for your Neo4j Cypher queries</title>
      <dc:creator>Inzamam ul Haque</dc:creator>
      <pubDate>Thu, 16 Apr 2020 07:02:50 +0000</pubDate>
      <link>https://forem.com/iaminziee/optimization-essentials-for-your-neo4j-cypher-queries-hgh</link>
      <guid>https://forem.com/iaminziee/optimization-essentials-for-your-neo4j-cypher-queries-hgh</guid>
      <description>&lt;p&gt;I have been working on Neo4j for quite some time. It has been a good learning experience with it and has allowed exploring and extracting knowledge from connected data. In case you’re not familiar with it, Neo4j is currently the leading vendor in the space of graph databases.&lt;/p&gt;

&lt;p&gt;Around a month ago, while helping on a project of a friend, I had to spend few hours trying to optimize about 10 Cypher queries that not performing good enough (query time ranged from 46786ms to 135759ms) on a QA server. After some trial and error, I had changed them all and brought down query run-time to 2367ms to 5755ms. At that time I understood why it is very necessary to focus on query optimization from the very beginning of your development cycle. So writing this one in case if someone may get help.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;First&lt;/strong&gt; thing towards query optimization is to check the execution plan of your query. Neo4j provides two keywords for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EXPLAIN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PROFILE&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of them can be prefixed with your query to check the execution plan. Only difference between lies in the fact that &lt;code&gt;EXPLAIN&lt;/code&gt; provides estimates of the graph engine processing that will occur, but does not execute the Cypher statement, while &lt;code&gt;PROFILE&lt;/code&gt; provides real profiling information for what has occurred in the graph engine during the query and executes the Cypher statement.&lt;/p&gt;

&lt;p&gt;We can use it like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;PROFILE&lt;/code&gt;&lt;/strong&gt; &lt;code&gt;MATCH&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(celebrity:Person)&amp;lt;-[:FOLLOWS*0..4]-(follower:Person)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;return celebrity,follower limit 500&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mKTlFMcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/profile_neo4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mKTlFMcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lumen.netlify.com/media/profile_neo4j.png" alt="Neo4j Profile Query"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second,&lt;/strong&gt; I started &lt;a href="https://neo4j.com/docs/cypher-manual/current/administration/indexes-for-search-performance/"&gt;indexing&lt;/a&gt; the most frequently used properties of nodes of different labels. This improved the timings by a good margin. For a node, the index can be created on single or multiple nodes.&lt;/p&gt;

&lt;p&gt;For creating a single-property index,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE INDEX [index_name] FOR (n:LabelName) ON (n.propertyName)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For creating a composite index,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE INDEX [index_name] FOR (n:LabelName)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ON (n.propertyName_1, n.propertyName_2, ..., n.propertyName_n)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remember that_, If you have set a constraint on any property of a node, there is no need to create index for that property._&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third&lt;/strong&gt; , make sure to use parameters in maximum numbers of cypher queries is using parameter(s). If you go through &lt;a href="https://neo4j.com/docs/cypher-manual/current/syntax/parameters/"&gt;Neo4j documentation&lt;/a&gt;, you’ll know how it helps in caching of execution plans.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fourth,&lt;/strong&gt; although it will be possible always, is to avoid &lt;code&gt;ORDER BY&lt;/code&gt; and &lt;code&gt;DISTINCT&lt;/code&gt; clauses if not needed compulsorily. They add a lot of time.&lt;/p&gt;

&lt;p&gt;I’ve been still unable to fully simplify few of the things which include removal of optional paths. Like one of below format:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MATCH A-[o?:optional]-B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WHERE (o is present, match B to C and D)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OR (o is absent, match A to E and F)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I’ll update this section later whenever I get a full-proof way to remove optional paths. If you have any suggestions on this, please help me out on twitter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fifth,&lt;/strong&gt; If you are running updates make sure that your updates handle data of about 10k-100k records, if you have more, please batch them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sixth,&lt;/strong&gt; try to run tests on servers with as much less as resources available, I would recommend your local machine.&lt;/p&gt;

&lt;p&gt;One more suggestion from my side would be to use test/development data this is a bit close to production data. This will help against the discovery of special cases in your data; like you might find later that some nodes are heavily connected, others, not so much, and some queries perform differently for lightly and heavily connected nodes.&lt;/p&gt;

&lt;p&gt;For Summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try to check the query plan with &lt;code&gt;EXPLAIN&lt;/code&gt; and &lt;code&gt;PROFILE.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Analyze time taken not only during the execute() on the query, but also the time to iterate through the results.&lt;/li&gt;
&lt;li&gt;Index your most-used properties.&lt;/li&gt;
&lt;li&gt;Parameterize your queries.&lt;/li&gt;
&lt;li&gt;Examine your MATCH and RETURN clauses. Include in the MATCH only those parts that are required in RETURN. The remaining which would be to filter the results can go into the WHERE.&lt;/li&gt;
&lt;li&gt;Get rid of &lt;code&gt;ORDER BY&lt;/code&gt; and &lt;code&gt;DISTINCT&lt;/code&gt; wherever possible.&lt;/li&gt;
&lt;li&gt;Optional paths can be moved from the MATCH into WHERE if you don’t needed.&lt;/li&gt;
&lt;li&gt;Try to use live data as far as possible.&lt;/li&gt;
&lt;li&gt;Use batches while running updates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can refer to these for more details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neo4j.com/docs/developer-manual/current/cypher/query-tuning/"&gt;Developer Manual: Query Tuning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neo4j.com/docs/developer-manual/current/cypher/execution-plans/"&gt;Developer Manual: Execution Plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@mesirii/5-tips-tricks-for-fast-batched-updates-of-graph-structures-with-neo4j-and-cypher-73c7f693c8cc"&gt;Batched Efficient Updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/neo4j/loading-graph-data-for-an-object-graph-mapper-or-graphql-5103b1a8b66e"&gt;Efficient Loading of Sub-graphs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>neo4j</category>
      <category>cypher</category>
      <category>graphdb</category>
      <category>optimisation</category>
    </item>
    <item>
      <title>Shell loops to process text files? Think again!</title>
      <dc:creator>Inzamam ul Haque</dc:creator>
      <pubDate>Fri, 10 Apr 2020 15:12:13 +0000</pubDate>
      <link>https://forem.com/iaminziee/shell-loops-to-process-text-files-think-again-5264</link>
      <guid>https://forem.com/iaminziee/shell-loops-to-process-text-files-think-again-5264</guid>
      <description>&lt;p&gt;Holla folks! How’s lockdown going on? 😁&lt;/p&gt;

&lt;p&gt;I’m writing this as first entry to this what I think could live on to be called my blog. A lot of procrastination, a hell lot of ifs and buts on how should I start writing, and then yesterday I decided to write on it!&lt;/p&gt;

&lt;p&gt;I am not sure whether you have used shell scripts or you write them regularly. In any case, just take this post as my opinion, not as set of hard-bound rules .&lt;/p&gt;

&lt;p&gt;Lately, I have come across many scripts and people writing them for the purpose of processing text files, having things like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while read row; do

   echo $row | cut -c3

done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for row in `cat file`; do

   foo=`echo $row | awk '{print $2}'`

   echo blahblah $foo

done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Those are naive literal translations of what you would do in languages like C or python, but that’s not how you do things in shells, and those examples are very inefficient, completely unreliable, and if you ever manage to fix most of the bugs, your code becomes illegible(I will explain this later.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conceptually,&lt;/strong&gt; in these languages, building blocks are just one level above machine instructions. You tell your processor what to do and then what to do next. You open that file, you read that many bytes, you do this, you do that with it.&lt;/p&gt;

&lt;p&gt;Shells are a higher level language. I would say it’s not even a language, they’re just all command line interpreters. The job is done by those commands you run and the shell is only meant to orchestrate them.&lt;/p&gt;

&lt;p&gt;I think shell is more like a plumbing tool. You open the files, setup the pipes, invoke the commands. and when it’s all ready, it just flows without the shell doing anything. The tools do their job concurrently, efficiently at their own pace with enough buffering so as not one blocking the other, it’s just beautiful and yet so simple.&lt;/p&gt;

&lt;p&gt;Let’s take an example of &lt;code&gt;cut&lt;/code&gt;, it is like opening the kitchen drawer, take the knife, use it, wash it, dry it, put it back in the drawer.&lt;/p&gt;

&lt;p&gt;When you do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while read row; do

   echo $row | cut -c3

done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s like for each line of the file, getting the &lt;code&gt;read&lt;/code&gt; tool from the drawer, read a line, wash your read tool, keep it back to the drawer. Then schedule a meeting for the &lt;code&gt;echo&lt;/code&gt; and &lt;code&gt;cut&lt;/code&gt; tool, get them from the drawer, invoke them, wash them, dry them, place them back in the drawer. This process keeps repeating till the last line.&lt;/p&gt;

&lt;p&gt;You can just read the above para as: slicing an onion but washing your knife and putting it back to the drawer between each slice. But Here, the obvious better way is to get your cut tool from the drawer, slice your whole onion and put it back in the drawer after the whole job is done.&lt;/p&gt;

&lt;p&gt;In other words, in shells, especially to process text, you should invoke as few utilities as possible and have them cooperate to the task, not run thousands of tools in sequence waiting for each one to start, run, clean up before running the next one.&lt;/p&gt;

&lt;p&gt;Talking in terms of &lt;strong&gt;performance,&lt;/strong&gt; When you do a &lt;code&gt;fgets()&lt;/code&gt; or &lt;code&gt;fputs()&lt;/code&gt; in C, that’s a function in stdio. stdio keeps internal buffers for input and output for all the stdio functions, to keep away from to doing expensive system calls too often.But, The corresponding even builtin shell utilities (&lt;code&gt;read&lt;/code&gt;, &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;printf&lt;/code&gt;) can’t do that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;read&lt;/code&gt; is meant to read one line. If it reads past the newline character, that means the next command you run will miss it. So read has to read the input one byte at a time. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;printf&lt;/code&gt; can’t just buffer its output, it has to output it straight away because the next command you run will not share that buffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And especially, when we get on to processing the big file, which could have thousands or millions of lines, it is not fine for the shell script to take a significant fraction of a second (even if it’s only a few dozen milliseconds) for each line, as that could add up to hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the alternative?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of using a loop to look at each line, we need to pass the whole file through a pipeline of commands. This means that, instead of calling the commands thousands or millions of time, the shell calls them only once. It’s true that those commands will have loops to process the file line-by-line, but they are not shell scripts and they are designed to be fast and efficient.&lt;/p&gt;

&lt;p&gt;Unix has many wonderful built in tools, ranging from the simple to the complex, that we can use to build our pipelines. Simple tools include &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;tr&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;(when merging 2 files), and &lt;code&gt;awk&lt;/code&gt; one-liners, among many others. When it gets more complex, and you really have to apply some logic to each line, &lt;code&gt;awk&lt;/code&gt; is a good option.&lt;/p&gt;

&lt;p&gt;I’m giving you a simple example from a script I’ve written:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat file.txt | grep -w "|" | grep -Ewo "[0-9]" | sed '4q;d' | awk '{$1=$1};'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I’m pushing contents of file.txt to pipe using &lt;code&gt;cat file.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;then selecting only lines containing ’|’ using &lt;code&gt;grep -w "|"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;selecting lines containing only digits by, &lt;code&gt;grep -Ewo "[0-9]"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;then just selecting the 4th line from the file using, &lt;code&gt;sed '4q;d'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and in last, removing white-spaces by &lt;code&gt;awk '{$1=$1};'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, my suggestion as a whole would be to avoid using shell for doing what it’s not very good at and what it is not intended for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally&lt;/strong&gt; , I would close this on note that Its all your call to decide what to use based on the situation and your requirements. And with a good old proverb of ”&lt;em&gt;horses for courses”,&lt;/em&gt; I would suggest that next time take a pause before thinking: ’ &lt;strong&gt;I’m going to do this in shell’!&lt;/strong&gt; 😄&lt;/p&gt;

&lt;p&gt;In case if you want to dig into some deeper details, I’m leaving with few good articles/answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://unix.stackexchange.com/questions/209123/understanding-ifs-read-r-line/209184#209184"&gt;Stéphane Chazelas answer on stackoverflow on: Understanding “IFS= read -r line”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.unix.com/homework-and-coursework-questions/261027-alternative-solution-nested-loops-shell-programming.html"&gt;Alternative solution to nested loops in shell programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.theunixschool.com/2012/06/10-tips-to-improve-performance-of-shell.html"&gt;10 tips to improve Performance of Shell Scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tada!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>shell</category>
      <category>bash</category>
      <category>scripting</category>
    </item>
  </channel>
</rss>
