我想在循环中打开/创建一个文件并在其中写入许多行。
基本上我会这样做:
for i in {1..100}; do
echo "line $i">>test.log
done
我的理解是操作系统将打开/关闭test.log
文件i
时间。
我遇到了另一种语法/方法:
exec {log}>>test.log
for i in {1..1000}; do
echo "line $i" >& $log
done
{log}>&-
我假设exec {log}>>test.log
将打开/创建文件并保持打开状态,而echo "line $i" >& $log
使用已打开的文件?
{log}>&-
这会关闭文件句柄吗?
这个方法叫什么?在哪里可以找到有关用例的更多信息?
答案1
在您展示的用例中,您可以仅重定向for
复合命令的标准输出。这消除了处理文件描述符的需要。
for i in {1..100}; do
printf 'line %d\n' "$i"
done >test.log
这将创建或截断名为 的文件test.log
,并且循环内标准输出流的所有输出(除非显式重定向到其他地方)都将转到该文件。用于>>
追加到文件而不是截断它。该文件只会被打开一次。
您可以对任何其他复合命令执行相同的操作:
if [ -e file ]; then
echo 'file exists'
else
echo 'file does not exist'
fi >out.log
{
echo 'line 1'
cat some-file
echo 'last line'
} >lines.txt
答案2
首先,由于 fd 仅在单个循环中使用,因此也可以将重定向放在循环上,而无需随后手动关闭它:
for i in {1..100}; do
echo "line $i"
done >>test.log
在这里,如果您想在循环开始时清除文件,您还可以使用截断重定向> test.log
而不是使用 附加重定向。>>
它不会在循环迭代之间被截断,因为它对于整个循环来说是相同的文件句柄。
我不确定使用exec
来处理重定向是否有特定的名称,这只是修改适用于整个 shell 的重定向的一种方法。有点奇怪的是, 的另一种用法exec
是与命令一起使用,它将替换整个 shell,但在这里,shell 继续运行。
带有的那个{var}>filename
是非标准扩展,它是Bash 手册中描述:
每个重定向前面都可以加上文件描述符,但前面可以加上以下形式的字:{变量名}。在这种情况下,对于除 >&- 和 <&- 之外的每个重定向运算符,shell 都会分配一个大于 10 的文件描述符,并将其分配给 {变量名}。如果 >&- 或 <&- 前面有 {变量名},varname 的值定义要关闭的文件描述符。如果 {变量名提供后,重定向将持续超出命令的范围,从而允许 shell 程序员手动管理文件描述符的生命周期。
它至少也受到 ksh 和 zsh 的支持(并且可能从其中之一借用给 Bash)。
请注意,您不需要自动分配,但可以使用固定数量,例如:
exec 9>>test.log
for i in {1..100}; do
echo "line $i" >&9
done
exec 9>&-
您只需要自己跟踪 fd 编号即可。 3到9的数字应该可供脚本作者自由使用; 0、1和2是标准文件描述符,10及以上可以由shell内部使用。