On Mon, Nov 08, 2010 at 03:26:10PM +0100, Hans-Georg Bork wrote: > if this is true, then please explain the differences between > $ find /test -type d ! -wholename "/test" > (/test not shown) > and > $ prog='find /test -type d ! -wholename "/test"' > $ echo $prog > find /test -type d ! -wholename "/test" > $ echo "$($prog)" > (/test shown) > (more results in original mail)
imadev:~$ args find /test -type d ! -wholename "/test" 7 args: <find> </test> <-type> <d> <!> <-wholename> </test> imadev:~$ prog='find /test -type d ! -wholename "/test"' imadev:~$ args $prog 7 args: <find> </test> <-type> <d> <!> <-wholename> <"/test"> "args" is a script that I have in ~/bin. Here is it: imadev:~$ cat bin/args #! /bin/sh printf "%d args:" $# printf " <%s>" "$@" echo I find it incredibly useful. So now, to answer your question, first I need to figure out what "-wholename" actually is. I suspect it's a GNU extension that aliases the -path extension...? Yeah. That's what the man page says. -wholename pattern See -path. This alternative is less portable than -path. OK, now let's see what you're doing: > $ find /test -type d ! -wholename "/test" So... you're trying to filter out the top-level directory itself from the set of results, right? imadev:~$ cd /tmp imadev:/tmp$ mkdir -p test/foo/bar; touch test/foo/bar/file imadev:/tmp$ find test -type d ! -path "test" test/foo test/foo/bar And then you're wondering why this "fails": imadev:/tmp$ find test -type d ! -path \"test\" test test/foo test/foo/bar You're asking it to filter out "test" but there is no "test". There is only test. Or in your original case, you were asking it to filter out "/test" but there was no "/test". There was only a /test directory. It didn't have literal double quotes in its name, but your argument to find DID have literal double quotes, so find was looking for them. > This were indeed just a simple example, the script where I use this set > a complex find command with several -wholename options and there is also > whitespace and wildcards in them. IMHO I'd need double-quotes with it; > it is also explained that way in the man page of find. GNU man page, I assume? The one in Debian 5.0 has this example: -path pattern File name matches shell pattern pattern. The metacharacters do not treat `/' or `.' specially; so, for example, find . -path "./sr*sc" This example is fine, and it demonstrates the use of quotes to protect a glob from exapansion BY A SHELL. But then the shell removes the quotes before passing the glob on to find. find should never see the actual quotes. If it does, it will treat them as literal. That is not what you want. In your code, you were passing literal quotes to find along with the directory name. This is why it failed. The workarounds if you absolutely positively MUST put the argument vector into a variable are (1) eval, or (2) an array. And I'd avoid eval if I were writing the script. It's extremely dangerous, especially if your arguments are as complex as you say. Since you appear not to have read http://mywiki.wooledge.org/BashFAQ/050 yet, let me do all the hard reading for you. This is what you SHOULD have used: prog=(find /test -type d ! -wholename "/test") echo "$( "${pr...@]}" )" And if I modify it slightly and use it, this is what it does: imadev:/tmp$ prog=(find test -type d ! -path "test") imadev:/tmp$ echo "$( "${pr...@]}" )" test/foo test/foo/bar You can put all the double triple quoted space glob metacharacter funny business you want inside array elements. Not inside scalar strings. http://mywiki.wooledge.org/BashFAQ/050