繁体   English   中英

在 bash 脚本中间切换输出文件重定向

[英]switch output file redirection in the middle of a bash script

我只想将脚本的输出保存在脚本开头我不知道的地方。 我尝试了一些东西,但我很确定它很丑。 有没有一种优雅的方法来做到这一点:

#!/bin/bash

# Here I don't know where to write outputfile so I create a tmpfile
fic=$(mktemp -t)
trap 'rm -f $fic' EXIT
rm -f $fic
:> $fic
exec 3<> $fic
exec 1>&3
exec 2>&3

# some code in particular reading options and dest dir
echo foo
dir="."

# Here I finally know where I can write my output
fic2=$dir/log.log

cp -f $fic $fic2
exec 3>&- # close fd #3
exec 1>> $fic2
exec 2>&1

echo bar

此外,我想打开整个输出,例如 $ exec ... >(tee $fic)$ 但我找不到解决方案。

非常感谢您的任何建议。 PJLM

如果您知道两个输出文件在同一个文件系统上,您可以只mv输出文件。 您打开的文件描述符将继续工作。

exec 1>/tmp/out1 2>&1
echo out1
mv /tmp/out1 /tmp/out2   # replace with your desired destination
echo out2

如果你想tee输出,并且,同样,两个输出文件都在同一个文件系统上,你可以做几乎相同的事情(一旦tee打开文件进行写入,它同样会继续写入同一个 fd,即使文件移动)。

log1=$(mktemp)
exec 3>"$log1"
exec 1> >(tee /dev/fd/3) 2>&1
echo out1
mv "$log1" "$log2"
echo out2

请注意,不是执行>(tee "$log1")我首先在 shell 中打开 fd 3 然后使用>(tee /dev/fd/3) 这是因为否则存在潜在的竞争条件,即当我们到达mv步骤时tee将不会打开文件。 exec只等待tee将在其中运行的子 shell启动,但tee本身启动并打开文件需要一些时间)。


如果您的第一个和第二个输出文件可能不在同一个文件系统上,您将必须进行一些更高级的改组,并确保在复制第一个文件之前完成写入。

在简单重定向的情况下,我们需要在移动之前关闭文件描述符:

exec 1>"$log1" 2>&1
echo out1
exec 1>&- 2>&-
mv "$log1" "$log2"
exec 1>>"$log2" 2>&1
echo out2

对于可能在不同文件系统上的输出文件的进程替换,我们需要确保在移动文件之前完成进程替换:

exec 3>&1 4>&2                # save original stdout, stderr
exec 1> >(tee "$log1") 2>&1   # redirect to tee
pid=$!                        # save pid of tee's subshell

echo out1
exec 1>&3 2>&4                # restore original stdout, stderr

# wait until tee is done. on newer bash can use `wait $pid` instead
while kill -0 $pid 2>/dev/null; do :; done

mv "$log1" "$log2"

# repeat steps above for new file
exec 3>&1 4>&2
exec 1> >(tee -a "$log2") 2>&1
pid=$!
echo out2
exec 1>&3 2>&4
while kill -0 $pid 2>/dev/null; do :; done

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM