I want to generate a random password, and am doing it like so:

</dev/urandom tr -dc [:print:] | head -c 64

On my laptop, which runs Ubuntu, this produces only printable characters, as intended. But when I ssh into my school's server, which runs Red Hat Enterprise Linux, and run it there, I get outputs like 3!ri�b�GrӴ��1�H�<�oM����&�nMC[�Pb�|L%MP�����9��fL2q���IFmsd|l�K, which won't do at all. What might be going wrong here?


It's your locale and tr problem.

Currently, GNU tr fully supports only single-byte characters. So in locales using multibyte encodings, the output can be weird:

$ </dev/urandom LC_ALL=vi_VN.tcvn tr -dc '[:print:]' | head -c 64
`�pv���Z����c�ox"�O���%�YR��F�>��췔��ovȪ������^,<H ���>

The shell will print multi-byte characters correctly, but GNU tr will remove bytes it think non-printable.

If you want it to be stable, you must set the locale:

$ </dev/urandom LC_ALL=C tr -dc '[:print:]' | head -c 64
| improve this answer | |
  • 14
    +1 because this made me realise (having use shells on Unix/Linux for only about 30 years), that the stdin/stdout/stderr redirection doesn't have to be positioned after the command it applies to. – Anthon Feb 2 '15 at 13:25
  • Just a comment, if some strange locale is set, shouldn't the shell still be able to print the characters correctly, even if they are not ascii? At least a competent shell (excluding xterm of course)? – orion Feb 2 '15 at 13:26
  • 2
    @orion: the shell will print the characters correctly. In this case, that's tr problem. It removed bytes it think non-printable, make the result weird. – cuonglm Feb 2 '15 at 13:32
  • @orion A uniformly random stream of bytes will not, in general, be a uniformly random stream of well-formed UTF-8 character encodings. – zwol Jun 18 '15 at 16:30
  • Also, unless you what spaces in your password, you should use :graph: instead of :print:: </dev/urandom LC_ALL=C tr -dc '[:graph:]' | head -c 64 – edan Apr 12 '18 at 16:56

Consider instead

$ dd if=/dev/urandom bs=48 count=1 status=none | base64

This has two advantages:

  • You read only 48 bytes from the random device, not ~8KB; if other processes on the same host need random numbers, 8KB drained all at once can be a serious problem. (Yes, arguably nobody should be using the blocking random device, but people do.)

  • The output of base64 contains almost no characters with special meanings. (For none at all, tack | tr +/ -_ on the end, and (as in the example) make sure the number of bytes input to base64 is a multiple of 3.)

A password generated this way has exactly 384 bits of entropy, which is somewhat less than what you were doing (log2 9664 ≈ 421.4), but more than enough for most purposes (256 bits of entropy is safely in "still guessing when the Sun burns out" territory except for RSA keys, AFAIK).

| improve this answer | |

Other people already pointed out that locale determines what [:print:] means. However, not all printable characters are suitable for passwords (not even in ascii). You really don't want spaces, tabs, and #$%^? in your password - it's not just difficult to remember, it's also potentially dangerous to the underlying authentication system, may be impossible to enter in an input field, and so on. In this case, you should just manually select "sane" characters:

LC_ALL=C </dev/urandom tr -dc '[:alnum:]_' | head -c 64

or simply

</dev/urandom tr -dc 'A-Za-z0-9_' | head -c 64

Or even better, use base64 as suggested in other answers.

| improve this answer | |
  • The password in question is never going to be entered by humans (if it were I'd be using Diceware instead) and I'm quite sure that the underlying system can handle special characters without problems. Thanks anyway. – Taymon Feb 2 '15 at 15:34
  • 4
    What you say is utterly wrong. Forcing users to use only ascii letters, digits and underscore reduces the alphabet size considerably, making much easier to break passwords for attackers. An authentication system that cannot even handle ? or ^ is just too bad to be taken seriously. – Bakuriu Feb 2 '15 at 21:16
  • 2
    If your auth system or input fields choke on regular ASCII symbols... then you're doing something wrong and are not to be trusted with my private information. There is absolutely no reason not to accept all manner of characters (including spaces) in your passwords. – nzifnab Feb 2 '15 at 23:14
  • 2
    It appears this is not the case here, but when it comes to human input, it's much easier to remember a long alphanumeric password that holds a unique meaning to the owner than a shorter jumble of symbols. There's also the issue of inputting these characters on various keyboards (not everybody has ^ on the first level and most people don't even know where or what a backtick is), input boxes almost certainly can't handle the tab character, and a surprising number of webforms out there are still susceptible to validation errors, sql injection, or even uncertain case sensitivity. – orion Feb 2 '15 at 23:38
  • 1
    Just a note: in C locale [:print:] class does not include tabs. It is only [:alnum:] + [:punct:] + space (single space, not [:space:]). – jimmij Feb 3 '15 at 21:50

What about

tr -dc [:print:] < /dev/urandom | head -c 64 | strings

strings should print the output of urandom in a printable format

| improve this answer | |
  • This gives -bash: /dev/urandom: Permission denied – Anthon Feb 2 '15 at 11:32
  • sorry forgot the leading cat – Blindstealer Feb 2 '15 at 11:40

I don't know if there's any reason why you use /dev/random to generate the password, but I would recommend you using pwgen in order to ease your pain.

$ pwgen -s 10 1

Where 10 is the length of the password.


| improve this answer | |
#Chars allowed in password (I don't like l,o,O, etc):

#Or such:

head -c 8 < /dev/urandom | tr '\000-\377' "$P$P$P$P$P"

This method IMHO is smarter when consume data from /dev/urandom The string pasted as $P$P$P... must be at least 256 chars long.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.