Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash command substitution ( $(...) ) forcing process to foreground

Summary: I have a bash script that runs a process in background, and is supposed to work as a normal command and inside a command substitution block such as $(...). The script itself spawns a process that forks to background. It can be reduced to this test case:

#!/bin/sh
echo something
sleep 5 &

Running this script in a shell will return immediately (and print "something"), running it inside $(...) will hang for 5 seconds, waiting for the backgrounded "sleep" to finish.

Applies to anything that is started inside the command substitution shell and spawns processes in background, including any children in that process tree apparently. Seems to affect both bash and zsh, haven't tried others.


Original question: I have a bash script that is supposed to print a value to stdout and also copy it to the X clipboard every time it runs.

#!/bin/sh
echo something
echo something | xclip -selection clipboard

This script (let's call it "something") is meant to be used to get this word (which is actually the output of another command) and be used in different ways such as:

$ something
something
$ xclip -o -selection clipboard
something
$ echo $(something)
^C

Prints to normal stdout, copies the output to the clipboard to be used in normal X applications, and should also be able to use the stdout with bash command substitution, to insert this word in the middle of any command.

However the bash command substitution seems to force xclip to stay alive in foreground. xclip normally daemonizes itself since the X clipboard requires that a client provides the clipboard contents, and the default behavior is to make it quit once the clipboard contents are replaced.

After having this issue with xclip I made the minimal test case that I wrote at the beginning of this question, so it seems to apply that anything that daemonizes inside the $(...) shell

Can anyone explain this behavior? Is there any way I can avoid it?

like image 351
dequis Avatar asked Jun 01 '13 15:06

dequis


People also ask

What is$@ in Bash?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

How does command substitution work?

Command substitution is a mechanism that is followed by programmers in a shell script. In this mechanism, the output of a command replaces the command itself. Shell operates the expansion by executing a command and then replacing the command substitution with the standard output of the command.

What is% 1 in Bash?

If the substring matches more than one job, bash reports an error. The symbols %% and %+ refer to the shell's notion of the current job, which is the last job stopped while it was in the foreground or started in the back- ground. The previous job may be referenced using %-.

What is command substitution in Linux?

Command substitution allows you to capture the output of any command as an argument to another command. When you place a command line within backquotes ( `` ), the shell first runs the command or commands and then replaces the entire expression, including the backquotes, with the output.


1 Answers

If you want the backgrounded process to not interfere with command substitution, you have to disconnect its stdout. This will return immediately:

$ cat bg.sh 
#!/bin/sh
echo before
sleep 5 >/dev/null &
echo after
$ date; x=$(./bg.sh); date; echo "$x"
Sat Jun  1 13:02:26 EDT 2013
Sat Jun  1 13:02:26 EDT 2013
before
after

You will lose the ability to capture the backgrounded process's stdout, but if you're running it in the background you probably don't care. the bg.sh process can always write to disk.

like image 194
glenn jackman Avatar answered Sep 20 '22 08:09

glenn jackman