{"id":8,"date":"2013-09-28T06:28:52","date_gmt":"2013-09-28T06:28:52","guid":{"rendered":"http:\/\/143.198.247.44\/wordpress\/?p=8"},"modified":"2024-10-04T16:35:12","modified_gmt":"2024-10-04T16:35:12","slug":"bash-the-pipes","status":"publish","type":"post","link":"https:\/\/www.type.sh\/index.php\/2013\/09\/28\/bash-the-pipes\/","title":{"rendered":"Bash the Pipes"},"content":{"rendered":"<p>Bash shell is often seen as simple launcher for other programs, when in fact it is fairly sophisticated piece of software. It has its own language, its own start-up scripts (several of them, executed depending on context) and its own job management service. \u00a0 In this post I explore the bash redirects, pipes and their typical use cases. I am not going to repeat basic examples that can be found in every tutorial, instead I will go over a few tricks, shortcuts and gotchas I came across while working with bash shell. I am not a bash expert, but still I hope that some of the examples may be useful.<\/p>\n<ol>\n<li>Need to delete a content of a file? Easy, use &#8220;&gt;&#8221; :\n<pre class=\"brush: bash; gutter: true\">dd if=\/dev\/random bs=1 count=16 &gt; myfile # creates a file\r\n&gt; myfile #removes the content of myfile<\/pre>\n<\/li>\n<li>Bash allows commands to be grouped. In this case the output streams of all commands in the list are combined:\n<pre class=\"brush: actionscript3; gutter: true\">(echo  1_error 1&gt;&amp;2; echo 1_output)<\/pre>\n<p>The line above produces two messages, &#8220;1_error&#8221; goes to the combined STDERR, while &#8220;1_output&#8221; goes to the combined STDOUT. We will use this construct below.<\/p>\n<p>For more details on the command grouping see here: <a title=\"Grouping\" href=\"http:\/\/www.gnu.org\/software\/bash\/manual\/html_node\/Command-Grouping.html\" target=\"_blank\" rel=\"noopener\">reference<\/a>.<\/li>\n<li>To redirect the standard error to standard output use &#8220;2&gt;&amp;1&#8221;. There is also a shortcut \u00a0 &#8220;&amp;&gt;&#8221; for &#8220;2&gt;&amp;1 \u00a0&gt;&#8221;. \u00a0Finally, &#8220;&amp;|&#8221; is a shortcut for &#8220;2&gt;&amp;1 |&#8221;\n<pre class=\"brush: bash; gutter: true\">(echo  1_error 1&gt;&amp;2; echo 1_output) #outputs to both STDOUT and STDERR\r\n(echo  1_error 1&gt;&amp;2; echo 1_output)  2&gt; \/dev\/null # supresses STDERR\r\n(echo  1_error 1&gt;&amp;2; echo 1_output)  1&gt; \/dev\/null # supresses STDOUT\r\n(echo  1_error 1&gt;&amp;2; echo 1_output) | tr 1 2 # only STDOUT is tr&#039;ed\r\n(echo  1_error 1&gt;&amp;2; echo 1_output)  2&gt;  &gt;(tr 1 2) # only STDERR is tr&#039;ed (we are using &#039;process substitution&#039;)\r\n(echo  1_error 1&gt;&amp;2; echo 1_output)  2&gt;&amp;1 | tr 1 2 # both are tr&#039;ed\r\n(echo  1_error 1&gt;&amp;2; echo 1_output) |&amp; tr 1 2 # both are tr&#039;ed\r\n(echo  1_error 1&gt;&amp;2; echo 1_output) &amp;&gt; &gt;(tr 1 2) # both are tr&#039;ed<\/pre>\n<\/li>\n<li>The order of redirects is important:\n<pre class=\"brush: bash; gutter: true\">(echo  1_error 1&gt;&amp;2; echo 1_output)  1&gt; \/dev\/null 2&gt;&amp;1 #outputs nothing\r\n(echo  1_error 1&gt;&amp;2; echo 1_output) 2&gt;&amp;1  1&gt; \/dev\/null #outputs &quot;1_error&quot; to STDOUT<\/pre>\n<p>It is useful to think of a sequence of redirects as if it&#8217;s a program that operates on stream names and their locations. In the first example, \u00a0&#8220;1&gt; \/dev\/null&#8221; sets STDOUT to location &#8220;\/dev\/null&#8221;, then &#8220;2&gt;&amp;1&#8221; sets STDERR to point to the same location as STDOUT, i.e. &#8220;dev\/null&#8221;. In the second example, STDERR is set to the location of STDOUT, and then STDOUT name is set to point to &#8220;\/dev\/null&#8221; location.<br \/>\nLet&#8217;s illustrate this by the following example:<\/p>\n<pre class=\"brush: bash; gutter: true\">(echo  1_error 1&gt;&amp;2; echo 1_output) 3&gt;&amp;1 1&gt;&amp;2 2&gt;&amp;3- | tr 1 2<\/pre>\n<p>In this example we swap STDOUT and STDERR. First, we introduce a new file handler &#8220;3&#8221; and make it point to the current location of STDOUT, then we make STDOUT point to the current location of STDERR, and finally STDERR is made to the location of &#8216;3&#8217;, which is the original location of STDOUT. &#8220;-&#8221; means &#8220;close the file handle after we are done&#8221;.<br \/>\nSome of the examples were borrowed here: \u00a0\u00a0<a href=\"http:\/\/stackoverflow.com\/questions\/1507816\/with-bash-how-can-i-pipe-standard-error-into-another-process\">http:\/\/stackoverflow.com\/questions\/1507816\/with-bash-how-can-i-pipe-standard-error-into-another-process<\/a><\/li>\n<li>An interesting application. We can highlight error messages in the command output:\n<pre class=\"brush: bash; gutter: true\">color()(set -o pipefail; bash -c &quot;$@&quot; 2&gt;&amp;1&gt;&amp;3|sed $&#039;s,.*,\\e[31m&amp;\\e[m,&#039;&gt;&amp;2)3&gt;&amp;1<\/pre>\n<p>Now execute<\/p>\n<pre class=\"brush: actionscript3; gutter: true\">color  &quot;(echo  1_error 1&gt;&amp;2; echo 1_output)&quot;<\/pre>\n<p>to see it in action. For more details take a look <a title=\"Color output\" href=\"http:\/\/serverfault.com\/questions\/59262\/bash-print-stderr-in-red-color\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/li>\n<li>Sudo and tee. Redirects will fail if there is not enough permissions to write a file. As a workaround we can use &#8220;sudo tee&#8221; trick:\n<pre class=\"brush: bash; gutter: true\">touch protected.file\r\nchmod a-xrw protected.file\r\necho test &gt; protected.file # fails\r\nsudo echo test &gt; protected.file #fails as well\r\necho test | sudo tee protected.file #this works\r\necho test | sudo tee protected.file &gt;\/dev\/null #works and suppresses STDOUT as we don&#039;t need it<\/pre>\n<\/li>\n<li>Programs can detect that their output is being redirected. For example, run &#8220;ls \/bin&#8221; and &#8220;ls \/bin &gt; list.txt&#8221;. In the former case the output has several columns, while in the later the output is one column. To test create outputtest.sh:\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nif &#x5B;&#x5B; -t 1 ]] ; then\r\n  echo stdout is a terminal\r\nelse\r\n  echo stdout is not a terminal\r\nfi\r\n<\/pre>\n<p>(taken from http:\/\/stackoverflow.com\/questions\/9340129\/test-stdout-and-stderr-redirection-in-bash-script)<br \/>\nThe script can be confused by<\/p>\n<pre class=\"brush: bash; gutter: true\">outputtest.sh &gt; \/dev\/pts\/3 #still console but not the current one<\/pre>\n<\/li>\n<li>Run-time redirection. In Linux it is possible to redirect the output of already running process. This is a bit hacky but doable. Get screenify script from here<br \/>\n<a title=\"Screenify\" href=\"https:\/\/gist.github.com\/mikebern\/8214869\" target=\"_blank\" rel=\"noopener\">script<\/a><br \/>\nRun the following script that just prints its PID<\/p>\n<pre class=\"brush: bash; gutter: true\">ruby -e &#039;while (1) do print(&quot;my pid is &quot; + $$.to_s() + &quot; \\n&quot;); sleep(10) end&#039;&amp;<\/pre>\n<p>Execute<\/p>\n<pre class=\"brush: bash; gutter: true\">.\/screenify &lt;pid&gt; &gt; newoutputdestination.txt<\/pre>\n<\/li>\n<li>Pipes can have names. I haven&#8217;t been in a situation when this functionality is needed, but it still gives an idea how things work under the hood. In one terminal window run:\n<pre class=\"brush: bash; gutter: true\">mkfifo \/tmp\/mypipe\r\ncat \/tmp\/mypipe<\/pre>\n<p>In another terminal execute:<\/p>\n<pre class=\"brush: bash; gutter: true\">ls \/bin &gt; \/tmp\/mypipe<\/pre>\n<p>The output of &#8220;ls&#8221; will appear in the first terminal window.<\/li>\n<li> Statuses. There are ways to obtain the status of each command in a pipe, and there is an option that ensures that a failing command status is not lost and is returned as the status of the entire pipe:\n<pre class=\"brush: bash; gutter: true\">\r\n# We can get the status for all commands in a pipe\r\nfalse | true\r\necho &quot;Statuses: ${PIPESTATUS[0]} ${PIPESTATUS[1]}&quot;\r\n\r\n# &quot;pipefail&quot; option forces the pipe to return the the first non-zero status (and zero otherwise)\r\nset -o pipefail\r\nfalse | true\r\necho &quot;With pipefail on: $?&quot;\r\n\r\n# turn &quot;pipefail&quot; off\r\nset +o pipefail\r\nfalse | true\r\necho &quot;With pipefail off: $?&quot;\r\n\r\n<\/pre>\n<\/li>\n<li> The last command in a pipe can run in the same process as the script itself. This can be convenient if we want to use the same set of variables:\n<pre class=\"brush: bash; gutter: true\">\r\n#!\/bin\/bash\r\n# With this option the last command in the pipe runs in the same process\r\n# so the updates to the bash variables are visible. \r\nshopt -s lastpipe\r\nn=0\r\nyes | n=1\r\necho &quot;n is $n&quot;\r\n# If the option is unset then the updates are lost\r\nshopt -u lastpipe\r\nn=0\r\nyes | n=1\r\necho &quot;n is $n&quot;\r\n<\/pre>\n<\/li>\n<li>Misc.\n<ul>\n<li>If want to know what &#8220;&gt;|&#8221; does, then check &#8220;noclobber&#8221; option. See <a title=\"Noclobber\" href=\"http:\/\/www.cyberciti.biz\/tips\/howto-keep-file-safe-from-overwriting.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/li>\n<li>It is possible to statically redirect outputs for all subsequent shell commands:\n<pre class=\"brush: bash; gutter: true\">exec 2&gt;&amp;1<\/pre>\n<\/li>\n<li>&#8220;&gt;&amp;&#8221; is the same as &#8220;&amp;&gt;&#8221;, but the latter is preferable.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Bash shell is often seen as simple launcher for other programs, when in fact it is fairly sophisticated piece of software. It has its own language, its own start-up scripts (several of them, executed depending on context) and its own job management service. \u00a0 In this post I explore the bash redirects, pipes and their\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.type.sh\/index.php\/2013\/09\/28\/bash-the-pipes\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[10,5],"class_list":["post-8","post","type-post","status-publish","format-standard","hentry","category-linux","tag-bash","tag-i-o-redirect"],"_links":{"self":[{"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/posts\/8","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/comments?post=8"}],"version-history":[{"count":2,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/posts\/8\/revisions"}],"predecessor-version":[{"id":10,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/posts\/8\/revisions\/10"}],"wp:attachment":[{"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/media?parent=8"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/categories?post=8"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.type.sh\/index.php\/wp-json\/wp\/v2\/tags?post=8"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}