Bash:遍历目录的行为很奇怪
Posted
技术标签:
【中文标题】Bash:遍历目录的行为很奇怪【英文标题】:Bash: Iteration through directories acts weird 【发布时间】:2014-04-06 20:16:27 【问题描述】:#!/bin/bash
for dir in "/home/$USER/sessions/out/*/"; do
size=$(stat -c %s $dir/log)
if [ 1 -ne 0 ]; then
echo $size.
fi
done
今天开始使用 bash。我正在尝试检查 home/sessions/out 中所有目录中日志文件的大小。如果 1!=0(总是,作为测试),应该打印日志的文件大小。我得到的是:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57344001 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 966904.
我希望每个文件大小后都有一个句点,实际上我得到了一个句点。在到达 if 子句之前,是否所有文件大小都附加到可变大小?我很困惑。
【问题讨论】:
尝试删除 /home/$USER/sessions/out/*/ 周围的引号 完美。 :) 当您将评论移至答案时,我会将您的答案标记为正确。 在[the]未来,请不要包含if [ 1 -ne 0 ]; then ...
之类的声明,因为它们所做的只是制造混乱(尽管您有解释)。
【参考方案1】:
问题是路径名扩展('*'的扩展)发生在stat
调用中,而不是在循环声明中,因为循环中的路径被引用,但stat
调用中的路径没有。
即循环只发生了一次迭代,dir
的值为/home/$USER/sessions/out/*/
。然后在 stat 调用中对其进行扩展,提供与 /home/$USER/sessions/out/*/log
匹配的所有路径到 stat
。
解决方案是在循环声明中取消引用路径并在stat
调用中引用它。
像这样:
#!/bin/bash
for dir in /home/$USER/sessions/out/*/; do
size=$(stat -c %s "$dir/log")
if [ 1 -ne 0 ]; then
echo $size.
fi
done
【讨论】:
虽然在这种情况下是不必要的,但通常您可以引用模式中可能需要引用的部分(例如参数扩展):for dir in "/home/$USER/sessions/out/"*/; do
。
你也应该使用带有双引号的echo "$size"
,如果只是为了证明引用变量插值应该是常态。
@triplee 我同意总是引用是好的。但是,我在此处省略了引用,因为这不是绝对必要的,并且为了使对原始内容的更改更加清晰以更好地说明这一点。【参考方案2】:
您的整个程序可以简化为一行
stat -c %s /home/$USER/sessions/out/*/log
【讨论】:
【参考方案3】:不太清楚为什么你有一个测试条件 1 != 0,它总是在那里评估为真。但是,以下循环将为您完成:
for LOGFILE in `find $LOGPATH -type f -iname 'log'`
do
echo `stat -c %s $LOGFILE`'.'
done
我使用了变量 LOGPATH,您将使用 '/home/$USER/sessions/out'。如果这是在脚本文件中,明智的做法是在脚本顶部使用这样的变量,以便以后可以在需要时轻松更改。
如果存在名称为 log 的目录,则存在“-type f”,您可能不想解析。如果不是这种情况,那么您可以省略它。
我使用了 find 命令,因为您可以更精细地控制它。您可以设置搜索深度、文件类型、文件大小等。要获得末尾的句点,只需在 echo 语句的末尾单引号一个句点即可。
如果您需要文件名,然后是大小,只需更改 echo 语句,如下所示:
echo "$LOGFILE" `stat -c %s $LOGFILE`'.'
【讨论】:
您的find
命令将在目标目录的子树中找到log
文件anywhere,而不仅仅是在直接子文件夹中,如在OP 的代码中。用for
解析find
输出绝不是一个好主意,因为它会破坏包含空格的路径。
你是绝对正确的@mklement0。但是,如果变量名被双引号引起来,那就说明了。我将编辑我的答案以反映这一点。谢谢。
不幸的是,在for
循环中,没有安全的方法来解析来自命令替换(`...`
或 - 最好是 - $(...)
)的输出。在命令替换中双引号可能会使命令本身更加健壮,但for
循环仍然会出现输出行包含例如嵌入空格或看起来像一个 glob(例如,*
)的问题。双引号将命令替换作为一个整体也不起作用,因为这会将 整个 输出分配给for
变量一次;有关背景信息,请参阅mywiki.wooledge.org/ParsingLs。以上是关于Bash:遍历目录的行为很奇怪的主要内容,如果未能解决你的问题,请参考以下文章