在 bash 中打开文件句柄以避免多个打开/关闭句柄的语法或方法是什么

在 bash 中打开文件句柄以避免多个打开/关闭句柄的语法或方法是什么

我想在循环中打开/创建一个文件并在其中写入许多行。

基本上我会这样做:

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内部使用。

相关内容