如何处理shell脚本中的空格

时间:2014-09-14 21:44:06

标签: bash shell whitespace

我正在尝试编写一个bash脚本来列出当前目录的每个文件/子目录的大小,如下所示:

for f in $(ls -A)
do
    du -sh $f
done

我使用了ls -A,因为我需要包含以点开头的隐藏文件/目录,例如.ssh。但是,如果$f中的文件名包含空格,则上述脚本无法处理空格。 例如我有一个名为:

的文件
books to borrow.doc

以上脚本将返回:

du: cannot access `books': No such file or directory
du: cannot access `to': No such file or directory
du: cannot access `borrow.doc': No such file or directory

有一个类似的问题Shell script issue with filenames containing spaces,但要处理的名称列表来自展开*(而不是ls -A)。该问题的答案是向$f添加双引号。我尝试了相同的,即改变

    du -sh $f

    du -sh "$f"

但结果是一样的。我的问题是如何编写脚本来处理空格?

感谢。

5 个答案:

答案 0 :(得分:3)

不要解析ls的输出。当文件包含空格时,$f包含在空格上分割的文件名的部分,因此双引号没有得到整个文件名

下一个将工作,并将与您的脚本

相同
GLOBIGNORE=".:.."  #ignore . and ..
shopt -s dotglob   #the * will expand all files, e.g. which starting with . too
for f in *
do
    #echo "==$f=="
    du -sh "$f"  #double quoted (!!!)
done

答案 1 :(得分:2)

除非目录太大,文件名列表太大:

du -sh * .*

请注意,这将包括...。如果你想消除..(可能是一个好主意),你可以使用:

for file in * .*
do
    [ "$file" = ".." ] && continue
    du -sh "$file"  # Double quotes important
done

您可以考虑将名称分配给数组,然后处理数组:

files=( * .* )
for file in "${files[@]}"
do
    ...
done

您可以使用其中的变体来对名称组运行du,但您也可以考虑使用:

printf "%s\0" "${files[@]}" | xargs -0 du -sh

答案 2 :(得分:1)

如果find循环会导致头痛,我通常更喜欢使用程序for。在你的情况下,它非常简单:

$ find . -maxdepth 1 -exec du -sh '{}' \;

使用-exec存在许多安全问题,这就是为什么GNU find支持更安全的-execdir,如果可用的话,应该首选find。由于我们不是在这里递归到目录,但它并没有产生真正的区别。

-print0的GNU版本还有一个选项({{1}})来打印出由NUL字节分隔的匹配文件名,但我发现上述解决方案比先输出一个更简单(也更有效)列出所有文件名,然后将其拆分为NUL字节,然后迭代它。

答案 3 :(得分:0)

试试这个:

    ls -A |
    while read -r line
    do
    du -sh "$line"
    done

while循环逐行检查,而不是逐字检查ls -A输出。 这样,您就不需要更改IFS变量。

答案 4 :(得分:0)

总结时间。假设您正在使用Linux,这应该适用于大多数(如果不是全部)情况。

find -maxdepth 1 -mindepth 1 -print0 | xargs -r -0 du -sh