[bash] How do I redirect output to a variable in shell?

I have a script like that

genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5

I want to get stream generated by genhash in a variable. How do I redirect it into a variable $hash to compare inside a conditional?

if [ $hash -ne 0 ]
  then echo KO
  exit 0
else echo -n OK
  exit 0
fi

This question is related to bash shell

The answer is


I got error sometimes when using $(`code`) constructor.

Finally i got some approach to that here: https://stackoverflow.com/a/7902174/2480481

Basically, using Tee to read again the ouput and putting it into a variable. Theres how you see the normal output then read it from the ouput.

is not? I guess your current task genhash will output just that, a single string hash so might work for you.

Im so neewbie and still looking for full output & save into 1 command. Regards.


read hash < <(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)

This technique uses Bash's "process substitution" not to be confused with "command substitution".

Here are a few good references:


I guess compatible way:

hash=`genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5`

but I prefer

hash="$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)"

Create a function calling it as the command you want to invoke. In this case, I need to use the ruok command.

Then, call the function and assign its result into a variable. In this case, I am assigning the result to the variable health.

function ruok {
  echo ruok | nc *ip* 2181
}

health=echo ruok *ip*

If a pipeline is too complicated to wrap in $(...), consider writing a function. Any local variables available at the time of definition will be accessible.

function getHash {
  genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5
}
hash=$(getHash)

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Functions


TL;DR

To store "abc" into $foo:

echo "abc" | read foo

But, because pipes create forks, you have to use $foo before the pipe ends, so...

echo "abc" | ( read foo; date +"I received $foo on %D"; )

Sure, all these other answers show ways to not do what the OP asked, but that really screws up the rest of us who searched for the OP's question.

The answer to the question is to use the read command.

Here's how you do it

# I would usually do this on one line, but for readability...
series | of | commands \
| \
(
  read string;
  mystic_command --opt "$string" /path/to/file
) \
| \
handle_mystified_file

Here is what it is doing and why it is important:

  1. Let's pretend that the series | of | commands is a very complicated series of piped commands.

  2. mystic_command can accept the content of a file as stdin in lieu of a file path, but not the --opt arg therefore it must come in as a variable. The command outputs the modified content and would commonly be redirected into a file or piped to another command. (E.g. sed, awk, perl, etc.)

  3. read takes stdin and places it into the variable $string

  4. Putting the read and the mystic_command into a "sub shell" via parenthesis is not necessary but makes it flow like a continuous pipe as if the 2 commands where in a separate script file.

There is always an alternative, and in this case the alternative is ugly and unreadable compared to my example above.

# my example above as a oneliner
series | of | commands | (read string; mystic_command --opt "$string" /path/to/file) | handle_mystified_file

# ugly and unreadable alternative
mystic_command --opt "$(series | of | commands)" /path/to/file | handle_mystified_file

My way is entirely chronological and logical. The alternative starts with the 4th command and shoves commands 1, 2, and 3 into command substitution.

I have a real world example of this in this script but I didn't use it as the example above because it has some other crazy/confusing/distracting bash magic going on also.


You can do:

hash=$(genhash --use-ssl -s $IP -p 443 --url $URL)

or

hash=`genhash --use-ssl -s $IP -p 443 --url $URL`

If you want to result of the entire pipe to be assigned to the variable, you can use the entire pipeline in the above assignments.