这是如何运作的 ? for 循环去除变量结果

这是如何运作的 ? for 循环去除变量结果

在从书本上学习 bash/ksh 时。我遇到了一个练习,它的结果我很想理解。

当使用 bash -x 执行此脚本以尝试了解其行为(调试)时,我注意到行变量是数字+文件名。因为这是 wc -c [file] 的结果。但一旦 for 循环设置了 res 变量,它就会以某种方式删除文件名,只显示 res=23
(wc -c 的数字结果),我可以看到它发生,但不太明白为什么?我想我理解 for 循环构造.. for i in xxx 做什么.. 不是 100% 理解这个构造中的中断,我确实知道它是为了打破嵌套循环。

这是练习脚本:

if [ ! $# -eq 2 ] ;then
    echo
    echo "usage: $0 <location> <FileName>"
    echo
    exit 1
fi
TMPFILE=/tmp/count
line=$(find "$1" -name "$2" -type f -print | tee $TMPFILE | wc -l)
aant=$line
nr=0
som=0

while [ $nr -lt "$aant" ] ; do
    nr=$(( nr +1 ))
    bestand=$(head -$nr $TMPFILE | tail -1)
    echo -n "$bestand"
    line=$(wc -c "$bestand")

    for woord in $line ; do
        res=$woord
        break
    done
    echo "  $res"
    som=$(( som + res ))
done

if [ "$aant" -eq 0 ] ; then
    echo "No files found"
else
    echo
    echo "In totaal $aant files take $som bytes of space"
fi

rm $TMPFILE
exit 0

答案1

for word in $line,变量的内容line分割成单词然后扩展文件名全局变量(另请参阅这些 问题)。然后,循环针对每个结果值(或“单词”)运行一次。但在这种情况下,循环最多只有一次迭代,因为该break语句会停止循环运行。因此,res循环的第一次迭代中 set 的值仍然保留,其效果与从 中选取第一个空格分隔的单词相同line

会有更好的编写方法,例如我们可以使用 shell 扩展删除文件名。这将输出23

line='23 somefilename'
res="${line%% *}"
echo "$res"

或者,只是没有wc输出文件名,通过将文件重定向到wc的 stdin,而不是将文件名传递到wc.比较这两个:

$ wc -c foo.txt
8 foo.txt
$ wc -c < foo.txt
8

答案2

如果我正确理解你的问题,魔法就发生在这里:

for woord in $line ; do
    res=$woord
    break
done

为了帮助您了解其工作原理,也许考虑一下会有所帮助:

for N in 1 2 3 4 5; do
    echo $N
done
echo "N is $N"

接下来,添加“ break”语句并考虑:

for N in 1 2 3 4 5; do
    echo $N
    break
done
echo "N is $N"

您能描述一下将break语句添加到for循环中的作用吗?

在我看来,我最初引用的四行代码可以减少到只有三行:

for res in $line ; do
    break
done

这本质上是一种“笨拙”的说法:

res="$(awk '{print $1}' <<< "$line")"

答案3

检查 的手册页wc -c

它输出bytecount filename$line空格分隔的列表。

for $woord in $line循环从 中读取第一个变量(直到第一个空格)$list,即 并将bytecount其存储在 中$res。然后,它不会继续读取下一个项目,而是$list点击break指令并退出循环。

正如 @ikkachu 所说,有bytecount比循环更简单的方法来获取 。

相关内容