0xC*_*22L 25 bash permissions stdout
升级到新发布版本后,我的bash脚本开始出现错误:
bash: /dev/stderr: Permission denied
Run Code Online (Sandbox Code Playgroud)
在以前的版本中的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
Run Code Online (Sandbox Code Playgroud)
在旧系统(Ubuntu 10.04)上:
$ echo $BASH_VERSION
4.1.5(1)-release
Run Code Online (Sandbox Code Playgroud)
Kei*_*son 48
我不认为这完全是一个 bash 问题。
在评论中,你说你在做之后看到了这个错误
sudo su username2
Run Code Online (Sandbox Code Playgroud)
当以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/stdoutand /dev/stderr; 例如,替换这个:
echo OUT > /dev/stdout
echo ERR > /dev/stderr
Run Code Online (Sandbox Code Playgroud)
这样:
echo OUT
echo ERR 1>&2
Run Code Online (Sandbox Code Playgroud)
我在我自己的系统 Ubuntu 12.04 和 bash 4.2.24 上看到了这一点——即使info bash我系统上的 bash 文档 ( ) 说明了这一点,/dev/stdout并且/dev/stderr在重定向中使用时会被特殊对待。但是即使 bash 没有特别对待这些名称,它们仍然应该充当标准 I/O 流的等效项。(POSIX 没有提到/dev/std{in,out,err},因此可能很难说这是一个错误。)
查看旧版本的 bash,文档暗示/dev/stdout无论文件是否存在,都会对等进行特殊处理。该功能是在 bash 2.04 中引入的NEWS,该版本的文件说:
重定向代码现在专门处理几个文件名:/dev/fd/N、/dev/stdin、/dev/stdout 和 /dev/stderr,无论它们是否存在于文件系统中。
但是,如果您检查源代码 ( redir.c),您将看到仅当HAVE_DEV_STDIN定义了符号时才启用该特殊处理(这是在从源构建 bash 时确定的)。
据我所知,bash 的任何发布版本都没有对/dev/stdoutet al 进行无条件的特殊处理——除非某些发行版已经修补了它。
因此,另一种解决方法(我还没有尝试过)是获取bash 源代码,进行修改redir.c以使特殊/dev/*处理成为无条件的,并使用您重建的版本而不是系统附带的版本。不过,这可能有点矫枉过正。
概括 :
您的操作系统,像我一样,不处理所有权和权限/dev/stdout和/dev/stderr正确。bash应该在重定向中专门处理这些名称,但实际上只有在文件不存在时才会这样做。如果/dev/stdout并且/dev/stderr正常工作,那并不重要。此问题仅在您su转到另一个帐户或执行类似操作时出现;如果您只是登录一个帐户,则权限是正确的。