我经常用来tee /proc/self/fd/2
向 stdout 和 stderr 显示一些内容,捕获 stdout,同时仍将所有输出保留到 stderr。
例如,我有一个do.sh
:
STD_OUT_STR=$(CMD ARGS ... 2>&1 | tee /proc/self/fd/2)
# handle STD_OUT_STR ...
...
这效果非常好。
例如,
./do.sh
基本上是这样运行的:
bash -c 'echo hi | tee /proc/self/fd/2'
输出
hi
hi
然而,有一天我在 下运行它sudo -u A_USER ./do.sh
,它失败了。
sudo -u A_USER ./do.sh'
其本质上是运行:
sudo -u A_USER bash -c 'echo hi | tee /proc/self/fd/2'
输出
tee: /proc/self/fd/2: Permission denied
hi
到目前为止,我必须遵循以下解决方法:
sudo -u A_USER bash -c 'echo hi | tee >(cat >&2)'
我知道这是出于安全原因:不与其他用户共享当前用户的 pty。
我想知道是否有任何选项可以sudo -u A_USER
让进程访问其 pty?
编辑:我需要将其放入tee /proc/self/fd/2
do.sh 脚本中,即我不能将其放在tee /proc/self/fd/2
do.sh 之外,所以sudo -u A_USER bash -c '...' | tee ...
对我没有帮助。
或者:
由于其中没有任何特定于 bash 的内容,因此可以在Linux 或 Cygwin以外的系统上运行。
虽然在大多数系统上,打开
/dev/fd/x
就像在Linux 或 Cygwin 上dup(x)
一样,与在相应文件描述符上打开的文件的“神奇”符号链接相同,因此打开它们不会获得与根本不。>&x
sh
/dev/fd/x
/proc/self/fd/x
dup()
fd 2 很可能在您无权打开写入的文件上打开,就像您的情况一样,或者根本不能像套接字一样打开(通常是由 stderr 是套接字启动的进程的情况
systemd
)到journald
)。即使它是您具有写入权限的常规文件,执行
tee /proc/self/fd/2
或tee /dev/fd/2
也是错误的,因为它从头开始打开相应的文件并截断它。Eventee -a /proc/self/fd/2
是错误的(尽管实际上更好一些),因为虽然有如此多的截断并且它导致在文件末尾完成写入,但只有当 stderr 也以附加模式打开时才有效。例如,之后:
的
hi
输出是通过test
写入的tee
。在 Linux/Cygwin 上,只有当相应的 fd 在某些不可查找的文件(例如管道或 tty 设备)上打开时,使用
/dev/fd/x
//proc/self/fd/x
(或/dev/stdout
, )才可以接受,但即使如此,您也可能会遇到像这里这样的权限问题。/dev/stderr
您的
tee >(cat >&2)
shell 会将您的 shell 转换为在管道上打开的某个位置,并且由于管道是由写入该管道的用户创建的,因此不存在权限问题,但在 bash shell 中这样做仍然是错误的,特别是像 bashtee /proc/self/fd/somefd
那样somefd
不等待那个cat
过程。后:
你会发现有时
file
包含:因为
bash
之前已经返回cat
并成功写入test
并echo
输出了它的hi
第一个。在这里,您可以使用
zsh
而不是bash
可以对多个文件描述符进行发球,而不是像 with 那样仅对文件进行发球tee
:当 fd(此处为 1/stdout)被重定向多次以进行输出时,它会被重定向到一个管道,该管道通向执行发球的内部进程。
无需 bash 的上述警告即可工作,但这些警告
tee
是cat
不必要的,因为 zsh 具有内置功能。如果
zsh
是调用 shell,您可以让调用用户而不是 USER_A 完成内部发球:在 Linux/Cygwin 上哪个会比
本身比
(尽管他们也解决了许可问题)出于上述原因。
使用
sh
(不能使用进程替换) +tee
,将 stderr 转换为管道以解决权限问题的解决方案是手动执行此操作:在内部命令组内部,stderr 成为 的管道
cat
,由 共享cmd
,尽管您也可以将cmd
的 stderr 单独保留:这将与您的情况更接近,
cmd | tee >(cat >&2)
尽管在这里cat
已经得到了适当的等待。就按照你自己的样子跑吧
tee
。考虑这个命令:
它将文本行发送到标准输出。
无需以
tee
其他用户身份运行。接受这些台词并像你自己一样处理它们。sudo
如果您稍后在管道中确实需要这些权限,请再次调用。如果遇到困难,您的脚本始终可以写入文件系统,然后写入
cat
另一个tail -f
进程中的文本文件。如果需要,文本生成器始终可以使用 stdbuf 来调整行缓冲并立即显示结果。