Here's a problem you may be familiar with: I wanted to make an inquiry into my disk usage on my Mac, so I tried in my home directory
~/$> for file in `ls`; do du -hs $file; done
with output
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
which is great except for the last one because it is a directory called "VirtualBox VMs" -- there is a space in the name. I google it (actually, all I had to do was start typing "bash loop..." and it autocompleted to "bash loop over files with spaces" -- thanks Google!) and I get this question, Iterate over list of files with spaces, as the first result.
If you peruse that thread, you'll find a lot of complicated solutions that use xargs
or something weird. Of course, I could write my own functions to handle these cases, but I was pretty adamant about having a one line solution. Thus, in my opinion, the hands-down best solution (though not the top-voted or accepted solution) was
for file in *; do du -hs "${file}"; done
Somewhat perversely, the following don't work:
Removing the quotes
for file in *; do du -hs ${file}; done #splits on spaces and throws error
Using
ls
, even with the quotes:for file in `ls`; do du -hs "${file}"; done #splits on spaces and throws error
My question is, Can some bash expert explain to me exactly what the difference between all these is, and why the ones that fail fail?