重定向 Ruby 脚本的 stderr 未按预期工作

重定向 Ruby 脚本的 stderr 未按预期工作

我有一个我认为正在输出的命令,stderr因为当我重定向stdout到时/dev/null,我仍然将输出打印到屏幕上。

但是,当我重定向stderr到时/dev/null,我也会将输出打印到屏幕上。

此外,当我将所有输出重定向到/dev/nullthen 时,它会按预期工作。

怎么会这样?应该1>2>至少抓住一些吗&>

下面是一个例子:

$ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
$ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles 1>/dev/null
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
$ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles 2>/dev/null
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
$ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles &>/dev/null
$ 

要复制,请克隆我的项目:

➜  ~/D/w/tmp  rm /tmp/fakehome
➜  ~/D/w/tmp  mkdir /tmp/fakehome
➜  ~/D/w/tmp  git clone https://github.com/mbigras/mb-fullstop
Cloning into 'mb-fullstop'...
remote: Counting objects: 150, done.
remote: Compressing objects: 100% (84/84), done.
remote: Total 150 (delta 49), reused 147 (delta 46), pack-reused 0
Receiving objects: 100% (150/150), 24.06 KiB | 0 bytes/s, done.
Resolving deltas: 100% (49/49), done.
Checking connectivity... done.
➜  ~/D/w/tmp  cd mb-fullstop
➜  mb-fullstop master ✓ git checkout fix-git-logging-to-stderr
Branch fix-git-logging-to-stderr set up to track remote branch fix-git-logging-to-stderr from origin.
Switched to a new branch 'fix-git-logging-to-stderr'
➜  mb-fullstop fix-git-logging-to-stderr ✓ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': Cloning into 'fake-dotfiles'...
➜  mb-fullstop fix-git-logging-to-stderr ✓ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
➜  mb-fullstop fix-git-logging-to-stderr ✓ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles 1> /dev/null
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
➜  mb-fullstop fix-git-logging-to-stderr ✓ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles 2> /dev/null
stderr output of 'git clone https://github.com/mbigras/fake-dotfiles': fatal: destination path 'fake-dotfiles' already exists and is not an empty directory.
Error running 'git clone https://github.com/mbigras/fake-dotfiles'
checkout dir already exists, use --force to overwrite
➜  mb-fullstop fix-git-logging-to-stderr ✓ HOME=/tmp/fakehome/ bundle exec bin/fullstop https://github.com/mbigras/fake-dotfiles &> /dev/null
➜  mb-fullstop fix-git-logging-to-stderr ✓

答案1

这是 Ruby 日志库的一个特性美沙酮由该脚本使用。它的行为有所不同,具体取决于标准输出和标准错误是否是终端。

参见initialize方法cli_logger.rb。正如评论中所描述的:

将错误类型消息记录到第二个设备的记录器;对于确保错误消息进入标准错误很有用。这对于做正确的事情来说应该是非常明智的。如果两个日志设备都是 tty,例如,一个用于标准错误,另一个用于标准输出,则消息在整个输出流中仅出现一次。换句话说,将显示记录的错误仅有的在标准误中。如果任一日志设备不是 tty,则所有消息都会发送到 +log_device+,只有错误会发送到 +error_device+

您可能会对“做正确的事非常聪明”的说法提出异议。日志模块的更明智的默认设置是记录到 stderr 并忽略 stdout。

相关内容