Bash语法古怪与带空格的文件

时间:2016-11-22 19:18:05

标签: bash shell unix

这是您可能熟悉的问题:我想查询我的Mac上的磁盘使用情况,所以我在我的主目录中尝试了

~/$> for file in `ls`; do du -hs $file; done

带输出

 55M    Applications
107M    Desktop
132G    Documents
5.1G    Downloads
 16G    Library
457M    Music
 53M    Pictures
du: VirtualBox: No such file or directory
du: VMs: No such file or directory

除了最后一个之外很棒,因为它是一个名为“VirtualBox VMs”的目录 - 名称中有一个空格。我谷歌它(实际上,我所要做的就是开始输入“bash loop ...”并且它自动完成“用空格覆盖文件循环” - 感谢Google!)我得到了这个问题,Iterate over list of files with spaces ,作为第一个结果。

如果你仔细阅读那个帖子,你会发现很多复杂的解决方案使用xargs或者奇怪的东西。当然,我可以编写自己的函数来处理这些情况,但我非常坚持有一个单行解决方案。因此,在我看来,最好的解决方案(虽然不是最高投票或被接受的解决方案)是

for file in *; do du -hs "${file}"; done

有些反常,以下不起作用:

  1. 删除引号

    for file in *; do du -hs ${file}; done  #splits on spaces and throws error
    
  2. 使用ls,即使是引号:

    for file in `ls`; do du -hs "${file}"; done #splits on spaces and throws error
    
  3. 我的问题是,一些bash专家可以准确地向我解释所有这些之间的区别是什么,以及为什么失败的失败?

2 个答案:

答案 0 :(得分:1)

意识到工作案例扩展为:du -hs "VirtualBox VMs"

  1. 对于这种情况,问题是该命令扩展为:
    du -hs VirtualBox VMs
    这会将两个文件名传递给du命令。

  2. 对于这种情况,问题是for命令看到两个单独的标记。因此,迭代迭代迭代每个 du -hs VirtualBox
    du -hs VMs

答案 1 :(得分:0)

这一切都解释了在进程替换和参数扩展之后发生分词的事实。因此,$(ls)${file}的结果会进行分词,而"${file}"中的双引号则会抑制分词。