Python without a tty

S

Steven D'Aprano

I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I am running Linux.
 
T

Thomas Jollans

I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I am running Linux.

../program </dev/null >/dev/null 2>&1
 
A

Alain Ketterlin

Steven D'Aprano said:
I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I am running Linux.

Isn't os.setsid() what you're looking for? It makes the calling process
have no controlling terminal. There's also a user command called setsid
that should have the same effect.

-- Alain.
 
S

Steven D'Aprano

Alain said:
Isn't os.setsid() what you're looking for? It makes the calling process
have no controlling terminal. There's also a user command called setsid
that should have the same effect.

It doesn't appear so to me.

[steve@sylar ~]$ tty
/dev/pts/16
[steve@sylar ~]$ setsid tty
/dev/pts/16

[steve@sylar ~]$ python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True
[steve@sylar ~]$ setsid python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True


If I run the same Python command (without the setsid) as a cron job, I
get False emailed to me. That's the effect I'm looking for.
 
H

Hans Mulder

I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

There is module on Pypi called python-daemon; it implements PEP-3143.
This module detaches the process from the tty and resets a number of
process attributes that are normally inherited.

You could start by reading the PEP to determine which of its features
are relevant to your situation. It would provide you with a complete
list of aspects you'd need to think about.

If a third of what the module does is relevant to your situation and
the other two thirds do not hurt, then using the module is likely to
be less work than rolling your own.

Hope this helps,

-- HansM
 
A

Alain Ketterlin

Steven D'Aprano said:
Alain Ketterlin wrote:
I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?
Isn't os.setsid() what you're looking for?[...]
It doesn't appear so to me. [...]
[steve@sylar ~]$ python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True
[steve@sylar ~]$ setsid python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True

If I run the same Python command (without the setsid) as a cron job, I
get False emailed to me. That's the effect I'm looking for.

If that's what you mean by "without a tty attached", simply redirecting
standard channels should work, no?

-- Alain.
 
H

Hans Mulder

[steve@sylar ~]$ python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True

If I run the same Python command (without the setsid) as a cron job, I
get False emailed to me. That's the effect I'm looking for.

In that case, all you need to do is redirect stdout:

$ python -c "import sys, os
print os.isatty(sys.stdout.fileno())" >/tmp/xxx
$ cat /tmp/xxx
False

You'll probably want to redirect to /dev/null and
maybe you want to redirect stdin and stderr as well.

-- HansM
 
R

Roy Smith

Steven D'Aprano said:
I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I'm not sure what you mean by "without a tty attached to the process".
If you mean no file descriptors attached to your control terminal, then
some variation on

foo.py < /dev/null > /dev/null

(as others has suggested) might be good enough. Or, are you talking
about control terminals in the process control sense? In that case, you
might want to look at the "at" or "batch" commands, which do very much
the same thing as cron, but without the overhead of having to edit the
cron file to get things going.
 
M

Martin P. Hellwig

I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I am running Linux.
Well you could double fork and drop the parent, that would lose the tty
which is the same effect what you get when you want a daemon.
 
R

ron

I have a Python script which I would like to test without a tty attached
to the process. I could run it as a cron job, but is there an easier way?

I am running Linux.

Have you tried GNU Screen? It let's you run processes under virtual
terminals, which can then be backgrounded, reconnected to, etc. I
think it comes with most linux distros.
 
R

RJB

Isn't os.setsid() what you're looking for? It makes the calling process
have no controlling terminal. There's also a user command called setsid
that should have the same effect.

It doesn't appear so to me.

[steve@sylar ~]$ tty
/dev/pts/16
[steve@sylar ~]$ setsid tty
/dev/pts/16

[steve@sylar ~]$ python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True
[steve@sylar ~]$ setsid python -c "import sys,os; print os.isatty(sys.stdout.fileno())"
True

If I run the same Python command (without the setsid) as a cron job, I
get False emailed to me. That's the effect I'm looking for.

You could try the old UNIX "nohup ... &" technique for running a
process in the background (the &) with no HangUP if you log out:

$ nohup python -c "import sys,os; print
os.isatty(sys.stdout.fileno())" &
appending output to nohup.out
$ cat nohup.out
False

But that is over kill I guess.

One worrying detail.... the definition of a running process in UNIX
implies is that it has standard input/output files open.
You'd be wise to make sure that they are connected to things that are
safe.... /dev/null.

Even so /dev/tty can be opened any way...

Hope this helps.
 
N

Nobody

Isn't os.setsid() what you're looking for? It makes the calling process
have no controlling terminal. There's also a user command called setsid
that should have the same effect.

setsid() requires that the calling process isn't a process group
leader; this can be achieved by fork()ing. The setsid command does this
automatically.

