bash:/ dev / stderr:权限被拒绝


19

升级到新发行版本后,我的bash脚本开始出现错误:

bash: /dev/stderr: Permission denied

在以前的版本中的Bash将在内部承认这些文件的名称(这就是为什么这个问题不是重复这一个),并做正确的事(TM) ,但是,这现在已经不再工作。如何才能成功再次运行脚本?

我尝试将运行脚本的用户添加到组中tty,但这没有什么区别(即使注销并重新登录后也是如此)。

我可以在命令行上重现它,而不会出现问题:

$ echo test > /dev/stdout
bash: /dev/stdout: Permission denied
$ echo test > /dev/stderr
bash: /dev/stderr: Permission denied
$ ls -l /dev/stdout /dev/stderr
lrwxrwxrwx 1 root root 15 May 13 02:04 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 May 13 02:04 /dev/stdout -> /proc/self/fd/1
$ ls -lL /dev/stdout /dev/stderr
crw--w---- 1 username tty 136, 1 May 13 05:01 /dev/stderr
crw--w---- 1 username tty 136, 1 May 13 05:01 /dev/stdout
$ echo $BASH_VERSION
4.2.24(1)-release

在较旧的系统(Ubuntu 10.04)上:

$ echo $BASH_VERSION
4.1.5(1)-release

1
ls -l /dev/stdout /dev/stderr和的输出是ls -lL /dev/stdout /dev/stderr什么?
基思·汤普森

@基思:看我编辑过的问题。这是否意味着Bash完全放弃了对此的内部处理?在较旧的系统上,这些符号链接不存在,但是代码可以正常工作。请注意,这是通过sudo su username2 -... 模拟运行的
0xC0000022L 2012年

您正在使用什么bash版本?echo $BASH_VERSION
吉比2012年

1
有哪些旧版本和新版本(在您的操作系统和bash之前和之后?)
Keith Thompson

Answers:


41

我不认为这完全是个bash问题。

在一条评论中,您说过您在执行此操作后看到了此错误

sudo su username2

以身份登录时username。这是su多数民众赞成引发的问题。

/dev/stdout是的符号链接/proc/self/fd/1,例如是的符号链接/dev/pts/1/dev/pts/1;是伪终端,由拥有和可写username;该所有权是在username登录时授予的。当您时sudo su username2,的所有权/dev/pts/1不会更改,并且username2没有写许可权。

我认为这是一个错误。 实际上/dev/stdout 应该是标准输出流的别名,但是在这里我们看到了一个echo hello可行但echo hello > /dev/stdout失败的情况。

一种解决方法是使username2group成为成员tty,但这将授予username2任何 tty的权限,这可能是不可取的。

另一个解决方法是登录username2帐户而不是使用su,从而/dev/stdout指向由拥有的新分配的伪终端username2。这可能不切实际。

另一个解决方法是修改脚本,使它们不引用/dev/stdout/dev/stderr; 例如,替换为:

echo OUT > /dev/stdout
echo ERR > /dev/stderr

这样:

echo OUT
echo ERR 1>&2

我在带有bash 4.2.24的我自己的系统Ubuntu 12.04上看到了这一点,尽管info bash我系统上的bash文档()表示了这一点,/dev/stdout并且/dev/stderr在重定向中使用时对其进行了特殊处理。但是,即使bash并未对这些名称进行特殊处理,它们仍应充当标准I / O流的等效项。(POSIX没有提及/dev/std{in,out,err},因此可能很难断定这是一个错误。)

看看bash的旧版本,文档暗示/dev/stdout无论文件是否存在,都会对et al进行特殊对待。该功能在bash 2.04中引入,NEWS该版本的文件显示:

重定向代码现在专门处理几个文件名:/ dev / fd / N,/ dev / stdin,/ dev / stdout和/ dev / stderr,无论它们是否存在于文件系统中。

但是,如果您检查源代码(redir.c),则会看到只有HAVE_DEV_STDIN定义了符号的情况下启用特殊处理(这是从源构建bash时确定的)。

据我所知,没有任何发行版的bash可以/dev/stdout无条件地对et al 进行特殊处理-除非某些发行版本对其进行了修补。

因此,另一种解决方法(我还没有尝试过)是获取bash源,进行修改redir.c以使特殊/dev/*处理成为无条件的,并使用您重建的版本而不是系统随附的版本。不过,这可能是过大了。

摘要:

您的操作系统,像我一样,不处理所有权和权限/dev/stdout/dev/stderr正确。据说 bash 在重定向中会特别对待这些名称,但实际上只有在文件不存在的情况下它才会这样做。如果/dev/stdout并能/dev/stderr正常工作就没关系。仅当您su使用另一个帐户或执行类似操作时,才会出现此问题。如果您仅登录帐户,则权限是正确的。


TTY的所有权应更改。这就是ConsoleKit(又名pam_ck_connector.so是)。
Mikel

其实我可能是错的。将不得不挖掘更多。
Mikel

在我的系统上,/proc/self/fd/1正在更新其权限,但这毫无意义,因为它是一个符号链接。同样在Fedora上也会发生,这似乎排除了ConsoleKit。
Mikel

1

实际上,这样做的原因是udev专门在tty设备上将权限设置为0620,而su既不会更改所有权也不会更改权限。在我看来,这使我们无法使用/ dev / std *进行移植。

一种简单的解决方案是将“ mesg y”放在/ etc / profile(或您要使用的任何顶级配置文件)中,因为这会将tty设备的权限更改为0622。我不是很喜欢,但可能会更好而不是更改udev规则。


“ msg y”不起作用
Luciano

等等...也许搜索Bash会在 Bash手册页中的重定向特殊使用多个文件名时处理
0xC0000022L

0

作为Linux的长期用户,我最近建立了一个新的Ubuntu 64位12.04 LTS系统,并且对为什么我的bash脚本无法正常工作(权限被拒绝)感到迷惑不解,后来我找到了这个线程。我认为问题可能是由于新操作系统中的某些问题所致。

最后,事实证明,我愚蠢地使用了UI工具来设置/home目录权限,问题出在与驱动器相关。可以肯定的是,我在上面创建了一个temp目录,/opt并发现我的脚本可以从那里正常运行。一旦我修复了/home驱动器权限后,一切恢复正常。

一个小谜团解决了。


2
这肯定是一个不同的错误。修改/ home中的内容不会影响/ dev。
ott--

-1

这是一个古老的问题,但是我认为仍然非常相关,因此这里是我发现此处未提及的解决方案。

我遇到了这个问题,因为在bash中,我也看到过'su'切换帐户执行命令中的问题:

echo test > /dev/stderr

由于我要做的只是将stdout重定向到stderr,因此以下操作可以达到相同目的,即使在'su'切换帐户中也可以使用:

echo test 1>&2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.