我需要在一个大约有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}"
当我加入CMD=$(sed...)的时候,while循环在执行几百次后会提前结束。但是,如果我去掉CMD=$(sed...),while循环就能够正常工作。显然,有一些我没有发现的干扰。
根据我在这里所读到的,在尝试了以下方法之后:
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}"
但是没有任何变化。针对这种行为有什么解释和如何解决的帮助吗?
谢谢!
为了向用户1934428澄清情况(感谢您的关注!),我现在创建了一个最小脚本并添加了"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."
输入文件是一个由大约20k行组成的列表,格式如下:
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行之后提前结束,而输入文件有大约20k行。
FILE
,它是否总是在相同的点中止,并且没有错误消息?使用set -x
跟踪它是否能提供任何见解?这是完整的脚本吗,还是您之前进行了任何设置(例如set -e
)? - user1934428ulimit
?否则,为了调试,我会用一些简单的程序(如:
)替换sed
,以查看是sed
的问题还是其他原因。 - user1934428sed
是一个不好的反模式。你正在重新发明awk '{printf "[%i] %s: CMD=\047%s\047\n", NR, $0, $1}' "$FILE"
,但引号使用是有问题的。 - tripleeeIFS=' ' read -r -a TOK <<< "${LINE}"; CMD="${TOK[0]}"; TIME="${TOK[1]}"
。这当然提高了效率(至少暂时省去了学习awk的麻烦;))。问题仍然存在。我在脚本末尾添加了“wc -l $ {FILE}”,发现“wc”也失败了。原因可能是${FILE}仍在增长(它被另一个正在运行的进程附加)。通过将“$ {FILE}”复制到新文件中(即,就脚本而言冻结它),循环可以正常工作。虽然这种行为很奇怪... - Guido