Let's say I defined this function in the script:

fct1() {
  local msg1=${@}
if [[ "${verb}" = 'tru' ]]; then
  echo "I say $msg1"
  sleep 1
  echo "i repeat"
  sleep 1
  echo "I saaaaaaaaay $msg1"
  echo "$msg1"

How would I go about making a user call this function from read ?

I'm thinking something like

read fct1 "aha aha ahaaaaa"

And the output would be:

"I say aha aha ahaaaaa" "I repeat" "I saaaaaaaaay aha aha ahaaaaa"

Basically, how do I use the input on read and not store it in a variable, but use it as a command?



If you wanted the message do be read as one line from stdin (entered by the user when the script is used in a terminal) and then passed as argument to the function, you could do:

fct1 "$(line)"

line is no longer a standard command but still fairly widespread. You could replace it with head -n1, but with some implementations, it could read more than one line (though it outputs only one) when the input is not coming from a terminal device.

With bash's read you would have to store it in a variable. That's what read is for, store input in a variable.

IFS= read -r line && fct1 "$line"

With zsh's read, you can use the -e option which echoes the read data instead of storing it in a variable, so line above can be written there as IFS= read -re:

fct1 "$(IFS= read -re)"

(that's less efficient than using read with a variable as we need to fork a process so zsh can read read's output).

Of course, you could also replace your:

local msg1=${@}


local msg1; IFS= read -r msg1 || return
  • So if I would do something like define function readfct() {;${x};} and then read x;readfct, it would execute whatever is in x as an actual command? – iamAguest Aug 23 '18 at 9:07
  • @iamAguest, yes. ${x} or ${x} applies split+glob on the expansion of $x, the first word resulting of that is taken as a command name (builtin, function or external; not keyword nor alias) and the list of words passed to that command. You'd use "$x" for the content to be one command with no argument, and eval "$x" for the content of $x to be taken as shell code to evaluate. – Stéphane Chazelas Aug 23 '18 at 9:13

The read utility does not allow using callbacks (I'm not sure any common Unix tools does).It furthermore does not output the data that's is read.

What you would have to do is to wrap the read call in a function that takes what the user is providing and outputs it back as you describe. Alternatively, use some other tool to read the input and produce the wanted output, like awk.

Also, in general, using variable=$@ is not well defined. If you want the command line arguments as a list of space-delimited values, use variable="$*" instead (assuming the default value of the IFS variable).

  • "$*" is only space separated if $IFS starts with space (as it is by default) or is unset. – Stéphane Chazelas Aug 23 '18 at 8:24
  • awk and most text utilities would read more than one line of input though when the input is not a terminal nor a regular file (for regular files, they still read more, but some seek back to appear as if they'd read only one line). You could use the line utility (no longer standard though) which reads one character at a time to avoid reading more than one line. – Stéphane Chazelas Aug 23 '18 at 8:26
  • While bash's read doesn't echo back what it reads (except with -e on stderr when stdin is a terminal), but zsh's one does with -e or -E (for echo, not edit like with bash). So zsh's IFS= read -re works like line. – Stéphane Chazelas Aug 23 '18 at 8:28

This is a quite unusual request ... hmmm ... in order to get some input from the terminal into the positional parameter list of that function, try

fct1 "$(cat)"
I say dfergerg
i repeat
I saaaaaaaaay dfergerg

That will keep catting until you enter a EOF (CTRL-D) character. Make sure the vert variable is set to tru outside the function.

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.