通过管道将 main 方法传递给 tee 将使 trap 方法看不到全局变量

发布于 2025-01-11 13:30:39 字数 831 浏览 0 评论 0原文

我有一个 trap 方法,它既不访问全局变量,也不使用 $* 接收变量。它看起来像这样:

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

declare -a arr

finish_exit() {
        echo "* = $*"
        echo "arr = ${arr[*]}"
}
trap 'finish_exit "${arr[@]}"' EXIT

main() {
  arr+=("hello")
  arr+=("world")
}

main | tee -a /dev/null

脚本打印“”。

如果我删除 | tee -a ... 片段,脚本按照预期打印 'hello\nworld' 两次。

现在,如何将输出通过管道传输到日志文件而不丢失所有上下文? 一种解决方案是路由脚本调用中的所有内容,如下所示: <代码>./myscript.sh>> /dev/null,但我认为应该有一种方法可以在脚本中执行此操作,这样我就可以记录每个调用,而不仅仅是那些由 cron 运行的调用。

我研究的另一个解决方案是:

main() {
  ...
} >> /dev/null

但这将导致交互式 shell 上没有输出。


解释为什么这个子 shell 会在调用 trap 函数之前“擦除”全局变量的额外业力。

I have a trap method which neither access global variables nor receive variables using $*. It looks like this:

#!/usr/bin/env bash
set -euo pipefail
IFS=

The script prints ''.

If I remove the | tee -a ... snippet, the script prints 'hello\nworld' twice as expected.

Now, how can I pipe the output to a logfile WITHOUT loosing all context?
One solution would be to route everything from the script call, like so:
./myscript.sh >> /dev/null, but I think there should be a way to do this inside the script so I can log EVERY call, not just those run by cron.

Another solution I investigated was:

main() {
  ...
} >> /dev/null

But this will result in no output on the interactive shell.


Bonus karma for explanations why this subshell will "erase" global variables before the trap function is being called.

\n\t' declare -a arr finish_exit() { echo "* = $*" echo "arr = ${arr[*]}" } trap 'finish_exit "${arr[@]}"' EXIT main() { arr+=("hello") arr+=("world") } main | tee -a /dev/null

The script prints ''.

If I remove the | tee -a ... snippet, the script prints 'hello\nworld' twice as expected.

Now, how can I pipe the output to a logfile WITHOUT loosing all context?
One solution would be to route everything from the script call, like so:
./myscript.sh >> /dev/null, but I think there should be a way to do this inside the script so I can log EVERY call, not just those run by cron.

Another solution I investigated was:

But this will result in no output on the interactive shell.


Bonus karma for explanations why this subshell will "erase" global variables before the trap function is being called.

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

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

发布评论

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

评论(1

单调的奢华 2025-01-18 13:30:39

将使 trap 方法看不到全局变量

子 shell 确实“看到”全局变量,但它不执行 trap。

为什么这个子shell会“删除”全局变量

https:// “删除”全局变量www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html

命令替换、用括号分组的命令和异步命令在与 shell 环境重复的子 shell 环境中调用,除了 shell 捕获的陷阱被重置为shell 在调用时从其父级继承。

如何将输出通过管道传输到日志文件而不丢失所有上下文?

#!/bin/bash
exec 1> >(tee -a logfile)
trap 'echo world' EXIT
echo hello

{
   trap 'echo world' EXIT
   echo hello
} | tee -a logfile

研究:https://serverfault.com/questions/ 103501/how-can-i-complete-log-all-bash-scripts-actions 和类似的。


以下脚本:

#!/usr/bin/env bash
set -euo pipefail
{
set -euo pipefail
IFS=

为我输出:

* = hello
world
arr = hello
world

我在管道之前添加了 set -o pipelinefail ,以保留退出状态。

\n\t' declare -a arr finish_exit() { echo "* = $*" echo "arr = ${arr[*]}" } trap 'finish_exit "${arr[@]}"' EXIT main() { arr+=("hello") arr+=("world") } main } | tee -a /dev/null

为我输出:

我在管道之前添加了 set -o pipelinefail ,以保留退出状态。

will make trap method not see global variables

The subshell does "sees" global variables, it does not execute the trap.

why this subshell will "erase" global variables

From https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html :

Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment, except that traps caught by the shell are reset to the values that the shell inherited from its parent at invocation.

how can I pipe the output to a logfile WITHOUT loosing all context?

#!/bin/bash
exec 1> >(tee -a logfile)
trap 'echo world' EXIT
echo hello

or

{
   trap 'echo world' EXIT
   echo hello
} | tee -a logfile

And research: https://serverfault.com/questions/103501/how-can-i-fully-log-all-bash-scripts-actions and similar.


The following script:

#!/usr/bin/env bash
set -euo pipefail
{
set -euo pipefail
IFS=

outputs for me:

* = hello
world
arr = hello
world

I added that set -o pipefail before the pipe, to preserve the exit status.

\n\t' declare -a arr finish_exit() { echo "* = $*" echo "arr = ${arr[*]}" } trap 'finish_exit "${arr[@]}"' EXIT main() { arr+=("hello") arr+=("world") } main } | tee -a /dev/null

outputs for me:

I added that set -o pipefail before the pipe, to preserve the exit status.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文