josh-cain
josh-cain

Reputation: 5226

How can I use "read" to substitute user input inside a bash command substitution?

Was trying to do a quick-and-dirty curl call like so:

curl -u username:$(read -s -p "password: ") https://some.basic.auth.url.com

However, this fails every time. What's more, I attempted to see what's happening with something like:

echo you entered: $(read -p "enter some text: ")

However, the output is simply:

you entered:

I'm clearly missing something essential about the use of this command (or Bash in general). Can someone shed some light on:

  1. Can this sort of thing even work? why?
  2. If so, how could I change this to make it work without going to a script file?

Upvotes: 1

Views: 619

Answers (3)

Christopher Ferrin
Christopher Ferrin

Reputation: 21

I do not see what would be wrong with simply doing a read && echo combo? I was looking to use read command output as a substitution and thus a search lead me here. I quickly figured out something that works for me and I see no reason why it would not work for op. I needed to get a quick output of a bmc sensor using ipmitool reading the sensor indicated by user input. I knew I could not just use read as is but was not sure then realized I could do this:

[root@localhost ~]# printf "%d\n" "0x$(ipmitool raw 0x4 0x2d 0x$(read -p 'id: ' r && echo ${r:-00})|awk '{print $1}')"
id: 
0
[root@localhost ~]# printf "%d\n" "0x$(ipmitool raw 0x4 0x2d 0x$(read -p 'id: ' r && echo ${r:-00})|awk '{print $1}')"
id: 0f
73

note use of ${var:-default*} so that no input defaults 00. output of command we are interested in is the second field which is in hex and needs to be converted.. well I mean it doesn't actually need to be, but to each their own lol. I am no expert in anything but I don't see this breaking anywhere except pure posix maybe.

**raw code for ipmitool are not specific to any platform that I know of. I actually learned them here https://github.com/erik-smit/oohhh-what-does-this-ipmi-doooo-no-deedee-nooooo/blob/master/1-discovering/snippets/Computercheese/IPMI-Sensor%20Device%20Commands.txt and there are many other very useful ones documented not just for ipmitool but various other ipmi interfaces.

Upvotes: 0

agc
agc

Reputation: 8446

The read part can be put in a bash function, with a local variable, which would make the code cleaner:

password(){ local password; read -s -p "password: " password; echo "${password}"; }

Usage:

curl -u username:"$(password)" https://some.basic.auth.url.com

Upvotes: 1

PesaThe
PesaThe

Reputation: 7509

echo "You entered: $(IFS= read -rp "Enter some text: "; printf '%s' "$REPLY")"

From help read:

read ... [name ...]

Reads a single line from the standard input ... The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with any leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters.

If no NAMEs are supplied, the line read is stored in the REPLY variable.

  • IFS= ...: Don't trim leading and trailing spaces
  • -r: Don't mangle backslashes
  • echo "$REPLY": If you don't supply any NAME, the line read is stored in the $REPLY variable. However, read doesn't print it so the command substitution expands to nothing. Consequently, you have to print it explicitly with, for example, printf

Note that if you use read inside $(...), the variable is lost as soon as you leave the substitution. Better approach:

IFS= read -rp "Enter some text: " var
echo "You entered: $var"

Upvotes: 6

Related Questions