如何在脚本本身内重定向整个 shell 脚本的输出?

发布于 2024-07-08 16:47:31 字数 738 浏览 8 评论 0原文

是否可以将 Bourne shell 脚本的所有输出重定向到某个地方,但在脚本本身内部使用 shell 命令?

重定向单个命令的输出很容易,但我想要更多类似这样的内容:

#!/bin/sh
if [ ! -t 0 ]; then
    # redirect all of my output to a file here
fi

# rest of script...

含义:如果脚本以非交互方式运行(例如,cron),则将所有内容的输出保存到文件中。 如果从 shell 交互运行,请像往常一样将输出发送到 stdout。

我想对通常由 FreeBSD 定期实用程序运行的脚本执行此操作。 这是日常运行的一部分,我通常不喜欢每天在电子邮件中看到它,所以我没有发送它。 但是,如果这个特定脚本中的某些内容失败,这对我来说很重要,我希望能够捕获并通过电子邮件发送这部分日常工作的输出。

更新:约书亚的答案是正确的,但我也想保存和恢复整个脚本的标准输出和标准错误,这样做是这样的:

# save stdout and stderr to file 
# descriptors 3 and 4, 
# then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1

# ...

# restore stdout and stderr
exec 1>&3 2>&4

Is it possible to redirect all of the output of a Bourne shell script to somewhere, but with shell commands inside the script itself?

Redirecting the output of a single command is easy, but I want something more like this:

#!/bin/sh
if [ ! -t 0 ]; then
    # redirect all of my output to a file here
fi

# rest of script...

Meaning: if the script is run non-interactively (for example, cron), save off the output of everything to a file. If run interactively from a shell, let the output go to stdout as usual.

I want to do this for a script normally run by the FreeBSD periodic utility. It's part of the daily run, which I don't normally care to see every day in email, so I don't have it sent. However, if something inside this one particular script fails, that's important to me and I'd like to be able to capture and email the output of this one part of the daily jobs.

Update: Joshua's answer is spot-on, but I also wanted to save and restore stdout and stderr around the entire script, which is done like this:

# save stdout and stderr to file 
# descriptors 3 and 4, 
# then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1

# ...

# restore stdout and stderr
exec 1>&3 2>&4

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

秋叶绚丽 2024-07-15 16:47:31

解决更新后的问题。

#...part of script without redirection...

{
    #...part of script with redirection...
} > file1 2>file2 # ...and others as appropriate...

#...residue of script without redirection...

