Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash: Assign variable from pipe?

Tags:

bash

In bash, what's the most efficient way to assign a variable using piped input -- using only left to right syntax? Suppose the left side of the pipe is seq 3, so we'd want:

seq 3 | x=<put some code here>

NB: Not an answer, although probably functionally equivalent:

x=`seq 3`

...because seq 3 is not on the left side of a pipe.

For this Q, please ignore the possibility of exceeding the variable's memory, which pipes could certainly do.

like image 529
agc Avatar asked Mar 22 '17 21:03

agc


2 Answers

To complement Charles Duffy's helpful answer with a focus on making it work in bash:

By default, and on Bash v4.1- invariably, any variable creations / modifications in a (multi-segment) pipeline happen in a subshell, so that the result will not be visible to the calling shell.

In Bash v4.2+, you can set option lastpipe to make the last pipeline segment run in the current shell, so that variable creations/modifications made there are visible to it.

For that to work in an interactive shell, you must additionally turn off job control with set +m.

Here's a complete example (Bash v4.2+):

$ unset x; shopt -s lastpipe; set +m; seq 3 | x=$(cat); echo "$x"
1
2
3

That said,

x=$(seq 3)

(the modern equivalent of your x=`seq 3`) is much simpler - it is POSIX-compliant and therefore works on older Bash versions too, and it requires no fiddling with global options.

like image 126
mklement0 Avatar answered Oct 16 '22 10:10

mklement0


This is covered in detail in BashFAQ #24.

You can reliably use a variable collected on the right-hand side of a pipeline only if the code referencing it is also on the right-hand side of that pipeline.

#!/bin/bash
echo "hello" | { read -r var; echo "Read value: $var"; }
echo "After the pipeline exited, var contains: $var"

Typical output is:

Read value: hello
After the pipeline exited, var contains:

The POSIX sh specification neither requires nor precludes the right-hand side of a pipeline being executed in the same shell which later executes subsequent commands. Thus, a shell may execute the read on the second line in the same shell where it executes the echo on the third -- but bash, specifically, will not do so unless the lastpipe shell option is enabled.

like image 45
Charles Duffy Avatar answered Oct 16 '22 09:10

Charles Duffy