【问题标题】:bash redirect to /dev/stdout: Not a directorybash 重定向到 /dev/stdout:不是目录
【发布时间】:2014-12-24 18:15:00
【问题描述】:

我最近从 CentOS 5.8(带有 GNU bash 3.2.25)升级到 CentOS 6.5(带有 GNU bash 4.1.2)。一个曾经适用于 CentOS 5.8 的命令不再适用于 CentOS 6.5。这是一个简单的解决方法的愚蠢示例,但我试图了解导致不同行为的 bash 引擎盖下发生的事情。可能是 bash 4.1.2 中的一个新 bug,或者是一个已修复的旧 bug,新的行为是预期的?

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

更新:看起来这不是与 CentOS 版本有关的问题。我有另一台 CentOS 6.5 机器,该命令可以运行。我已经消除了任何环境变量作为罪魁祸首。有任何想法吗? 在所有机器上,这些命令给出相同的输出:

    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

另一个更新:似乎子 shell 正在继承父 shell 的重定向标准输出。我猜这并不太令人惊讶,但为什么它仍然可以在一台机器上运行,但是当它们运行相同的 bash 版本时在另一台机器上失败?

在工作机器上:

    ((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

我认为 Yu Huang 是对的,重定向到 /tmp 在两台机器上都有效。两台机器都使用 isilon NAS 进行 /home 挂载,但可能其中一台的文件系统版本或配置略有不同,导致错误。总之,应该避免重定向到 /dev/stdout,除非你知道父进程不会重定向它。

更新:从 v3 升级到 NFS v4 后出现此问题。降级回 v3 后,此行为消失了。

【问题讨论】:

  • 为什么不干脆做:echo "hi" > test.txt
  • @user1999165:它适用于 RHEL 5 和 6。ls -ld /dev/stdout 的发布输出。
  • 这是一个非常奇怪的错误信息。从表面上看,这意味着/dev 不是目录,但这是非常非常不可能的。
  • @JonathanLeffler 是说/dev/stdout 不是目录,这是真的,但似乎并不相关。无论如何,(echo "hi" > /dev/stdout) > test.txt 应该做什么?同时输出到/dev/stdouttest.txt?我以为这就是 tee 的用途。
  • @ooga:如果问题出在/dev/stdout,它会说“没有这样的文件或目录”(或者“是目录”是/dev/stdout 神秘地是一个目录); “不是目录”意味着路径上的元素不是目录,路径上唯一可能出现问题的元素是 //dev — 尽管我不认为我相信. (echo "hi" > /dev/stdout) 将 sub-shell 的 echo 的输出重定向到标准输出,无论如何这就是它要去的地方; > test.txt 发送文件test.txt 的标准输出。这一切都只是有点奇怪。

标签: linux bash redirect centos stdout


【解决方案1】:

在许多 Linux 系统上,/dev/stdout 是当前进程的文件描述符 1 的别名(链接或类似名称)。当你从 C 中查看时,全局 stdout 连接到文件描述符 1。

这意味着echo foo > /dev/stdoutecho foo 1>&1 相同或将文件描述符重定向到自身。我不希望这会起作用,因为语义是“关闭描述符以重定向然后克隆新目标”。所以为了让它工作,必须有特殊的代码注意到这两个文件描述符实际上是相同的并且跳过“关闭”步骤。

我的猜测是,在失败的系统上,BASH 无法找出 /dev/stdout == fd1 并实际上将其关闭。不过,错误消息很奇怪。 OTOH,我不知道任何其他更适合的常见错误。

注意:我尝试使用 BASH 4.3.11 在 Kubuntu 14.04 上复制您的问题,在这里,重定向有效(即我没有收到错误)。也许这是 BASH 4.1 中的一个错误,此后已修复。

【讨论】:

    【解决方案2】:

    早上好,user1999165,:)

    我怀疑它与底层文件系统有关。在同一台机器上,尝试:

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

    /tmp/ 应该是 linux 原生(ext3 之类的)文件系统

    【讨论】:

      【解决方案3】:

      我看到将管道标准输入输入写入与此问题平行的 AWS EFS (NFSV4) 的问题。 (使用 Centos 6.8 所以很遗憾无法将 bash 升级到 4.2)。

      我就此询问了 AWS 支持,这是他们的回复 --

      这个问题与 EFS 本身无关,这里的问题在于 bash。此问题已在 bash 4.2 或更高版本的 RHEL 中修复。

      为避免此问题,请在运行 echo 命令之前尝试创建文件句柄 在子外壳中,之后可以将相同的文件处理程序用作重定向。像下面的例子:

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

      【讨论】:

        猜你喜欢
        • 2019-10-11
        • 2017-12-20
        • 2017-11-30
        • 2011-05-14
        • 2018-02-25
        • 2010-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多