10

I'm investigating the behaviour of a script that is normally run as an automated process (e.g. cron, Jenkins). The script can (eventually) invoke commands that behave differently (seeking user input) when run interactively; for example, patch will ask what to do with a reversed patch, and svn will ask for passwords, but I need to see what happens when they're run non-interactively.

Persuading patch that it's non-interactive is fairly easy; I just need to redirect stdout to be a non-tty:

$ </dev/null > >(cat) /path/to/myscript --args

However svn will connect to the controlling terminal if it exists; editing the scripts to pass --non-interactive isn't really an option as this is coming from several levels deep and it'd be difficult to be certain I'd found every invocation.

Is there a way to invoke a script/command non-interactively, without a controlling terminal (so that /dev/tty doesn't exist)? I'd prefer stdout/stderr to still go to my terminal.

(I found the question Run script in a non interactive shell? but the answers to that discuss the differences between the cron and user environment; I've already eliminated all differences except non-interactivity.)

ecatmur
  • 245
  • 2
  • 9

3 Answers3

14

You need to start another session not attached to a terminal, so for instance:

$ setsid sh -c 'tty; ps -jp "$$"; echo test' < /dev/null > log 2>&1
$ cat log
not a tty
  PID  PGID   SID TTY          TIME CMD
19506 19506 19506 ?        00:00:00 sh
test

See also the start-stop-daemon command found on some Linux distributions. There's also a daemon command.

  • 1
    What does this output mean? Looks very cryptic. – anatoly techtonik Mar 19 '17 at 09:35
  • 2
    @anatolytechtonik the important parts are "not a tty" which is the output of tty confirming there is no terminal on stdin, and the "?" in the TTY column of ps output which confirms there is no controlling tty for the sh process (and anything running under it). – mr.spuratic Jan 05 '18 at 11:03
  • To run the command like any other command, use setsid -w. Example: setsid -w sh -c 'tty < /dev/tty' gives sh: 1: cannot open /dev/tty: No such device or address (Note: /dev/tty is your controlling tty). Without -w setsid runs the process in parallel/background. – Tino Aug 11 '19 at 17:19
0

Sometimes you need to keep stdin open (not receive eof on stdin) (e.g. expect). In that case change /dev/null to /dev/zero.

setsid sh -c 'make test' </dev/zero >log 2>&1
Roger
  • 11
0

You'll probably want to do an expect script. Example with SVN:

https://stackoverflow.com/questions/609445/using-expect-to-login-into-svn

Bratchley
  • 16,824
  • 14
  • 67
  • 103
  • That doesn't work; expect runs commands interactively. – ecatmur Mar 20 '13 at 16:39
  • Interactively in what sense? In the sense that it requires input from the user? If that's what you mean, there wouldn't be much point in expect existing in that case. One example I use it for is on Solaris the passwd command doesn't have a --stdin option so I have a cronjob set up that executes an expect script that wraps around passwd to feed it a random password for an account. No human interaction required.

    It's my understanding that this is the user's requirement. I could have misunderstood though.

    – Bratchley Mar 20 '13 at 18:31
  • Actually the more I re-read this, the more I realize I did misunderstand what you were going for. Apologies. – Bratchley Mar 20 '13 at 18:48