Why can't tr read from /dev/urandom on OSX?
Based on the error message that you get, I don't think /dev/urandom is the problem. If it were, I'd expect an error like "no such file or directory".
I searched for the error message you got and found this, which seems like it might be relevant to your issue: http://nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence
Basically, specify the locale by prepending the tr
command with LC_CTYPE=C
:
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
Your tr
attempts to interpret its input as text in UTF-8 encoding. So it will complain and abort upon the first byte sequence which is not valid UTF-8. Prefixing tr
with LC_ALL=C
or LC_CTYPE=C
will export that variable into the environment of tr
, thus changing its idea of the local character set to the C standard, i.e. everything is just a sequence of opaque bytes.
By the way, is the sequence \)-+
in your command intentional? This includes *
as well, which you already included, but does not include -
itself as you might have intended. Better to write one of these instead:
LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom
As others have indicated, your problem isn't that /dev/urandom
is missing, but rather how tr
works on OS X. Instead of messing around with enviornment varialbes, use perl
in place of tr
:
perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo
This has the advantage of being portable across OS X, Redhat and Ubuntu.
(I also removed the pipe to xargs
, replacing witch echo
, to get a newline at the end of the output.)