大括号“{ ... }”提供 I/O 重定向单元。 大括号必须出现在命令可能出现的位置 - 简单地说,在行的开头或分号之后。 (是的,这可以做得更精确;如果您想狡辩,请告诉我。

您是对的,您可以使用您显示的重定向来保留原始的 stdout 和 stderr ,但通常是如果您按如上所示确定重定向代码的范围,对于稍后必须维护脚本以了解发生的情况的人员来说会更简单。

Bash 手册的相关部分是 分组命令I/O 重定向。 POSIX shell 规范的相关部分是 复合命令 和 < a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07" rel="noreferrer">I/O 重定向。 Bash 有一些额外的符号,但在其他方面与 POSIX shell 规范类似。

Addressing the question as updated.

#...part of script without redirection...

{
    #...part of script with redirection...
} > file1 2>file2 # ...and others as appropriate...

#...residue of script without redirection...

The braces '{ ... }' provide a unit of I/O redirection. The braces must appear where a command could appear - simplistically, at the start of a line or after a semi-colon. (Yes, that can be made more precise; if you want to quibble, let me know.)

You are right that you can preserve the original stdout and stderr with the redirections you showed, but it is usually simpler for the people who have to maintain the script later to understand what's going on if you scope the redirected code as shown above.

The relevant sections of the Bash manual are Grouping Commands and I/O Redirection. The relevant sections of the POSIX shell specification are Compound Commands and I/O Redirection. Bash has some extra notations, but is otherwise similar to the POSIX shell specification.

清醇 2024-07-15 16:47:31

通常我们会将其中之一放置在脚本的顶部或附近。 解析命令行的脚本将在解析后进行重定向。

文件

exec > file

将 stdout 发送到带有 stderr 的

exec > file                                                                      
exec 2>&1

将 stdout 和 stderr 附加到文件

exec >> file
exec 2>&1

As Jonathan Leffler 在他的评论中提到:

exec 有两个独立的工作。 第一个是用新程序替换当前正在执行的 shell(脚本)。 另一个是更改当前 shell 中的 I/O 重定向。 其特点是 exec 没有参数。

Typically we would place one of these at or near the top of the script. Scripts that parse their command lines would do the redirection after parsing.

Send stdout to a file

exec > file

with stderr

exec > file                                                                      
exec 2>&1

append both stdout and stderr to file

exec >> file
exec 2>&1

As Jonathan Leffler mentioned in his comment:

exec has two separate jobs. The first one is to replace the currently executing shell (script) with a new program. The other is changing the I/O redirections in the current shell. This is distinguished by having no argument to exec.

盗梦空间 2024-07-15 16:47:31

您可以使整个脚本成为这样的函数:

main_function() {
  do_things_here
}

然后在脚本的末尾添加以下内容:

if [ -z $TERM ]; then
  # if not run via terminal, log everything into a log file
  main_function 2>&1 >> /var/log/my_uber_script.log
else
  # run via terminal, only output to screen
  main_function
fi

或者,您可以在每次运行时将所有内容记录到日志文件中,然后仍然将其输出到标准输出,只需执行以下操作:

# log everything, but also output to stdout
main_function 2>&1 | tee -a /var/log/my_uber_script.log

You can make the whole script a function like this:

main_function() {
  do_things_here
}

then at the end of the script have this:

if [ -z $TERM ]; then
  # if not run via terminal, log everything into a log file
  main_function 2>&1 >> /var/log/my_uber_script.log
else
  # run via terminal, only output to screen
  main_function
fi

Alternatively, you may log everything into logfile each run and still output it to stdout by simply doing:

# log everything, but also output to stdout
main_function 2>&1 | tee -a /var/log/my_uber_script.log
毁我热情 2024-07-15 16:47:31

为了保存原始的stdout和stderr,您可以使用:

exec [fd number]<&1 
exec [fd number]<&2

例如,以下代码将打印“walla1”和“walla2”到日志文件(a.txt),“walla3”到stdout,“ walla4" 到 stderr。

#!/bin/bash

exec 5<&1
exec 6<&2

exec 1> ~/a.txt 2>&1

echo "walla1"
echo "walla2" >&2
echo "walla3" >&5
echo "walla4" >&6

For saving the original stdout and stderr you can use:

exec [fd number]<&1 
exec [fd number]<&2

For example, the following code will print "walla1" and "walla2" to the log file (a.txt), "walla3" to stdout, "walla4" to stderr.

#!/bin/bash

exec 5<&1
exec 6<&2

exec 1> ~/a.txt 2>&1

echo "walla1"
echo "walla2" >&2
echo "walla3" >&5
echo "walla4" >&6
无法回应 2024-07-15 16:47:31
[ -t <&0 ] || exec >> test.log
[ -t <&0 ] || exec >> test.log
随遇而安 2024-07-15 16:47:31

我终于知道该怎么做了。 我不仅想将输出保存到文件中,还想了解 bash 脚本是否成功运行!

我将 bash 命令包装在一个函数中,然后调用该函数 main_function 并将 tee 输出输出到文件中。 之后,我使用 if [ $? -eq 0]

#! /bin/sh -

main_function() {
 python command.py
}

main_function > >(tee -a "/var/www/logs/output.txt") 2>&1

if [ $? -eq 0 ]
then
    echo 'Success!'
else
    echo 'Failure!'
fi

I finally figured out how to do it. I wanted to not just save the output to a file but also, find out if the bash script ran successfully or not!

I've wrapped the bash commands inside a function and then called the function main_function with a tee output to a file. Afterwards, I've captured the output using if [ $? -eq 0 ].

#! /bin/sh -

main_function() {
 python command.py
}

main_function > >(tee -a "/var/www/logs/output.txt") 2>&1

if [ $? -eq 0 ]
then
    echo 'Success!'
else
    echo 'Failure!'
fi
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文