Skip to main content
workaround for older bash
Source Link
user313992
user313992

Here the CHLD trap has to be disabled and then reenabled, otherwise the $(jobs -p) command substitution will trigger it recursively.


This whole thing could be made into a standalone script instead of a function:

This whole thing could be made into a standalone script instead of a function:

Here the CHLD trap has to be disabled and then reenabled, otherwise the $(jobs -p) command substitution will trigger it recursively.


This whole thing could be made into a standalone script instead of a function:

workaround for older bash
Source Link
user313992
user313992

In older version of bash which do not support the ${var@P} expansion form, a clunkier kludge will have to be used:

set -- 'sigchld(){ trap - CHLD; test "$(jobs -p)" || exit; trap sigchld CHLD; }; trap sigchld CHLD;' "$@" 

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@"   # this only works in bash >= 4.4 # set -- 'sigchld(){ local j="\j"; ((${j@P})) || exit; }; trap sigchld CHLD;' "$@" set -- 'sigchld(){ trap - CHLD; test "$(jobs -p)" || exit; trap sigchld CHLD; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@" set -- 'sigchld(){ local j="\j"; ((${j@P})) || exit; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 

In older version of bash which do not support the ${var@P} expansion form, a clunkier kludge will have to be used:

set -- 'sigchld(){ trap - CHLD; test "$(jobs -p)" || exit; trap sigchld CHLD; }; trap sigchld CHLD;' "$@" 

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@"   # this only works in bash >= 4.4 # set -- 'sigchld(){ local j="\j"; ((${j@P})) || exit; }; trap sigchld CHLD;' "$@" set -- 'sigchld(){ trap - CHLD; test "$(jobs -p)" || exit; trap sigchld CHLD; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 
added 84 characters in body
Source Link
user313992
user313992
bash_in_gnome_terminal(){ local IFS printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } bash_in_gnome_terminal tail -f ~/.xsession-errors bash_in_gnome_terminal 'grep -r pattern dir | less' 

This solution is complicated (and crippled!) by the fact that the gnome-terminal command actually calls into a "terminal server" to spawn a terminal instance, and you cannot pass file descriptors to the process running in it.

With other terminals like xterm or mlterm the solution is simpler and more functional:

bash_in_xterm(){ local IFS xterm -e bash --rcfile <(printf '. ~/.bashrc; set -m; %s\n' "$*") } 

Also, it would be nice if bash had an option to run some commands before an interactive shell (like vi +'cmd'), without a kludge like --rcfile <(...). Maybe it even has -- but I wasn't able to figure it out ;-)

The set -m is needed because bash sources the initialization files with the monitor mode off, ie without job control and the possibility of using ^Z, fg, bg, etc.


If you want the shell to exit and the terminal to close when the started command has exited, the function could be modified like this [assumes a recent version of bash]:

bash_in_gnome_terminal(){ local IFS set -- 'j="\j";'sigchld(){ traplocal "j="\j"; ((\$${j@P})) || exit"exit; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } 

The ${var@P} form expands any prompt escapes in var, and the \j prompt escape expands to the number of jobs. Thence j="\j"; ((${jc@Pj@P})) || exit as called from the CHLD trap will exit the shell if there are no more jobs.

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@" set -- 'j="\j";'sigchld(){ traplocal "j="\j"; ((\$${j@P})) || exit"exit; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 
bash_in_gnome_terminal(){ local IFS printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } bash_in_gnome_terminal tail -f ~/.xsession-errors bash_in_gnome_terminal 'grep -r pattern dir | less' 

This solution is complicated (and crippled!) by the fact that the gnome-terminal command actually calls into a "terminal server" to spawn a terminal instance, and you cannot pass file descriptors to the process running in it.

With other terminals like xterm or mlterm the solution is simpler and more functional:

bash_in_xterm(){ local IFS xterm -e bash --rcfile <(printf '. ~/.bashrc; set -m; %s\n' "$*") } 

Also, it would be nice if bash had an option to run some commands before an interactive shell (like vi +'cmd'), without a kludge like --rcfile <(...). Maybe it even has -- but I wasn't able to figure it out ;-)

The set -m is needed because bash sources the initialization files with the monitor mode off, ie without job control and the possibility of using ^Z, fg, bg, etc.


If you want the shell to exit and the terminal to close when the started command has exited, the function could be modified like this [assumes a recent version of bash]:

bash_in_gnome_terminal(){ local IFS set -- 'j="\j"; trap "((\${j@P})) || exit" CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } 

The ${var@P} form expands any prompt escapes in var, and the \j prompt escape expands to the number of jobs. Thence ((${jc@P})) || exit as called from the CHLD trap will exit the shell if there are no more jobs.

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@" set -- 'j="\j"; trap "((\${j@P})) || exit" CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 
bash_in_gnome_terminal(){ local IFS printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } bash_in_gnome_terminal tail -f ~/.xsession-errors bash_in_gnome_terminal 'grep -r pattern dir | less' 

This solution is complicated (and crippled!) by the fact that the gnome-terminal command actually calls into a "terminal server" to spawn a terminal instance, and you cannot pass file descriptors to the process running in it.

With other terminals like xterm or mlterm the solution is simpler and more functional:

bash_in_xterm(){ local IFS xterm -e bash --rcfile <(printf '. ~/.bashrc; set -m; %s\n' "$*") } 

Also, it would be nice if bash had an option to run some commands before an interactive shell (like vi +'cmd'), without a kludge like --rcfile <(...). Maybe it even has -- but I wasn't able to figure it out ;-)

The set -m is needed because bash sources the initialization files with the monitor mode off, ie without job control and the possibility of using ^Z, fg, bg, etc.


If you want the shell to exit and the terminal to close when the started command has exited, the function could be modified like this [assumes a recent version of bash]:

bash_in_gnome_terminal(){ local IFS set -- 'sigchld(){ local j="\j"; ((${j@P})) || exit; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" } 

The ${var@P} form expands any prompt escapes in var, and the \j prompt escape expands to the number of jobs. Thence j="\j"; ((${j@P})) || exit as called from the CHLD trap will exit the shell if there are no more jobs.

This whole thing could be made into a standalone script instead of a function:

#! /bin/bash # uncomment and edit the following line accordingly # set -- <fixed command and arguments> "$@" set -- 'sigchld(){ local j="\j"; ((${j@P})) || exit; }; trap sigchld CHLD;' "$@" printf -v cmd %q ". ~/.bashrc; set -m; $*" gnome-terminal -- bash -c "bash --rcfile <(echo $cmd)" 
edited body
Source Link
user313992
user313992
Loading
deleted 1 character in body
Source Link
user313992
user313992
Loading
added 13 characters in body
Source Link
user313992
user313992
Loading
added 594 characters in body
Source Link
user313992
user313992
Loading
added 594 characters in body
Source Link
user313992
user313992
Loading
simplify
Source Link
user313992
user313992
Loading
added 53 characters in body
Source Link
user313992
user313992
Loading
simplify
Source Link
user313992
user313992
Loading
xterm solution
Source Link
user313992
user313992
Loading
use printf -v %q instead of ${var@Q} which is only supported in newer versions of bash
Source Link
user313992
user313992
Loading
use printf -v %q instead of ${var@Q} which is only supported in newer versions of bash
Source Link
user313992
user313992
Loading
Source Link
user313992
user313992
Loading