Håkon Hægland
Håkon Hægland

Reputation: 40778

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:

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

Upvotes: 5

Views: 1439

Answers (3)

Ben Ernest
Ben Ernest

Reputation: 498

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 (e.g., 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

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74695

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

Upvotes: 6

Sobrique
Sobrique

Reputation: 53508

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.

Upvotes: 1

Related Questions