简体   繁体   中英

Running system command under interactive bash shell

I am trying to run a command that has been aliased in my ~/.bashrc from Perl using the system command. It works well running the command only once, but when I run it twice the second invocation is run as a background job and then suspended (the same as pressing <CTRL-Z> ) and I have to type fg to complete the command. For example

use strict;
use warnings;

system ('bash -ic "my_cmd"');
system ('bash -ic "my_cmd"');

The second call never completes. The output is [1]+ Stopped a.pl .

Note:

  • The same result is obtained when replacing my_cmd with any other command, for example ls .
  • It seems not to depend of the contents of my ~/.bashrc file. I tried to remove everything from it, and the problem still persisted.

I am using Ubuntu 14.04 and Perl version 5.18.2.

Update

For debugging I reduced my ~/.bashrc to

echo "Entering ~/.bashrc .."
alias my_cmd="ls"
alias

and my ~/.bash_profile to

if [ -f ~/.bashrc ]; then
    echo "Entering ~/.bash_profile .."
    . ~/.bashrc
fi

Now running:

system ('bash -lc "my_cmd"');
system ('bash -lc "my_cmd"');

gives

Entering ~/.bash_profile ..
Entering ~/.bashrc ..
alias my_cmd='ls'
bash: my_cmd: command not found
Entering ~/.bash_profile ..
Entering ~/.bashrc ..
alias my_cmd='ls'
bash: my_cmd: command not found

and running

system ('bash -ic "my_cmd"');
system ('bash -ic "my_cmd"');

gives

Entering ~/.bashrc ..
alias my_cmd='ls'
a.pl  p.sh

[1]+  Stopped                 a.pl

Rather than using the -i switch for an interactive shell, I think you should use the -l (or --login ) switch, which causes bash to act as if it had been invoked as a login shell.

Using the -l switch doesn't load ~/.bashrc by default. According to man bash , in a login shell, /etc/profile/ is loaded, followed by the first file found from ~/.bash_profile/ , ~/.bash_login or ~/.profile/ . On my system, I have the following in ~/.bash_profile , so ~/.bashrc is loaded:

# Source .bashrc
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

Now that your ~/.bashrc is being loaded, you need to enable the expansion of aliases, which is off in a non-interactive shell. To do this, you can add the following line before setting your aliases:

shopt -s expand_aliases

A process randomly stopping - aside from ctrl-z is usually when it needs STDIN, but doesn't have it attached.

Try it with - for example passwd & . It'll background and go straight into 'stopped' state. This may well be what's happening with your bash command. -i means interactive shell, explicitly, and you're trying to do something noninteractive with it.

That's almost certainly not the best approach, you probably want to do something different. bash --login might be closer to what you're after.

Tom Fenech's answer worked for me in Ubuntu 16.04.1 LTS with a small addition. At the top of my ~/.bashrc file, I commented out the following section so that if the shell is not interactive (eg, a login shell), ~/.bashrc is still read. On some other versions of Linux I don't see this section.

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM