Josh Sanford
Josh Sanford

Reputation: 672

Read from alternate file descriptor into shell variable

I have a program that prompts the user for a password and derives a key from it, which I later need to pass on stdin to a decryption program. I don't want to store the key in a file at any time, so I am instead looking to pass it in a variable.

The password program needs to display a password prompt, so I can't read from its stdout into a variable without losing the prompt. I know from this that I can capture output from alternate descriptors, and from this that very elaborate redirection and piping is possible, but I'm failing to put it all together.

The password program is mine, so I can make it write to an alternate descriptor of my choice, say 3. The following illustrates what I would like to do, but I know it is incorrect. How can I fix this?

read key < <&3 $(password_program) 
# other operations ...
echo $key | decryption_program -

Upvotes: 2

Views: 1751

Answers (2)

Kai Petzke
Kai Petzke

Reputation: 2934

I think, this should do your trick in bash:

exec 4>&1
key=$(password_program 3>&1 >&4-)
exec 4>&-

It works as follows: The first exec duplicates file descriptor 1 (stdout) as descriptor 4. Then because of the $() syntax, password_program is executed in a subshell, whose stdout will go into the variable key. But we let that subshell do some descriptor mangling, before actually executing password_program: Descriptor 3 is opened as a copy of descriptor 1, so that password_program can write its results to descriptor 3. Then descriptor 4 (our saved "copy" of the original stdout) is moved to descriptor 1. So the result is: password_program will run with its stdout as the same file (or tty etc.), that the shell was started with. The final command then gets rid again of the descriptor 4 in the main shell.

If it is acceptable for you to clone stderr instead of stdout as input to your password_program, you could also do:

key=$(password_program 3>&1 >&2)

Upvotes: 4

rici
rici

Reputation: 241681

If you are writing the password program, the simplest (and usual) solution is to write the prompt to stderr, leaving stdout free. So you can then echo the password to stdout and capture it into a variable.

Alternatively, you could write the prompt and read the password from /dev/tty.

For the simplest solution, if you are using bash and all your password reader does is print a prompt and read a password without echoing it, you could just use IFS= read -srp "prompt: " passwd

Upvotes: 3

Related Questions