Python: how to write to fd 3?
Asked Answered
H

2

6

in C, I can write to file descriptor 3 like this:

$ cat write.c 
#include <unistd.h>

int main(void) {
    write(3, "written in fd 3\n", 16);
}

Then I can call the program and redirect fd 3 to fd 1 (stdin) like this:

$ ./write 3>&1
written in fd 3

How can I do that in python? I checked os.open() but it creates a file descriptor out of a file in the filesystem (apparently I can't select which file descriptor to allocate) and os.fdopen() creates a file object out of a file descriptor (created with os.open()). So, how can I choose the file descriptor number.

I tried:

with os.fdopen(3, 'w+') as fdfile:

but it gives me:

OSError: [Errno 9] Bad file descriptor

EDIT: This is my python program:

$ cat fd.py
import os

with os.fdopen(3, 'w+') as fdfile:
    fdfile.write("written to fd 3\n")
    fdfile.close()

And this is the result when I run it:

$ python fd.py 3>&1
Traceback (most recent call last):
  File "fd.py", line 3, in <module>
    with os.fdopen(3, 'w+') as fdfile:
  File "/usr/lib/python3.8/os.py", line 1023, in fdopen
    return io.open(fd, *args, **kwargs)
io.UnsupportedOperation: File or stream is not seekable.
Hoopoe answered 1/5, 2020 at 2:12 Comment(8)
notice that fd 3 is just stderrLiberalize
@Liberalize stderr is FD 2Caia
Did you use 3>&1 when running the python script, like you did when running the C program?Caia
@Caia thank you. I suppose then fd 1 should be stdout?Liberalize
@Liberalize Yes. stdin = 0, stdout = 1, stderr = 2Caia
Your error message shows you're trying to access file descriptor 4, not 3.Scorpaenid
@Barmar, I commented in your replyHoopoe
@user2357112supportsMonica, I had pasted the wrong part of the result, sorry. I fixed itHoopoe
H
4

Change "w+" to "w" in the call to os.fdopen. That's what's causing the "not seekable" error. The + tells it to open it for both reading and writing, which won't work.

Heresy answered 1/5, 2020 at 3:1 Comment(8)
Have you ever noticed that almost all open() calls in code posted on SO have w+ modes?Caia
@Caia Hm, yeah I guess it does some up a lot. There must be some bad example out there that people are getting it from.Heresy
btw, why can't I read from a file descriptor? Why can't I open it with w+, write to it and then read from it?Hoopoe
also, tutorialspint has an example with "w+", but it is to do an os.fdopen() using in fd already opened by os.open(), so it works fine in that case (tutorialspoint.com/python/os_fdopen.htm)Hoopoe
@Hoopoe FD 1 is stdout, which you can only write to, not read.Caia
@Barmar, I meant fd3, not 1.Hoopoe
But FD 3 is dup'ed from FD 1, so it has the same restrictions. @HoopoeCaia
Also, they're connected to a tty, which isn't seekable. If you'd redirected FD 1 to a file before running this, you wouldn't get that error.Caia
C
1

Your code should work. But just like when running the C program, you have to redirect FD 3 first.

python write.py 3>&1
Caia answered 1/5, 2020 at 2:20 Comment(5)
I did that, but the problem is os.fdopen() which can't open the file descriptor 3. I believe os.fdopen() can only assign a file object after it has been open with os.open(), no? I edited my questionHoopoe
@TomKarzes, how do I open it without using a file in the filesystem or tempfile.mkstemp()?Hoopoe
you are rigth. It worked, thanks. If you want to reply it I mark as answeredHoopoe
For me it works with python 2, but python 3 raises not seekable.Overlie
@Friedrich See the other answer: Get rid of the + in the mode.. I don't know why so many programmers use that when it's not needed.Caia

© 2022 - 2024 — McMap. All rights reserved.