bug-bash
[Top][All Lists]
Advanced

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

Re: converting array to string by quoting each element for eval


From: Greg Wooledge
Subject: Re: converting array to string by quoting each element for eval
Date: Wed, 16 Nov 2011 09:22:01 -0500
User-agent: Mutt/1.4.2.3i

On Wed, Nov 16, 2011 at 08:05:03AM -0600, Peng Yu wrote:
> > **NEVER** use getopt(1).  It is broken.  It cannot be made to work
> > correctly.  Its entire design is flawed.
> 
> I don't see these warnings in my systems (macports and ubuntu)

Debian getopt(1) says:

       Traditional implementations of getopt(1) are unable to cope with white-
       space and other (shell-specific) special characters  in  arguments  and
       non-option  parameters.  To solve this problem, this implementation can
       generate quoted output which must once  again  be  interpreted  by  the
       shell  (usually by using the eval command). This has the effect of pre-
       serving those characters, but you must call getopt in a way that is  no
       longer  compatible  with  other versions (the second or third format in
       the SYNOPSIS).  To determine whether this enhanced version of getopt(1)
       is installed, a special test option (-T) can be used.

And that is enough of this nonsense.  I have cited three official manuals
for you already.  Let's move on.


> To support your claim, tell me what myscript would be if the commands
> 
> ./myscript 'a b' 'c d' -type f -name '*"
> ./myscript 'a b' -type f -name '*"
> 
> actually do
> 
> find 'a b' 'a d' -maxdepth 1 -type f -name '*"
> find 'a b' -maxdepth 1 -type f -name '*"

You have a double-quote at the end of each line.  I will assume this is
a typo which was cut-and-pasted several times, and that you actually want
this invocation:

  ./myscript 'a b' 'c d' -type f -name '*'

to have this effect:

  find 'a b' 'a d' -maxdepth 1 -type f -name '*'

Or in other words, you want to write a wrapper script which accepts
find(1) arguments but inserts the arguments -maxdepth 1 after the last
pathname.

Now that we know the goal, it's simple enough:

#!/bin/bash
paths=() i=0
while [[ $1 != -* ]]; do
  paths[i++]=$1; shift
done
exec find "${paths[@]}" -maxdepth 1 "$@"


For testing purposes, I will replace "find" with "args", which is a
script I use to dump arguments to stdout so I can see them.

imadev:~$ ./foo 'a b' 'c d' -type f -name '*'
8 args: <a b> <c d> <-maxdepth> <1> <-type> <f> <-name> <*>

This appears to work correctly, assuming I understand what your goal is.

Here is ~/bin/args:

#! /bin/sh
printf "%d args:" $#
printf " <%s>" "$@"
echo



reply via email to

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