jur*_*iks 62 shell gnu-screen files output
目前我有一个 shell 脚本,它将消息记录到这样的日志文件中:
log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command
Run Code Online (Sandbox Code Playgroud)
执行此脚本时,屏幕上没有输出,并且由于我通过 putty 连接到服务器,因此我必须打开另一个连接并执行“tail -f log_file_path.log”,因为我无法终止运行脚本,我想实时查看输出。
显然,我想要的是将文本消息打印在屏幕上并打印到文件中,但我想在一行中完成,而不是两行,其中一行没有重定向到文件。
如何实现这一目标?
l0b*_*0b0 88
这有效:
command | tee -a "$log_file"
Run Code Online (Sandbox Code Playgroud)
tee将输入保存到文件(用于-a追加而不是覆盖),并将输入也复制到标准输出。
因为该命令可以检测到它现在正在以非交互式方式运行,所以这可能会改变它的行为。最常见的副作用是它禁用了颜色输出。如果发生这种情况(并且您想要 ANSI 颜色编码输出),您必须检查命令文档以查看它是否有办法强制它恢复交互行为,例如grep --color=always. 请注意,这意味着日志文件也将包含这些转义码,您需要使用less --RAW-CONTROL-CHARS "$log_file"它来阅读它而不会分散转义码文字的注意力。还要注意,在运行上述命令时,无法使日志文件内容与打印到屏幕上的内容不同,因此您不能在日志文件中将彩色编码输出到屏幕和非彩色输出。
您可以使用 here-doc 和 . 将其用于高效的、对 POSIX 友好的通用收集器模型。
. 8<<-\IOHERE /proc/self/fd/8
command
…
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE
Run Code Online (Sandbox Code Playgroud)
当您打开 heredoc 时,您会使用 IOHERE 输入令牌向 shell 发出信号,它应该将其输入重定向到您指定的文件描述符,直到它遇到限制器令牌的另一端。我环顾四周,但我没有看到很多使用重定向 fd 编号的示例,正如我上面展示的结合 heredoc 运算符,尽管它的用法在 POSIX 基本 shell 命令指南中明确指定。大多数人只是将其指向 stdin 并进行拍摄,但我发现以这种方式获取 scriptlet 可以使 stdin 自由,并且组成应用程序不会抱怨 I/O 路径被阻塞。
Heredoc 的内容被流式传输到您指定的文件描述符,然后将其解释为 shell 代码并由 . 内置,但并非没有为 . . 如果 /proc/self 路径给您带来麻烦,请尝试 /dev/fd/n 或 /proc/$$。顺便说一下,同样的方法适用于管道:
cat ./*.sh | . /dev/stdin
Run Code Online (Sandbox Code Playgroud)
可能至少和看起来一样不明智。当然,你可以对 sh 做同样的事情,但是 . 的目的是在当前的 shell 环境中执行,这可能是你想要的,并且,根据你的 shell,使用 heredoc 的可能性要大得多使用标准的匿名管道。
无论如何,正如您可能已经注意到的那样,我仍然没有回答您的问题。但是,如果您考虑一下,就像heredoc 将所有代码流式传输到 .'s 一样,它还为您提供了一个简单的输出点:
. 5<<EOIN /dev/fd/5 |\
tee -a ./log.file | cat -u >$(tty)
script
…
more script
EOIN
Run Code Online (Sandbox Code Playgroud)
因此,在您的 heredoc 中执行的任何代码的所有终端标准输出都是从 . 理所当然,可以很容易地从单个管道上开球。我包含了无缓冲的 cat 调用,因为我不清楚当前的 stdout 方向,但它可能是多余的(几乎可以肯定它无论如何都是这样写的)并且管道可能会在 tee 处结束。
您可能还会质疑第二个示例中缺少的反斜杠引号。在您开始之前了解这部分很重要,并且可能会给您一些关于如何使用它的想法。引用的 heredoc 限制器(到目前为止我们已经使用了 IOHERE 和 EOIN,第一个我用反斜杠引用,尽管“单”或“双”引号将用于相同的目的)将阻止 shell 对内容,但未加引号的限制器将使其内容可扩展。当您的 heredoc 是 . 来源是戏剧性的:
. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)}
HD
echo $vars
> 4,8,12…
echo $var1 $var51
> 4 104
Run Code Online (Sandbox Code Playgroud)
因为我没有引用 heredoc 限制器,所以 shell 在读取内容时以及在将结果文件描述符提供给 . 执行。这基本上导致命令被解析两次 - 无论如何都是可扩展的。因为我反斜杠引用了 $vars 参数扩展,shell 在第一次传递时忽略了它的声明,只去掉了反斜杠,所以整个 printf 扩展内容可以在 . 在第二遍获取脚本。
这个功能基本上正是危险的 eval shell 内置可以提供的功能,即使在heredoc 中引用比在 eval 中更容易处理,并且可能同样危险。除非您仔细计划,否则最好根据习惯引用“EOF”限制器。就是说。
编辑:呃,我回头看这个,觉得这有点太过分了。如果您需要做的只是将多个输出连接到一个管道中,那么最简单的方法就是使用:
{ or ( command ) list ; } | tee -a ea.sy >>pea.sy
Run Code Online (Sandbox Code Playgroud)
curlies 将尝试在当前 shell 中运行内容,而 parens 将自动分出。尽管如此,任何人都可以告诉你,至少在我看来,. Heredoc 解决方案是更有价值的信息,特别是如果您想了解 shell 的实际工作方式。
玩得开心!
小智 6
如果您不希望 tee 语句运行它,请执行以下操作:
#!/bin/bash
# A Shell subroutine to echo to screen and a log file
log_file_name="/some/dir/log_file.log"
echolog()
(
echo "$@"
echo "$@" >> $log_file_name
)
echo "no need to log this"
echolog "some important text that needs logging"
Run Code Online (Sandbox Code Playgroud)
所以现在在我的原始脚本中,我可以将“echo”更改为“echolog”,我希望在日志文件中输出。