将ls输出存储在变量中并将其拆分不起作用

时间:2018-07-10 07:27:32

标签: bash sh

#!/usr/bin/bash

dirs="$(ls /)"
IFS=' ' read -a dir <<<"$dirs"
for item in "${dir[@]}"; do
    if [[ $item != "proc" ]]; then
        du -sh /$item
    fi
done

我想在/中列出文件夹,并检查它们的大小,ls /响应bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var,但是如果我更改为<,则结果只有一项0 /bin。 / p>

#!/usr/bin/bash

dirs="bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var"
IFS=' ' read -a dir <<<"$dirs"
for item in "${dir[@]}"; do
    if [[ $item != "proc" ]]; then
        du -sh /$item
    fi
done

结果将是正确的,如何使其起作用?

4 个答案:

答案 0 :(得分:3)

在数个帖子中多次提到了这一点。不要以编程方式使用ls的输出。它有很多陷阱。参见Why you shouldn't parse the output of ls(1)

您需要做的就是外壳程序本身提供的glob扩展,以列出/目录下的目录。另外,您不应使用变量来存储多词内容。您需要使用数组!

shopt -s nullglob
topDirs=(/*/)

现在topDirs数组将包含根目录下的所有文件夹名称,您可以使用循环来解析,

for dir in "${topDirs[@]}"; do
    if [[ $dir != "/proc/" ]]; then
        du -sh "$dir"
    fi
done

至于为什么您的代码不起作用,执行ls /并不是列出目录的有效glob扩展,它列出了两个文件和目录。 ls的输出也是换行符。变量dirs的内容由换行符分隔,因此您在IFS=' '上进行拆分的逻辑从不起作用。它只会将第一行存储在返回的列表中。您应该使用mapfilereadarray来读入以换行符分隔的条目列表

mapfile -t dir <<<"$dirs"

但是整个逻辑存在疑问,因为ls在包含空格或其他特殊字符的情况下会拆分文件名。因此最好避免这种情况,并如上所述进行全局扩展逻辑。

答案 1 :(得分:1)

不需要您的IFS行。如果您确定没有目录包含空格(从IFS行可以看出),可以使用:

dirs="$(ls /)"
for item in $dirs; do
    if [[ $item != "proc" ]]; then
        du -sh /$item
    fi
done

请注意,您也可以省略[@],循环将在单词上重复(因此文件夹中的空格会中断此操作)。更好的是:

for item in /*/; do
    if [[ $item != "proc" ]]; then
        du -sh "$item"
    fi
done

还将处理带有空格的目录。

答案 2 :(得分:1)

您正在做的事情简单得多:

find / -maxdepth 1 -type d -a ! -path / -a ! -path /proc | xargs du -sh

使用find,您可以捕获同一级别的所有文件夹,但同时不包含//proc,最后您使用xargs将文件夹列表传递给{{ 1}},以计算尺寸。

答案 3 :(得分:0)

尝试 mapfile -t dirs <<<"$(ls /)"它必须给您结果而不用空格分开