Interactive scripts (back on topic for once) [was Re: The "loop and a half"]
Chris Angelico
rosuav at gmail.com
Fri Oct 6 14:25:05 EDT 2017
On Sat, Oct 7, 2017 at 4:54 AM, Grant Edwards <grant.b.edwards at gmail.com> wrote:
> On 2017-10-06, Chris Angelico <rosuav at gmail.com> wrote:
>> On Sat, Oct 7, 2017 at 4:05 AM, Grant Edwards <grant.b.edwards at gmail.com> wrote:
>>> On 2017-10-06, Thomas Jollans <tjol at tjol.eu> wrote:
>>>
>>>> Seriously? sys.stdin can be None? That's terrifying.
>>>
>>> Why?
>>>
>>> Unix daemons usually run with no stdin, stderr, or stdout.
>>>
>>> And yes, people do write Unix daemons in Python.
>>
>> Hmm, but usually I would expect them still to HAVE those streams,
>> they're just connected to /dev/null or something. I don't think they
>> would actually fail to exist, would they?
>
> That's a good point. The basic approach is to fork and then just
> close all file descriptors. Since what is normally the
> std{in,out,err} descriptors can be re-used, you could end up with some
> naive code (e.g. something in a library) writing to a file/socket that
> it shouldn't be writing to.
>
> The defensive approach is to open /dev/null and use dup2() to make fd
> 0 1 2 refer to that. In that case, they do exist, but stdin always
> reads empty and stdout stderr write data is discarded.
>
> That's probably the more common approach.
Yeah. I usually see daemonized processes that still have *some*
handles in 0/1/2, either /dev/null or to some sort of logging facility
(the latter being extremely helpful where it's available). But I just
tested it, and sure enough, Python does actually stash None into
sys.stdin/out/err if the corresponding file handles were closed prior
to exec.
#include <unistd.h>
#define IGNORE1 \
""" ";
int main()
{
close(0);
close(1);
close(2);
execlp("python3", "python3", "nostreams.c", NULL);
}
#define IGNORE2 \
" """; #\
import sys #\
with open("nostreams.log", "w") as f: #\
print("stdin: ", sys.stdin, file=f) #\
print("stdout:", sys.stdout, file=f) #\
print("stderr:", sys.stderr, file=f)
So I suppose you'd have to do something like:
if sys.stdout and sys.stdout.isatty():
# be interactive
else:
# perform in batch mode
just to be on the safe side.
ChrisA
More information about the Python-list
mailing list