1

I'm trying to get past the "lack" of a good terminal tool on OS X to generate passwords. This script is a mix from various sources and already done debug from my side (here, here, here and here too)

pass=`LC_CTYPE=C < /dev/urandom tr -cd [:graph:] | tr -d '\n' | head -c 32`
echo $pass

I opted for the head -c 32 method instead of the fold -w 32 method because head seems more clear to me after reading their corresponding man page, and because when I use fold, the script just "hangs" (never stop loading). I did clearly understood the -c flag of head is for a number of bytes and not characters and that is why I sometimes have more than 32 characters in my resulting password.

The question being, is there a way to replace head to have 32 characters? (I would accept using fold, of course if you explain me why it does not work and rephrase the use of fold -w so I can understand it clearer than with the description coming from the man).

Example of problematic return :

^[[A]S9,Bx8>c:fG)xB??<msm^Ot|?C()bd] # 36 characters, sadly 
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • 1
    I don't use OSX, but I _suspect_ that `pass` is actually always 32 chars long, but `echo $pass` is sometimes doing funny stuff, depending on the contents. `echo "$pass"` is slightly better, but `echo` is really not suitable for printing arbitrary strings. Try piping the output of your pipeline into a hexdump or `wc` to check. Instead of using `echo $pass` try `printf "%s\n" "$pass"`. BTW, you don't need the second `tr` in the pipeline, as the first one should delete `\n` chars. – PM 2Ring Jan 06 '15 at 13:14
  • Thanks for the comment, I actually did a version without the tr for newlines, and got new lines in my echo'ed pass (maybe it came from the echo itself, as you stated). And since the man for tr only stands `[:graph:] all printable characters, not including space` I was not really sure if newlines was or not in this class so wouldn't or would (yes in that order) be suppressed by tr -cd :) – β.εηοιτ.βε Jan 06 '15 at 13:20
  • You can test it using `printf`. Eg, here's a string with newlines & a tab. `printf "this\nis\ta\ntest\n" | tr -cd '[:graph:]'` – PM 2Ring Jan 06 '15 at 13:25
  • Well. There is something I don't understand at all now : `$ printf "this\nis\ta\ntest\n" | tr -cd '[:graph:]' #I get thisisatest $ echo "this\nis\ta\ntest\n" | tr -cd '[:graph:]' #I get this\nis\ta\ntest\n` but yes, I see the point, I will use printf in the future, thanks – β.εηοιτ.βε Jan 06 '15 at 13:30
  • 1
    That's because `echo` is interpreting `\n` as two separate chars. On Linux we have an `-e` option to `echo` to force it to interpret backslashed chars, but you don't have that facility on OSX `echo`. – PM 2Ring Jan 06 '15 at 13:33
  • 1
    The `bash` built-in `echo` works the same whether you use it on Linux or OS X, and requires the `-e` flag to interpret `\n` as a literal newline character (unlike POSIX `echo`, which will do so by default). – chepner Jan 06 '15 at 13:51
  • @chepner is right `echo -e "this\nis\ta\ntest\n" | tr -cd '[:graph:]'` does the same as `printf "this\nis\ta\ntest\n" | tr -cd '[:graph:]'` even on my OS X something new I learn about such a silly command as *echo* ! Thanks. – β.εηοιτ.βε Jan 06 '15 at 13:56
  • Thanks for that info, @chepner - I was just going from the info on the OSX `echo` man page. – PM 2Ring Jan 06 '15 at 13:57
  • Although... (sorry for that) the man on OS X stands : `Some shells may provide a builtin echo command which is similar or identical to this utility. Most notably, the builtin echo in sh(1) does not accept the -n option. Consult the builtin(1) manual page.` and if fact, echo -e in a shell bin/sh script does not work as the bash one. (it does not accept -e flag) – β.εηοιτ.βε Jan 06 '15 at 14:04

2 Answers2

2

One option would be just to use fold and head together:

pass=$(LC_CTYPE=C < /dev/urandom tr -cd [:graph:] | tr -d '\n' | fold -w 32 | head -n 1)

fold keeps the line length 32 characters, while head exits after capturing the first line. I've updated your backticks to the more modern $( ) syntax as a bonus.

fold -w 32 will insert newlines in the output after every 32 characters of input. As long as there continues to be any input, it will continue to produce output. head -n 1 will exit after one line (using the newlines, closing the pipe and causing all of the commands to terminate.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • I tried with the `$()` in the first but it didn't worked maybe I add a syntaxe error too, silly me :) Now regarding your code, I just want to be sure I understood : was `fold -w 32` hanging because I just forgot to limit the output of /dev/urandom to its first line ? And maybe even sillier question I actually do remove the newlines via tr, so how can head -n 1 even do something ? (Is that not the same line feed ?) – β.εηοιτ.βε Jan 06 '15 at 13:15
  • 1
    I have added some explanation, hopefully that makes things more clear. – Tom Fenech Jan 06 '15 at 14:04
  • Oh ! Thanks, I understand now, so it is the fold that is line feeding the result ! Thanks very much. – β.εηοιτ.βε Jan 06 '15 at 14:06
1

maybe use dd:

echo "$(LC_CTYPE=C < /dev/urandom tr -cd [:graph:] | tr -d '\n' | dd count=1 bs=32 status=none )"

On Linux, the tr -d '\n' seem useless, and the man says

[:graph:] all printable characters, not including space

But I don't know if OSX's tr has the same behaviour

OznOg
  • 4,440
  • 2
  • 26
  • 35