如何为读取行的变量赋值表达式?

时间:2018-03-15 19:29:04

标签: bash text-processing

我从while read line指定的文本文件中读取了一个bash $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是从文件中间读取的最快方法,因此,鉴于文件大小,我故意避免awk和{{1}在大多数情况下。

2 个答案:

答案 0 :(得分:3)

您的数据太大,无法完整阅读。好消息是进程替换的内容是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<&-

答案 1 :(得分:1)

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

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本身的问题。