3

What is the difference between find . and /home/user/* as an input to for command.? For example:

for var in $(find .)
do echo "$var"
done

or

for var in /home/user/*
do
echo "$var"
done

In the first case for command breaks up the file with names containing spaces. While in the second case it does not. Why?

4

This is standard practice for shells. The order of operations is command substitution ($(find .)), then word splitting, then glob expansion (/home/user/*).

From the POSIX standard (word splitting = field splitting; glob expansion = pathname expansion):

The order of word expansion shall be as follows:

  1. Tilde expansion (see Tilde Expansion), parameter expansion (see Parameter Expansion), command substitution (see Command Substitution), and arithmetic expansion (see Arithmetic Expansion) shall be performed, beginning to end. See item 5 in Token Recognition.

  2. Field splitting (see Field Splitting) shall be performed on the portions of the fields generated by step 1, unless IFS is null.

  3. Pathname expansion (see Pathname Expansion) shall be performed, unless set -f is in effect.

  4. Quote removal (see Quote Removal) shall always be performed last.


For this reason, it is always recommended to use globs where possible, so that word splitting does not interfere with your file names. The $(find) construct is actually an example of Bash Pitfall #1.

  • if I write cat *, if there exist only one file named 'abc def.txt', then it will take this as two different files. this contradicts your answer.. – Edward Torvalds Nov 13 '14 at 14:49
  • @edwardtorvalds Can you provide more information? * should match a file named abc def.txt. If it doesn't something is wrong so tell exactly what you type and exactly what output you get. – jw013 Nov 13 '14 at 15:11
  • goto this link: dwheeler.com/essays/filenames-in-shell.html it says that not to use '*' – Edward Torvalds Nov 13 '14 at 15:25
  • @edwardtorvalds For the problem pointed out by the Wheeler link, use ./* and the problem is solved. The wheeler link is irrelevant to your first comment about abc def.txt though. I still do not know what you were trying to say with your comment about abc def.txt. – jw013 Nov 13 '14 at 16:14
  • sorry to confuse you, I understood the concept and my doubts are clear. thanks a lot :) – Edward Torvalds Nov 13 '14 at 16:30
4

The shell does things in order. $(find .) is called command substitution. The results of command substitution are subjected:

  1. word splitting,
  2. pathname expansion
  3. quote removal

Word splitting is what causes the problem when there are file names with spaces.

/home/user/* is pathname expansion. Note that that is second to last on the above list. It is subjected only to quote removal.

1

One additional difference between the two is that shell globs (like /home/user/*) don't usually include "hidden files" (filenames that begin with a dot). On the other hand, find will match all filenames except the special directories '.' and '..' (current and parent directory).

  • 1
    Furthermore, that find command will recurse (as far as it can) - the wildcard will match only items immediately in the given directory. – Andrew Medico Nov 13 '14 at 3:15
0

Another approach of explaining it: When * is used then the shell knows what the single elements are. The find output is just a long string. The shell does not know what the elements (and their separators) are.

Command substitution can be used in a special way with a program that produces quoted output; then the problem would not appear. But in order to make the shell recognize the quoting you need e.g. eval which often makes the whole expression more complicated:

eval for var in $(ls --quoting-style=shell)\; do echo '"$var"'\; done
  • 1
    ls --quoting-style=shell would not help. Only literal quotes are actually treated as quotes. Any quote characters that happen to result from expansions are not special. You would have to use eval to get the shell to reparse expanded output, and I would not really recommend that. – jw013 Nov 13 '14 at 1:34
  • Never post without trying... – Hauke Laging Nov 13 '14 at 1:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.