As you say, this ensures that the process has no controlling terminal
(i.e. it won't get signals from the tty driver for ^C, ^Z, hangup, etc).
It won't detach stdin etc from a terminal. Also, open()ing a tty will
result in it becoming the controlling terminal unless O_NOCTTY is used.

I suspect that the OP just wants e.g.:

script.py &>/dev/null <&-

which will redirect stdout and stderr to /dev/null and close stdin.
 
H

Hans Mulder

You could try the old UNIX "nohup ...&" technique for running a
process in the background (the&) with no HangUP if you log out:

$ nohup python -c "import sys,os; print
os.isatty(sys.stdout.fileno())"&
appending output to nohup.out
$ cat nohup.out
False

But that is over kill I guess.

One worrying detail.... the definition of a running process in
UNIX implies is that it has standard input/output files open.
You'd be wise to make sure that they are connected to things
that are safe.... /dev/null.

Even so /dev/tty can be opened any way...

Not if you really detach from your tty: after you've detached,
there is no tty for /dev/tty to connect to and any attempt to
open it will raise IOError.

-- HansM
 
S

Steven D'Aprano

[...]
I suspect that the OP just wants e.g.:

script.py &>/dev/null <&-

which will redirect stdout and stderr to /dev/null and close stdin.


No, that's not what I wanted.

I ended up just running the script as a cron job. It was a one-off (well,
twice actually, since the first time demonstrated a bug in my code) test
of some code that tries to determine the size of the current terminal. I
wanted to ensure that it would do the right thing when run without a tty,
such as from a cron job.

Thanks to everyone who replied.
 
H

Hans Mulder

I have a Python script which I would like to test without a tty
attached to the process. I could run it as a cron job, but is there an
easier way?
[...]
I suspect that the OP just wants e.g.:

script.py&>/dev/null<&-

which will redirect stdout and stderr to /dev/null and close stdin.


No, that's not what I wanted.

I ended up just running the script as a cron job. It was a one-off (well,
twice actually, since the first time demonstrated a bug in my code) test
of some code that tries to determine the size of the current terminal. I
wanted to ensure that it would do the right thing when run without a tty,
such as from a cron job.

In that case, the "at" command would have been the answer.
It is a bit like cron, but meant for one-off jobs.

You might have received more useful answers if you'd
mentioned you goals earlier.

-- HansM
 
H

Hegedüs, Ervin

hello,

I wanted to ensure that it would do the right thing when run without a tty,
such as from a cron job.

If you fork() your process, then it will also loose the tty...


import os
import sys


try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, e:
sys.exit(1)

os.chdir("/")
os.setsid()
os.umask(0)




a.
 
H

Hans Mulder

hello,



If you fork() your process, then it will also loose the tty...

Errhm, I suggest you check again. This cannot be true.
import os
import sys


try:
pid = os.fork()
if pid> 0:
sys.exit(0)
except OSError, e:
sys.exit(1)

os.chdir("/")
os.setsid()
os.umask(0)

It is os.setsid() that makes you lose the tty.


Hope this helps,

-- HansM
 
H

Hegedüs, Ervin

hello,

Errhm, I suggest you check again. This cannot be true.


It is os.setsid() that makes you lose the tty.

well, thank you, I confused Python fork() and glibc daemon() - as
I know that detach the terminal - I'm really sorry.


a.
 
G

Gregory Ewing

Hegedüs said:
If you fork() your process, then it will also loose the tty...

Um, no, fork() doesn't do that, as far as I know.
os.setsid()

*This* is what's losing the tty. According to the Fine Man Page:

DESCRIPTION
The setsid function creates a new session. The calling process is the
session leader of the new session, is the process group leader of a new
process group and has no controlling terminal.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
N

Nobody

*This* is what's losing the tty. According to the Fine Man Page:

DESCRIPTION
The setsid function creates a new session. The calling process is the
session leader of the new session, is the process group leader of a new
process group and has no controlling terminal.
^^^^^^^^^^^^^^^^^^^^^^^^^^^

The above description is incomplete. This version has more detail:

DESCRIPTION
setsid() creates a new session if the calling process is not a process
group leader. The calling process is the leader of the new session,
the process group leader of the new process group, and has no control-
ling tty. The process group ID and session ID of the calling process
are set to the PID of the calling process. The calling process will be
the only process in this new process group and in this new session.

The key point is "... if the calling process is not a process group leader".

The easiest way to achieve this condition is to fork(). This ensures that
the child process won't be a process group leader unless it explicitly
makes itself one with setpgid() or setpgrp().

A process launched from a shell typically /will/ be a process group leader
unless it's part of a pipeline (the shell creates a new process group for
each pipeline; one of the processes in that group will be its leader).

setsid() will fail with EPERM if the calling process is a process group
leader.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,089
Latest member
Ketologenic

Latest Threads

Top