bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Commands executed with $($prog) do not run properly


From: Greg Wooledge
Subject: Re: Commands executed with $($prog) do not run properly
Date: Mon, 8 Nov 2010 09:49:58 -0500
User-agent: Mutt/1.4.2.3i

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 "$( "${prog[@]}" )"

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 "$( "${prog[@]}" )"
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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]