我想在.xprofile使用logger. 在 Bash 中,我认为这看起来像这样:
exec 1> >(logger --priority user.notice --tag $(basename $0)) \
2> >(logger --priority user.error --tag $(basename $0))
Run Code Online (Sandbox Code Playgroud)
我将如何以POSIX /bin/sh兼容的方式做到这一点?
Gil*_*il' 10
没有 POSIX 等价物。您只能使用 执行重定向exec,而不能使用 fork。管道需要叉子,外壳等待子进程完成。
一种解决方案是将所有代码放在一个函数中。
all_my_code () {
…
}
{ all_my_code |
logger --priority user.notice --tag "$(basename "$0")"; } 2>&1 |
logger --priority user.error --tag "$(basename "$0")"
Run Code Online (Sandbox Code Playgroud)
(这还将记录从 logger 的 stdout 实例到 stderr 实例的任何错误。您可以通过更多的文件描述符改组来避免这种情况。)
如果您希望父 shell 在logger进程仍在运行时退出,请将其放在调用&的末尾logger。
{ all_my_code |
logger --priority user.notice --tag "$(basename "$0")" & } 2>&1 |
logger --priority user.error --tag "$(basename "$0")" &
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用命名管道。
pipe_dir=$(mktemp -d)
mkfifo "$pipe_dir/out" "$pipe_dir/err"
<"$pipe_dir/out" logger --priority user.notice --tag "$(basename "$0")" &
<"$pipe_dir/err" logger --priority user.error --tag "$(basename "$0")" &
exec >"$pipe_dir/out" 2>"$pipe_dir/err"
…
rm -r "$pipe_dir"
Run Code Online (Sandbox Code Playgroud)
mik*_*erv 10
_log()( x=0
while [ -e "${TMPDIR:=/tmp}/$$.$((x+=1))" ]
do continue; done &&
mkfifo -- "$TMPDIR/$$.$x" &&
printf %s\\n "$TMPDIR/$$.$x" || exit
exec >&- >/dev/null
{ rm -- "$TMPDIR/$$.$x"
logger --priority user."$1" --tag "${0##*/}"
} <"$TMPDIR/$$.$x" &
) <&- </dev/null
Run Code Online (Sandbox Code Playgroud)
你应该能够像这样使用它:
exec >"$(_log notice)" 2>"$(_log error)"
Run Code Online (Sandbox Code Playgroud)
这是一个使用mktemp命令的版本:
_log()( p=
mkfifo "${p:=$(mktemp -u)}" &&
printf %s "$p" &&
exec <&- >&- <>/dev/null >&0 &&
{ rm "$p"
logger --priority user."$1" --tag "${0##*/}"
} <"$p" &
)
Run Code Online (Sandbox Code Playgroud)
...它的作用大致相同,只是它允许mktemp为您选择文件名。这是有效的,因为进程替换绝不是神奇的,它的工作方式与命令替换非常相似。进程替换不是像命令替换那样用其中运行的命令的值替换扩展,而是用可以找到输出的文件系统链接的名称替换它。
虽然 POSIX shell 没有为这样的事情提供直接的推论,但模拟它是非常简单的。您需要做的就是创建一个文件,通过命令替换将其名称打印到标准,并在相同的后台运行您的命令,该命令将输出到该文件。现在,你可以重定向到该扩张的价值-正是因为你进程替换做。因此,POSIX shell 提供了您当然需要的所有工具——所需要的只是您以适合您的方式使用它们。
上述两个版本都确保它们在使用它们之前销毁指向它们创建/使用的管道的文件系统链接。这意味着事后不需要清理,更重要的是,它们的流仅可用于最初打开它们的进程 - 因此它们的文件系统链接不能用作窥探/劫持您的日志记录活动的手段。将它们的 fs-links 留在文件系统中是一个潜在的安全漏洞。
另一种方法是包装它。它可以在脚本内完成。
exec >"$(_log notice)" 2>"$(_log error)"
Run Code Online (Sandbox Code Playgroud)
这基本上允许您的脚本在尚未调用时自行调用,并为您提供临时工作目录以进行启动。