2

I have a bash script that is reading quite a bit of data /dev/random. I need the user to type randomly to seed the random daemon. However once the script completes everything typed will get dumped to command input. Here's the code:

for i in ${users_thing[@]}
do
    pass[${num}] = $(dd if=/dev/random status=noexfer bs=1 count=128 | base64) & #generate password
    echo -n "Creating password: `expr $num + 1` of $sizes "     
#tell what's going of
    echo -en "\033[s"
    while [[ $(jobs) != *Exit* ]]  #while the program is still running 
    do
        for j in ${spinny_thing[@]} #now spin
        do 
           echo -en "\033[u\033[1D$j        "
        done
    done
    echo ""
    num=`expr $num + 1`
done

So I would like to be able to dump the standard input without interrupting the foreground process so read is out because it pauses. Would it be possible to some how map it /dev/null?

  • #now spin you beotch! what a nice comment. On a more serious note, might it be possible to have a child process read stdin constantly? And just kill it when the parent is done? – Drew McGowen Jul 24 '14 at 20:27
  • I was thinking about that but I found read doesn't work in the background, and I don't know how to read the standard in directly. – Micah Jul 24 '14 at 20:34
  • cat >/dev/null is one way to read stdin – Drew McGowen Jul 24 '14 at 20:41
  • Alternatively why don't you use /dev/urandom instead and negate the requirement to press keys. It has less entropy apparently - only you know if that will cause issues in your application. – garethTheRed Jul 24 '14 at 20:50
  • 1
    /dev/urandom is also good for a cryptographically secure PRNG. Do you really really need the data to be that random? Are the stakes high enough for the time your users will lose? See also: security.stackexchange.com/questions/3936/… – Valmiky Arquissandas Jul 24 '14 at 21:51
3

If understand what you're wanting, using read should accomplish your goal. However you don't want the read to sit there blocking indefinitely, so you pass a timeout.

For example:

#!/bin/bash

sleep 5
echo done sleeping
read -N 10000000 -t 0.01

You can type whatever you want while sleep is running. Once it finishes, bash will invoke the read which will slurp in everything sitting on the STDIN buffer.
The -N makes read put the terminal in character mode, instead of line mode. This is because the terminal emulator will normally only send the characters upon pressing Enter. So if characters are entered without pressing Enter, they'll show up at the prompt. The number is how many characters to read. I figure the user won't be able to type 10 million characters by the time the script finishes.
The -t makes it so that read will time out after 0.01 seconds. So if the user cant complete the 10 million characters in 0.01 seconds, read gives up and grabs what has been typed so far.

  • It works great, thanks! Although I downgraded it a thousandth of a second – Micah Jul 24 '14 at 23:13
1

Normally, when you run a command asynchronously (i.e., run it in the background with &) in a non-interactive shell (e.g., a shell script), and you don’t explicitly redirect the command’s standard input, the shell redirects it to /dev/null, so it doesn’t interfere with the foreground.  Of course your problem is that you want the background process to interfere with the foreground, in the sense that you want cat to grab the user’s random typing and prevent the interactive shell from seeing it.

I’m not sure how portable this is, but it seems that you may be able override this behavior of the shell simply by using <&0 to mean “I really want this background process to be connected to the foreground standard input”:

cat <&0 > /dev/null &

I’ve tested this a little more in the past 10 hours, and (in my, still very limited, testing) it always works for bash and sometimes (but not always) works for /bin/sh.  YMMV.

  • No it doesnt. ls -l /proc/self/fd/0 & to see FD0 is still pointed at the TTY. This is why SIGTTIN exists. Also the shell doesn't run in the background. Execution pauses while it waits for the command it ran to finish (unless that command is backgrounded). Thus it won't touch STDIN while another program is running. – Patrick Jul 25 '14 at 3:53
  • (1) I over-generalized. Oops. I’ve fixed my answer. (2) You, also, over-generalized. (3) “Also the shell doesn't run in the background.” I never said that it did. – Scott Jul 25 '14 at 13:53

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.