Eric Roller
Eric Roller

Reputation: 437

bash redirect to /dev/stdout: Not a directory

I recently upgraded from CentOS 5.8 (with GNU bash 3.2.25) to CentOS 6.5 (with GNU bash 4.1.2). A command that used to work with CentOS 5.8 no longer works with CentOS 6.5. It is a silly example with an easy workaround, but I am trying to understand what is going on underneath the bash hood that is causing the different behavior. Maybe it is a new bug in bash 4.1.2 or an old bug that was fixed and the new behavior is expected?

CentOS 5.8:

    (echo "hi" > /dev/stdout) > test.txt
    echo $?
0
    cat test.txt
hi

CentOS 6.5:

    (echo "hi" > /dev/stdout) > test.txt
-bash: /dev/stdout: Not a directory
    echo $?
1

Update: It doesn't look like this is problem related to CentOS version. I have another CentOS 6.5 machine where the command works. I have eliminated any environment variables as the culprit. Any ideas? On all the machines these commands gives the same output:

    ls -ld /dev/stdout
lrwxrwxrwx 1 root root 15 Apr 30 13:30 /dev/stdout -> /proc/self/fd/1

    ls -lL /dev/stdout
crw--w---- 1 user1 tty 136, 0 Oct 28 23:21 /dev/stdout

Another Update: It seems the sub-shell is inheriting the redirected stdout of the parent shell. The is not too surprising I guess, but still why does it work on one machine, but fail on the other machine when they are running the same bash version?

On the working machine:

    ((ls -la /dev/stdout; ls -la /proc/self/fd/1) >/dev/stdout) > test.txt
    cat test.txt
lrwxrwxrwx 1 root root 15 Aug 13 08:14 /dev/stdout -> /proc/self/fd/1
l-wx------ 1 user1 aladdin 64 Oct 29 06:54 /proc/self/fd/1 -> /home/user1/test.txt

I think Yu Huang is right, redirecting to /tmp works on both machines. Both machines are using isilon NAS for the /home mount, but probably one has slightly different filesystem version or configuration that caused the error. In conclusion, redirecting to /dev/stdout should be avoided unless you know the parent process will not redirecting it.

UPDATE: This problem arose after upgrade to NFS v4 from v3. After downgrading back to v3 this behavior went away.

Upvotes: 4

Views: 7772

Answers (3)

storm_m2138
storm_m2138

Reputation: 2519

I was seeing issues writing piped stdin input to AWS EFS (NFSV4) that paralleled this issue. (Using Centos 6.8 so unfortunately cannot upgrade bash to 4.2).

I asked AWS support about this, here's their response --

This problem is not related to EFS itself, the problem here is with bash. This issue was fixed in bash 4.2 or later in RHEL.

To avoid this problem, please, try to create a file handle before running the echo command within a subshell, after that the same file handler can be used as a redirect. Like the below example:

exec 5> test.txt; (echo "hi" >&5); cat test.txt
hi

Upvotes: 0

Yu Huang
Yu Huang

Reputation: 106

Good morning, user1999165, :)

I suspect it's related to the underlying filesystem. On the same machine, try:

(echo "hi" > /dev/stdout) > /tmp/test.txt

/tmp/ should be linux native (ext3 or something) filesystem

Upvotes: 2

Aaron Digulla
Aaron Digulla

Reputation: 328754

On many Linux systems, /dev/stdout is an alias (link or similar) for file descriptor 1 of the current process. When you look at it from C, then the global stdout is connected to file descriptor 1.

That means echo foo > /dev/stdout is the same as echo foo 1>&1 or a redirect of a file descriptor to itself. I wouldn't expect this to work since the semantics are "close descriptor to redirect and then clone the new target". So to make it work, there must be special code which notices that the two file descriptors are actually the same and which skips the "close" step.

My guess is that on the system where it fails, BASH isn't able to figure out /dev/stdout == fd1 and actually closes it. The error message is weird, though. OTOH, I don't know any other common error which would fit better.

Note: I tried to replicate your problem on Kubuntu 14.04 with BASH 4.3.11 and here, the redirect works (i.e. I don't get an error). Maybe it's a bug in BASH 4.1 which was fixed, since.

Upvotes: 1

Related Questions