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:遍历目录的行为很奇怪的主要内容,如果未能解决你的问题,请参考以下文章

遍历目录的 Bash shell 无法按预期工作

如何在bash中使用多个ifs遍历多个目录?

for 使用 Bash 遍历目录中的特定文件

使用 Bash find 遍历目录中的特定文件

交互式shell脚本遍历文件目录下的所有文件和目录(绝对路径)

不区分大小写的OSX文件系统 - 奇怪的更改目录(cd)bash行为