如何将表达式分配给读取行的变量



我有一个 bash while read line块从 $filename 指定的文本文件中读取:

IFS=''
while read -r line
do
    ...
done < $filename

我想根据提供给脚本的参数在重定向中提供不同的输入,而不是每次都读取整个文件。

  • 整个文件: done < "$filename"
  • 从X行开始:done < <(tail -n +"$x" "$filename")
  • X 行到 Y 行:done < <(tail -n +"$x" "$filename" | head -n "$y")
  • 开始到第 Y 行:done < <(head -n "$y" "$filename")

如何提前将这些输入分配给变量以供 while 循环读取?


我的输入文件是~4GB,带有一些58M行(所有行的长度都不同(,并且可能会不时增长或缩小。 阅读 https://unix.stackexchange.com/questions/47407/cat-line-x-to-line-y-on-a-huge-file 似乎tail | head是从文件中间读取的最快方法,因此考虑到文件大小,我在大多数情况下故意避免awksed

您的数据太大,无法完整读取。好消息是,进程替换的内容是一个 shell 脚本,所以你可以这样写:

while IFS= read -r line; do
    ...
done < <(
    if   [[ $x && $y ]];  then  tail -n +"$x" "$filename" | head -n "$y"
    elif [[ $x ]];        then  tail -n +"$x" "$filename"
    elif [[ $y ]];        then  head -n "$y" "$filename"
    else                        cat "$filename"
    fi
)

我不喜欢进程替换的一件事是代码遵循它所输入的循环。如果它先出现就好了。我认为这会起作用,但未经测试:

# set up file descriptor 3
exec 3< <(
    if   [[ $x && $y ]];  then  tail -n +"$x" "$filename" | head -n "$y"
    elif [[ $x ]];        then  tail -n +"$x" "$filename"
    elif [[ $y ]];        then  head -n "$y" "$filename"
    else                        cat "$filename"
    fi
)
# iterate over lines read from fd 3
while IFS= read -u3 -r line; do
    ...
done
# close fd 3
exec 3<&-

我可能会将所有这些作为循环条件的一部分来处理,并使用显式维护的行计数器。

start=10
end=30
i=0
while ((i <= end )) && IFS= read -r line; do
   (( i++ >= start )) || continue
   ...
done < "$filename"

但是,如果在开始时可能会跳过大量行,则使用sed

while IFS= read -r line; do
    ...
done < <(sed -n "$start,$stop p" "$filename")

awk

while IFS= read -r line; do
   ...
done < <(awk -v start "$start" -v end "$end" 'NR >= start && NR <= end' "$filename")

这就提出了一个问题,即while回路的主体有多少可以移动到awk本身。

最新更新