6

When I run the following script:

#!/bin/bash
cat /dev/urandom | tr -dc '[:graph:]' | head -c 64

(which is supposed to print 64 random characters and it does)

I get the following output:

Kn5Thh'H]F2NMG3^2(T*GdH]C+|Y0uj%C?LGFo=9d9o%vcP9k~6u~Q&exr`RuQv{./myScript: line 2: 21677 Broken Pipe             cat /dev/urandom
     21678                       | tr -dc '[:graph:]'
     21679 Done                    | head -c 64

Why am I getting the Broken Pipe error? Is it because cat doesn't finish printing but head is already done, so it sends a SIGPIPE?

How do I avoid this?

bp99
  • 338
  • 3
  • 15

3 Answers3

8

Well, this behavior seems to depend on two settings:

  1. compile-time option DONT_REPORT_SIGPIPE hasn't been set in your bash version (cf config-top.h)
  2. bash option set -o pipefail is in effect in your environment

Nonetheless, you can create a subshell with parentheses, and redirect the standard-error of the subshell into /dev/null:

(tr -dc '[[:graph:]]' </dev/urandom | head -c64) 2>/dev/null

--- Before the last edit this answer looked like this: ---

tr -dc '[[:graph:]]' </dev/urandom 2>/dev/null | head -c64
Lorinczy Zsigmond
  • 1,749
  • 1
  • 14
  • 21
4

You do not actually need a pipe in the first place and you do not need to use cat to print the output of /dev/urandom this is a very bad habit to spawn unnecessary processes and waste cycles.

The following command works fine (bash):

head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)

output:

$ head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)
\|_)gk$,gIW%vvBcc~B~:N2*FwozcdomgUI~I9$r$9Wj`q$KT4IoNI`)SS-i"Sc^

$ head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)                                                                                             
T8j0,?L))L4n@|(*EJ>Nkd|c7^t'[-7rnq8;E!sxIc>;SwOIhiPY"Zp}QWH&95nC

READINGS:

https://www.ibm.com/developerworks/aix/library/au-badunixhabits.html#ten https://www.infoworld.com/article/2614499/unix/unix--when-pipes-don-t-make-sense.html https://superuser.com/questions/1059781/what-exactly-is-in-bash-and-in-zsh http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html

For other shells use:

tr -dc '[[:graph:]]' </dev/urandom | head -c64
Allan
  • 12,117
  • 3
  • 27
  • 51
  • 1
    How about using a non bash-only variation: `tr -dc '[[:graph:]]' – Lorinczy Zsigmond Feb 11 '18 at 05:05
  • thank you for your insight!!! :) I have edited the post to take into account other shells – Allan Feb 11 '18 at 07:10
  • 1
    Thanks, I didn't realise I could ditch `cat` altogether... However, using `head -c64 <(tr -dc '[:graph:]' < /dev/urandom)` still results in a `Broken Pipe` error... – bp99 Feb 11 '18 at 19:49
1

Your diagnosis of the cause of the problem is correct, and one easy workaround is to use sed instead of head: sed -n "1,10p" is equivalent to head -n10. Or in your particular case, this will match and print the first 64 characters from the standard input:

sed -rn "1s/(.{64}).*/\1/p"

-r is a Gnu extension. Without it, it looks more complicated but it's just because the special characters must be escaped:

sed -n "1s/\(.\{64\}\).*/\1/p"

Different systems may require a different quote character, e.g. ' instead of ".

Russ Jones
  • 21
  • 4