Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how does `shopt -s lastpipe` affect bash script behavior?

Tags:

bash

shell

I am trying to make ffcast screen casting tool bash 4.1 backwards compatible.

and in this ffcast.bash script, there is oneline

shopt -s extglob lastpipe

lastpipe option is only available after bash 4.3, what can I do to emulate its effect?

like image 820
Shuman Avatar asked Mar 31 '16 18:03

Shuman


People also ask

Why do bash scripts start with #!?

The #! line in a shell script will be the first thing the command interpreter (sh or bash) sees. Since this line begins with a #, it will be correctly interpreted as a comment when the command interpreter finally executes the script. The line has already served its purpose - calling the command interpreter.

How does pipeline work bash?

A pipe in Bash takes the standard output of one process and passes it as standard input into another process. Bash scripts support positional arguments that can be passed in at the command line. Guiding principle #1: Commands executed in Bash receive their standard input from the process that starts them.

What is $() in bash?

$( command ) or. ` command ` Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting.

How does bash interpreter work?

Bash reads input from the terminal when interactive, and from the script file specified as an argument otherwise. When interactive, bash allows the user to edit command lines as they are typed in, using familiar key sequences and editing commands similar to the Unix emacs and vi editors.


2 Answers

lastpipe (introduced in bash 4.2, by the way) can only be simulated by not using a pipe. You need to explicitly run the last command of the pipe line in the current shell, and redirect its input from either a process substitution

# foo | bar | baz becomes ...
baz < <(foo | bar)

or a named pipe (which is POSIX-compliant as well)

# foo | bar | baz becomes ...
mkfifo baz_input
foo | bar > baz_input &
baz < baz_input
like image 105
chepner Avatar answered Oct 15 '22 14:10

chepner


Usual behavior without lastpipe and with job control enabled is to run each element of the pipeline in a sub-shell.

echo asd | var=$(cat) ; echo $var

var contains nothing, but user may expect that var will contain asd. That is because last pipeline element sets var in a sub-shell which has no access to current shell's environment.

From man bash:

Each command in a pipeline is executed as a separate process (i.e., in a subshell). See COMMAND EXECUTION ENVIRONMENT for a description of a subshell environment. If the lastpipe option is enabled using the shopt builtin (see the description of shopt below), the last element of a pipeline may be run by the shell process.

I don't know what is may be... Here is better description:

lastpipe
If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.

So

set +m  # To disable job control
shopt -s lastpipe
echo asd | var=$(cat)
echo $var

and now var contains asd.

Thanks @chepner.


Earlier I used to write like:

{ while read;do var="$REPLY";done; } < <(command | filter)

in cases when

var=$(command | filter)

is not suitable.

like image 38
kyb Avatar answered Oct 15 '22 12:10

kyb