如何解决Bash循环遍历文件过早结束
我无法在约2万行的文本文件中进行Bash循环。
这是我的代码(最小化):
LINE_NB=0
while IFS= read -r LINE; do
LINE_NB=$((LINE_NB+1))
CMD=$(sed "s/\([^ ]*\) .*/\1/" <<< ${LINE})
echo "[${LINE_NB}] ${LINE}: CMD='${CMD}'"
done <"${FILE}"
while循环在数百次迭代后过早结束。但是,如果我删除CMD = $(sed ...)部分,则循环可以正常工作。因此,显然有一些干扰我无法发现。
在准备好here时,我也尝试过:
LINE_NB=0
while IFS= read -r -u4 LINE; do
LINE_NB=$((LINE_NB+1))
CMD=$(sed "s/\([^ ]*\) .*/\1/" <<< ${LINE})
echo "[${LINE_NB}] ${LINE}: CMD='${CMD}'"
done 4<"${FILE}"
但没有任何变化。有关此行为的任何解释以及如何解决的帮助?
谢谢!
为弄清user1934428的情况(感谢您的关注!),我现在创建了一个最小脚本并添加了“ set -x”。完整的脚本如下:
#!/usr/bin/env bash
set -x
FILE="$1"
LINE_NB=0
while IFS= read -u "$file_fd" -r LINE; do
LINE_NB=$((LINE_NB+1))
CMD=$(sed "s/\([^ ]*\) .*/\1/" <<< "${LINE}")
echo "[${LINE_NB}] ${LINE}: CMD='${CMD}'" #,TIME='${TIME}' "
done {file_fd}<"${FILE}"
echo "Done."
输入文件是以下格式的约2万行的列表:
S1 0.018206
L1 0.018966
F1 0.006833
S2 0.004212
L2 0.008005
I8R190 18.3791
I4R349 18.5935
...
while循环在(看似)随机点过早结束。一种可能的输出是:
+ FILE=20k/ir-collapsed.txt
+ LINE_NB=0
+ IFS=
+ read -u 10 -r LINE
+ LINE_NB=1
++ sed 's/\([^ ]*\) .*/\1/'
+ CMD=S1
+ echo '[1] S1 0.018206: CMD='\''S1'\'''
[1] S1 0.018206: CMD='S1'
+ echo '[6510] S1514 0.185504: CMD='\''S1514'\'''
...[snip]...
[6510] S1514 0.185504: CMD='S1514'
+ IFS=
+ read -u 10 -r LINE
+ echo Done.
Done.
如您所见,循环在6510行之后过早结束,而输入文件的长度约为2万行。
解决方法
是的,创建稳定的文件副本是最好的开始。
学习awk
和/或perl
仍然很值得。它并不像看起来那么难。 :)
除此之外,还进行了一些优化-尽量避免在循环内运行任何程序。对于2万行文件,则为2万sed
,这实际上是不必要的。相反,您可以仅对此参数使用参数解析。
# don't use all caps.
# cmd=$(sed "s/\([^ ]*\) .*/\1/" <<< "${line}") becomes
cmd="${cmd%% *}" # strip everything from the first space
使用read
来处理它甚至更好,因为您已经在使用它了,但是如果可以避免,请不要生成另一个。就我所爱,read
效率很低;它必须花很多精力来处理所有选项。
while IFS= read -u "$file_fd" cmd timeval; do
echo "[$((++line_nb))] CMD='${CMD}' TIME='${timeval}'"
done {file_fd}<"${file}"
或
while IFS= read -u "$file_fd" -r -a tok; do
echo "[$((++line_nb))] LINE='${tok[@]}' CMD='${tok[0]}' TIME='${tok[1]}'"
done {file_fd}<"${file}"
(这将对行进行 sort 的重新构建,但是如果有制表符或多余的空格等,它将仅填充$IFS
的第一个字符,即默认值。在这里无关紧要。)
awk
可以简化此工作,并且可以更快地使用内置的更好的工具。
awk '{printf "NR=[%d] LINE=[%s] CMD=[%s] TIME=[%s]\n",NR,$0,$1,$2 }' 20k/ir-collapsed.txt
运行一些时间比较-在有和没有sed
的情况下,将一个read
与两个进行比较,然后将每个与awk
进行比较。 :)
每行需要做的事情越多,文件中的行越多,就越重要。养成尽可能整齐地做小事情的习惯-从长远来看,这会带来回报。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。