Environment Modules 1包的module
功能通过修改当前shell 进程的各种环境变量来完成它的工作。
不幸的是,无论成功与否,这个函数都会返回 0 2,这使得客户端脚本很难对失败做出适当的响应。
我想实现一个函数包装器mymodule
,module
它将所有参数直接传递给,如果失败module
,则正确返回一个非零值。module
mymodule
可以检测是否module
失败的唯一方法是检查输出module
函数写入 stderr(如果有)。
问题是我无法想出一个合理的方法mymodule
来获得这个输出而不使module
' 的动作无效。更具体地说,我能想到的几乎所有将module
'stderr 捕获到变量中的方法都需要module
在子进程中运行,从而阻止它完成它的工作(这需要修改当前的 shell)。
上述的一个例外是将module
's stderr 重定向到一个临时文件,但我讨厌每次module
函数运行时都创建一个文件的想法。
有没有办法在当前环境mymodule
中调用module
,同时在变量中捕获它的标准错误?
我对 和 的答案都很zsh
感兴趣bash
。
1不要与Lmod 环境模块包混淆,后者具有非常相似的界面。
2至少对于我必须使用的古老版本 3.2.9 来说是这样。我无法控制这一点。
Bash 和 zsh 都有协同进程(不幸的是略有不同),它们本质上封装了一个
pipe
调用并产生一个子进程,其标准输入和标准输出都可供调用 shell 使用。本质上,它们让 shell 同时运行x
和y
inx | cmd | y
,但是所有的x
、y
和cmd
从当前进程运行,而不是在管道执行环境中运行。这将让我们运行
module 2>&...
一些...
,module
从当前 shell 运行。如果我们使用cat
作为我们的协同进程(即cmd
),它只会再次直接重复所有内容,然后我们可以稍后再次将输出读回当前 shelly <&...
。另一种选择是将标准错误重定向到另一个后台进程并
wait
为其返回代码。我将在下面解决这两个问题。我将使用这个伪
module
函数进行测试,以便我可以随意打开和关闭错误。if 修改当前的 shell 环境以便我们可以看到它并将“err”输出到 stderr;我将根据需要评论该行:如果我
cat
在 Bash 中运行一个协同进程,我可以将module
's stderr 重定向到其中,并从cat
's stdout 读取以执行我想要的任何操作:在 zsh 中它需要是
而是在中间。
无论哪种情况,我都可以
module
在当前 shell 中运行命令并从那里读取错误输出。函数可以if
正常返回。cat
除了在当前执行环境中运行之外的所有内容:FD 重定向不会像管道那样创建独立的环境。我们可以echo $FOO
在最后检查一下,并看到日期已经更新,因为module
在当前环境中运行。或者,后台进程可以完成所有工作。这在 Bash 中有效:
以上将输出
7
或0
根据顶部子进程所说的内容 - 您可以调整以对返回码做任何您喜欢的事情。在 zsh 下它没有,因为$!
没有为进程替换设置;这应该是可以解决的,但我停止了尝试。固定的先进先出,而不是临时文件,也可以在这里工作。在这种情况下,您可能还希望在任一侧保存和恢复 FD 2。
我不知道“环境模块”是如何工作的,但我会从你的描述中假设它们是设置环境变量的 shell 函数,并且它们的 stderr 输出应该被捕获/匹配,而不需要在单独的进程中运行它们。
不管你喜不喜欢,答案是唯一可靠且明显的方法是将他们的标准错误重定向到一个临时文件。使用命名管道同样笨拙(您仍然必须创建一个临时文件!),而且更加棘手。并且使用协同进程是繁重、笨拙和不便的。
在
bash
(并且bash
仅在)中,您可以利用未记录的功能($!
从>(...)
进程替换中设置为 PID)并摆脱类似的情况:这个例子假设它
module
本身没有产生任何可能混淆的孩子$!
。在 Linux 上,使用 bash 和 zsh,您应该能够:
这
3<<< ''
是一个最初包含一个空行的here-string。zsh
并实现 here- stringsbash
和 here-documents 作为已删除的临时文件。在 Linux(和 Cygwin,但通常不是其他系统)上,打开/dev/fd/3
会打开 fd 3 指向的文件,即使它已经被删除(在其他系统上,它会复制 fd 3),因此这是一种非常干净的处理临时文件的方法那里。该文件已被删除,您不必担心它的清理,并且它仅在很短的时间内在 FS 上可见(但是从版本 5 开始,bash
删除了我们需要解决的对它的写入权限chmod
)。在这里,如果要按顺序运行(而不是在单独的进程中并行运行),则确实需要一个临时
module
文件grep
。如果有足够的数据输出填满管道,则使用管道(如 Michael 的方法,但与 @mosvy 的方法不同)会导致死锁。