How do I redirect output to a variable in shell?
Use the $( ... )
construct:
hash=$(genhash --use-ssl -s $IP -p 443 --url $URL | grep MD5 | grep -c $MD5)
bash exec sending output to a pipe, how?
When a command contains a pipeline, each subcommand is run in a subshell. So the shell first forks a subshell for each part of the pipeline, and then the subshell for the first part executes exec
with no arguments, which does nothing and exits.
exec
with redirection and no command is treated as a special case. From the documentation:
If command is not specified, any redirections take effect in the
current shell, and the return status is 0.
Bash: execute content of variable including pipe
Using eval
is not recommended here. It can lead to unexpected results, especially when variables can be read from untrusted sources (See BashFAQ/048 - Eval command and security issues.
You can solve this in a simple way by defining and calling a function as below
ps_cmd() {
ps aux | grep -v grep
}
and use it in the script as
output="$(ps_cmd)"
echo "$output"
Also a good read would be to see why storing commands in a variable is not a good idea and has a lot of potential pitfalls - BashFAQ/050 - I'm trying to put a command in a variable, but the complex cases always fail!
Send string to stdin
You can use one-line heredoc
cat <<< "This is coming from the stdin"
the above is the same as
cat <<EOF
This is coming from the stdin
EOF
or you can redirect output from a command, like
diff <(ls /bin) <(ls /usr/bin)
or you can read as
while read line
do
echo =$line=
done < some_file
or simply
echo something | read param
Pipe a command and redirect the output with command
This is a simplified version of how you would achieve this:
outfile, _ := os.OpenFile("backup.gz", os.O_RDWR|os.O_CREATE, 0755)
// your zfs command
zfs := exec.Command("zfs", "send", "storedb@backup")
gzip := exec.Command("gzip", "-cf") // gzip to stdout (-cf)
gzip.Stdin, _ = zfs.StdoutPipe() // zfs stdout to gzip stdin
gzip.Stdout = outfile // write output of gzip to outfile
gzip.Start() // gzip start waiting for input
zfs.Run() // zfs start command
gzip.Wait() // gzip wait for pipe to close
outfile.Close()
It is equivalent to this command in the shell:
zfs send stored@backup | gzip -cf > backup.gz
Piping and Redirection
Redirection is (mostly) for files (you redirect streams to/from files).
Piping is for processes: you pipe (redirect) streams from one process to another.
Essentially what you really do is "connect" one standard stream (usually stdout
) of one process to standard stream of another process (usually stdin
) via pipe.
Pipes have also the synchronization "side effect" : they block one process (on reading) when the other has nothing to write (yet) or when reading process cannot read fast enough (when the pipe's buffer is full).
How to redirect output of command to a file and in parallel pipe to other command?
You can use tee
ls | tee output.txt | wc -l
Pipe Bash command output to stdout and to a variable
Copying To A TTY (Not Stdout!)
Pipeline components run in subshells, so even if they do assign shell variables (and the syntax for that was wrong), those shell variables are unset as soon as the pipeline exits (since the subshells only live as long as the pipeline does).
Thus, you need to capture the output of the entire pipeline into your variable:
var=$(find "$filename" -perm "$i" | tee /dev/tty | wc -l)
Personally, btw, I'd be tee
ing to /dev/stderr
or /dev/fd/2
to avoid making behavior dependent on whether a TTY is available.
Actually Piping To Stdout
With bash 4.1, automatic file descriptor allocation lets you do the following:
exec {stdout_copy}>&1 # make the FD named in "$stdout_copy" a copy of FD 1
# tee over to "/dev/fd/$stdout_copy"
var=$(find "$filename" -perm "$i" | tee /dev/fd/"$stdout_copy" | wc -l)
exec {stdout_copy}>&- # close that copy previously created
echo "Captured value of var: $var"
With an older version of bash, you'd need to allocate a FD yourself -- in the below example, I'm choosing file descriptor number 3 (as 0, 1 and 2 are reserved for stdin, stdout and stderr, respectively):
exec 3>&1 # make copy of stdout
# tee to that copy with FD 1 going to wc in the pipe
var=$(find "$filename" -perm "$i" | tee /dev/fd/3 | wc -l)
exec 3>&- # close copy of stdout
Related Topics
How to Merge Two Rows in a Same Row from a Text File in Linux Shell Script
How to to Delete a Line Given with a Variable in Sed
Add Month to a Variable Date in Shell Script
Shell Script Issue with Filenames Containing Spaces
What Is Segment 00 in My Linux Executable Program (64 Bits)
How to Increase Openfabrics Memory Limit for Torque Jobs
Nginx Location Deny by File Extension Syntax
Docker in Wsl2 Alpine Without Docker Desktop
Delete Repeated Characters Without Back-Referencing with Sed
Write Failing Without Error on Qspi (Spansion S25Hs512T) - U-Boot
Safely Remembering Ssh Credentials in Bash Script
Linux Script- Date Manipulations
Displaying or Redirecting a Shell's Job Control Messages
Multiple -A with Greater Than/Less Than Break Bash Script
Sed: Find Pattern Over Two Lines, Not Replace After That Pattern
How to Read Input from the Terminal Using /Dev/Stdin and Read.Csv()
Gnuplot Doesn't Work Through Ssh Command
Docker-Compose Stop Working After Docker Desktop Installation on Debian 11