Bash – error thrown when using su -c: bash: no job control in this shell

bashsu

I have written a script which should execute certain commands as another user and after execution is finished (success or failure) should logout immediately.

I have read that I can use -c of su to execute commands. So, I wrote a script like:

#!/usr/bin/env bash

su - user2 -c "echo 'hurray' && exit"

It executes the echo command but stays logged in as user2 doesn't logout. I even tried using logout instead of exit but it stays logged in. I need to execute script as user1 which invokes the su command and executes as user2 and then the control should return to user1 after completion.

UPDATE

Alright, I was to able logout automatically but this time some commands are not being executed. For eg:

Command1:

su user2 -c 'echo 1'

Output1:

1

And, then it logs out on its own.

Command2:

su user2 -c 'bash some-script.sh'

Output2:

bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell

So, whenever I try to run some script via -c of su, it displays the above mentioned error. I've tried many commands with -c option such as ls, which, bash --version, mkdir, rm, whoami etc. All these commands produced the correct output. But any command which tries to execute a script, it fails with the error.

su user2 -c 'bash --version'      # Works
su user2 -c 'bash some-script.sh' # Doesn't work

I cannot figure out why this is happening. And, so is the reason I'm unable to fix this error.

Best Answer

The reason for this behaviour is documented in the manual page for recent versions of su:

-c, --command COMMAND

Specify a command that will be invoked by the shell using its -c.

The executed command will have no controlling terminal. This option cannot be used to execute interractive programs which need a controlling TTY.

(emphasis mine)


When you run basic commands such as ls, echo or bash --version, they simply print their output to the stdout stream without without needing a controlling terminal.

I suspect that either the way bash is being invoked (as an interactive shell) or some-script.sh contains commands which require a controlling terminal device so running 'bash some-script.sh' throws the cannot set terminal process group (-1): Inappropriate ioctl for device error.

Some explanation

A controlling terminal for a process is the terminal device from which the process was started. A controlling terminal can send signals to groups of process and is the mechanism by which job control works in Unix operating systems; job control allows processes in the process group to be run in foreground or the background.

The output of the ps command shows the controlling terminal for each process, e.g.,

$ ps

  PID TTY          TIME CMD
 3614 pts/5    00:00:00 bash
31628 pts/5    00:00:00 ps

Recent change in su

In the past, su -c did start a controlling terminal when not running an interactive shell. Running apt-get changelog login on my Ubuntu system shows that the removal of the controlling terminal was introduced in May 2012 as a security measure:

  • su: Fix possible tty hijacking by dropping the controlling terminal when executing a command (CVE-2005-4890). Closes: #628843