{"id":2227,"date":"2018-12-09T00:13:54","date_gmt":"2018-12-09T00:13:54","guid":{"rendered":"http:\/\/hauweele.net\/~gawen\/blog\/?p=2227"},"modified":"2019-04-15T15:47:25","modified_gmt":"2019-04-15T15:47:25","slug":"dont-forget-the-pipe-subshell","status":"publish","type":"post","link":"https:\/\/hauweele.net\/~gawen\/blog\/?p=2227","title":{"rendered":"Don&#8217;t forget the pipe subshell"},"content":{"rendered":"<p>This is a common error while using pipe over while loops. Consider this shell snippet:<\/p>\n<pre>#!\/bin\/sh\r\n\r\ncat file.txt | while read line\r\ndo\r\n  echo \"inside loop\"\r\n  exit 1\r\ndone\r\n\r\necho \"outside loop\"\r\nexit 0\r\n<\/pre>\n<p>You&#8217;d expect the script to exit on the first line in <i>file.txt<\/i>. However execute this script and you have:<\/p>\n<pre>inside loop\r\noutside loop\r\n<\/pre>\n<p>It is as if the <code>exit 1<\/code> inside the loop is ignored. Another example:<\/p>\n<pre>#!\/bin\/sh\r\n\r\na=0\r\ncat file.txt | while read line\r\ndo\r\n  echo \"inside loop\"\r\n  a=1\r\ndone\r\n\r\necho \"outside loop\"\r\necho \"a=$a\"\r\n<\/pre>\n<p>Here you&#8217;d expect the value of <i>a<\/i> to be 1 at the end of the script. Instead, if you execute this you have:<\/p>\n<pre>inside loop\r\noutside loop\r\na=0\r\n<\/pre>\n<p>It&#8217;s as if the variable <i>a<\/i> isn&#8217;t even updated. In fact it is, though only inside the loop. So what is happening here?<\/p>\n<p>The pipe (<code>|<\/code>) you use to feed the loop creates a subshell. In fact this is really just another process. So the <code>exit 1<\/code> or <code>a=1<\/code> only apply to these <i>piped<\/i> processes.<\/p>\n<p>How can you fix that?<br \/>\nIn the simple case presented above, you can simply use file redirection:<\/p>\n<pre>while read line\r\ndo\r\n  ...\r\ndone &lt; file.txt\r\n<\/pre>\n<p>But what if you really want to feed the loop with the output of another process. Like you would do with <i>find<\/i> for instance.<\/p>\n<p>If you use bash you can use <a href=\"http:\/\/tldp.org\/LDP\/abs\/html\/process-sub.html\">process substitution<\/a> as described <a href=\"https:\/\/stackoverflow.com\/questions\/13726764\/while-loop-subshell-dilemma-in-bash\/13727116#13727116\">here<\/a>. But you shouldn&#8217;t use bash for scripting anyway. For shell scripting you might be tempted to use a temporary file to store the process output:<\/p>\n<pre># Use a temporary file.\r\ntmp=$(mktemp)\r\nfind . &gt; $tmp\r\nwhile read line\r\ndo\r\n  ...\r\ndone &lt; $tmp \r\nrm $tmp\r\n<\/pre>\n<p>However this consumes disk space, and the loop only starts after the <i>find<\/i> process exited. Another option would be to use a named fifo:<\/p>\n<pre>fifo=$(mktemp -u)\r\nmkfifo $fifo\r\nfind . &gt; $fifo &amp;\r\n\r\nwhile read file\r\ndo\r\n  ...\r\ndone &lt; $fifo\r\nrm $fifo\r\n<\/pre>\n<p>This time you create a single file, yet no disk space is used (apart for the fifo inode itself). Also the <i>find<\/i> command is a child process, so the loop reads <i>find<\/i> output as it comes.<\/p>\n<p>Although the version above already works as it should, you may want to use an anonymous fifo. This way you only need to create a fifo file, although you can delete it immediatly. You can achieve this with a little help from our beloved file descriptor 3.<\/p>\n<pre>fifo=$(mktemp -u)\r\n\r\n# Create fifo\r\nmkfifo $fifo\r\n\r\n# Create fd 3 and unlink fifo file.\r\nexec 3&lt;&gt; $fifo\r\nrm $fifo\r\n\r\n# Redirect find to fd 3.\r\nfind . &gt;&amp;3 &amp;\r\n\r\n# Feed fd 3 to while loop.\r\nwhile read line\r\ndo\r\n  ...\r\ndone &lt;&amp;3 # Close fd 3. exec 3&gt;&amp;-\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This is a common error while using pipe over while loops. Consider this shell snippet: #!\/bin\/sh cat file.txt | while read line do echo &#8220;inside loop&#8221; exit 1 done echo &#8220;outside loop&#8221; exit 0 You&#8217;d expect the script to exit &hellip; <a href=\"https:\/\/hauweele.net\/~gawen\/blog\/?p=2227\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[1036,1034,30,1033,1035],"class_list":["post-2227","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-fifo","tag-pipe","tag-shell","tag-subshell","tag-while"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2227"}],"version-history":[{"count":0,"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2227\/revisions"}],"wp:attachment":[{"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hauweele.net\/~gawen\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}