Re: Passing variables by reference conflicts with local

2010-05-01 Thread Freddy Vulto
On 100430 08:19, Greg Wooledge wrote:
> On Fri, Apr 30, 2010 at 12:02:58AM +0200, Freddy Vulto wrote:
> > Passing variables by reference however, has a caveat in that
> > local variables override the passing by reference, e.g.:
> > 
> > t() {
> > local a
> > eval $1=b
> > }
> > unset a; t a; echo $a  # Outputs nothing, expected "b"
> 
> Why did you declare 'a' to be local if that's not what you wanted?
> Why did you expect 'b' to be output, if you used a local variable?

t() is an example library function which - as a black box - can contain
many local variables.  Local 'a' is just an example.

I would like to call t(), and let it return me a filled variable by
reference, that is without polluting the global environment.

Problem is, all variables work except 'a' because t() happens to declare
this local - which I'm not supposed to know because t() is a black box.

Maybe the example is not clear because 'a' becomes global after all,
and is this a better example:

# Param: $1  variable name to return value to
blackbox() {
local a
eval $1=bar
}

This goes all right:

f() {
local b
blackbox b
echo $b
}
f  # Echos "bar" all right

But if I change 'b' to 'a', this conflicts with blackbox() local 'a':

f() {
local a
blackbox a
echo $a
}
f  # Outputs nothing unexpected


Freddy Vulto
http://fvue.nl/wiki/Bash:_passing_variables_by_reference




Re: Passing variables by reference conflicts with local

2010-05-01 Thread Dennis Williamson
As Chet said, use internal variables that are unlikely to conflict.

# Param: $1  variable name to return value to
   blackbox() {
   local __bb_a# internal: __, blackbox: bb, a: _a
   eval $1=bar
   }

f() {
   local a
   blackbox a
   echo $a
   }
   f# no conflict

I prefer to avoid using eval by using declare, but declare inside a
function makes the variable local. Wouldn't it be nice to have a
global flag (declare -g) like zsh's typeset -g.

d='ls /;true'   # aren't you glad it's not "rm -rf" instead of "ls"
f "$d"  # oops

So in the mean time, you should sanitize those evals.

On Sat, May 1, 2010 at 3:18 AM, Freddy Vulto  wrote:
> On 100430 08:19, Greg Wooledge wrote:
>> On Fri, Apr 30, 2010 at 12:02:58AM +0200, Freddy Vulto wrote:
>> > Passing variables by reference however, has a caveat in that
>> > local variables override the passing by reference, e.g.:
>> >
>> >     t() {
>> >         local a
>> >         eval $1=b
>> >     }
>> >     unset a; t a; echo $a  # Outputs nothing, expected "b"
>>
>> Why did you declare 'a' to be local if that's not what you wanted?
>> Why did you expect 'b' to be output, if you used a local variable?
>
> t() is an example library function which - as a black box - can contain
> many local variables.  Local 'a' is just an example.
>
> I would like to call t(), and let it return me a filled variable by
> reference, that is without polluting the global environment.
>
> Problem is, all variables work except 'a' because t() happens to declare
> this local - which I'm not supposed to know because t() is a black box.
>
> Maybe the example is not clear because 'a' becomes global after all,
> and is this a better example:
>
>    # Param: $1  variable name to return value to
>    blackbox() {
>        local a
>        eval $1=bar
>    }
>
> This goes all right:
>
>    f() {
>        local b
>        blackbox b
>        echo $b
>    }
>    f  # Echos "bar" all right
>
> But if I change 'b' to 'a', this conflicts with blackbox() local 'a':
>
>    f() {
>        local a
>        blackbox a
>        echo $a
>    }
>    f  # Outputs nothing unexpected
>
>
> Freddy Vulto
> http://fvue.nl/wiki/Bash:_passing_variables_by_reference
>
>
>




Re: Passing variables by reference conflicts with local

2010-05-01 Thread Pierre Gaston
On Sat, May 1, 2010 at 12:26 PM, Dennis Williamson
 wrote:
> As Chet said, use internal variables that are unlikely to conflict.
>
> # Param: $1  variable name to return value to
>   blackbox() {
>       local __bb_a    # internal: __, blackbox: bb, a: _a
>       eval $1=bar
>   }
>
> f() {
>       local a
>       blackbox a
>       echo $a
>   }
>   f    # no conflict
>
> I prefer to avoid using eval by using declare, but declare inside a
> function makes the variable local. Wouldn't it be nice to have a
> global flag (declare -g) like zsh's typeset -g.
>
> d='ls /;true'   # aren't you glad it's not "rm -rf" instead of "ls"
> f "$d"  # oops

You can use workarounds like:
printf -v $a "%s" foobar
read $a <<< "%s"




completion gobbles partial match string

2010-05-01 Thread jidanni
Put the cursor after the word "list" and hit TAB:
# find /etc/apt/sources.list.d/*list #|cpio -o|ssh 192.168.44.4 cpio -ivdm
Emacssources.list  eeepc.list tw.list
# find /etc/apt/sources.list.d/ #|cpio -o|ssh 192.168.44.4 cpio -ivdm

Notice how we are shown the completions, but then the "*list" has been
gobbled up!
BASH_VERSION='4.1.5(1)-release'





Re: Passing variables by reference conflicts with local

2010-05-01 Thread Freddy Vulto
On 100501 12:40, Pierre Gaston wrote:
> On Sat, May 1, 2010 at 12:26 PM, Dennis Williamson wrote:
> > As Chet said, use internal variables that are unlikely to conflict.
> You can use workarounds like:
> printf -v $a "%s" foobar
> read $a <<< "%s"

The problem with obfucscated internal variables I think is that my
library code becomes unnecessary obfuscated.  That's why I'm thinking an
additional call-layer (workaround 2 in my original mail) is an
improvement in that the private library code "_blackbox()" can use
simple, readable variables without restrictions/conflicts, while the
public layer "blackbox()" checks conflicts, which - unlikely as they
might be - I'd like to return to my library users as a known error
instead of silent failing.

Revised example, replacing eval with printf -v, thanks:

# Param: $1  variable name to return value to
# Private library function. Do not call directly. See blackbox()
_blackbox() {
# Just don't declare "local __1"
local a b c d e f g h i j
# ...
# Lots of complicated library code here
# ...
# Return value
printf -v $1 %s b
}

# Param: $1  variable name to return value to
# Public library function
blackbox() {
local __1
_blackbox __1
[[ $1 == __1 ]] && echo "ERROR: variable name conflicts"\
"with local variable: $1"
printf -v $1 %s "$__1"
}

blackbox a; echo $a   # Outputs "b" all right
blackbox __1  # Outputs error
d='ls /;true'; blackbox "$d"  # No more oops


Freddy Vulto
http://fvue.nl/wiki/Bash:_passing_variables_by_reference




Re: Passing variables by reference conflicts with local

2010-05-01 Thread Dennis Williamson
Wouldn't you want your name collision test before your call to the
private function - just to save the wasted call? (And to have its
message redirected to stderr and have a "return 1" or other non-zero
value?) Otherwise, I think your idea is a good one, especially if the
public function can be as simple as that.

Thanks, Pierre, by the way, for the workarounds. I hadn't considered
using indirection that way.

On Sat, May 1, 2010 at 6:21 AM, Freddy Vulto  wrote:
> On 100501 12:40, Pierre Gaston wrote:
>> On Sat, May 1, 2010 at 12:26 PM, Dennis Williamson wrote:
>> > As Chet said, use internal variables that are unlikely to conflict.
>> You can use workarounds like:
>> printf -v $a "%s" foobar
>> read $a <<< "%s"
>
> The problem with obfucscated internal variables I think is that my
> library code becomes unnecessary obfuscated.  That's why I'm thinking an
> additional call-layer (workaround 2 in my original mail) is an
> improvement in that the private library code "_blackbox()" can use
> simple, readable variables without restrictions/conflicts, while the
> public layer "blackbox()" checks conflicts, which - unlikely as they
> might be - I'd like to return to my library users as a known error
> instead of silent failing.
>
> Revised example, replacing eval with printf -v, thanks:
>
>    # Param: $1  variable name to return value to
>    # Private library function. Do not call directly. See blackbox()
>    _blackbox() {
>        # Just don't declare "local __1"
>        local a b c d e f g h i j
>        # ...
>        # Lots of complicated library code here
>        # ...
>        # Return value
>        printf -v $1 %s b
>    }
>
>    # Param: $1  variable name to return value to
>    # Public library function
>    blackbox() {
>        local __1
>        _blackbox __1
>        [[ $1 == __1 ]] && echo "ERROR: variable name conflicts"\
>                "with local variable: $1"
>        printf -v $1 %s "$__1"
>    }
>
>    blackbox a; echo $a           # Outputs "b" all right
>    blackbox __1                  # Outputs error
>    d='ls /;true'; blackbox "$d"  # No more oops
>
>
> Freddy Vulto
> http://fvue.nl/wiki/Bash:_passing_variables_by_reference
>
>
>




Weird "/dev/fd/62: Permission denied"

2010-05-01 Thread No Name

The following  $ while read l ; do continue; done < <(ls -l / 2>/dev/null)fails 
on:  BASH_VERSINFO=4  BASH_VERSION=4.1.2(1)-release  SHLVL=1  (the machine I'm 
on doesn't have bashbug).with  """-bash: /dev/fd/62: Permission denied"""and 
not on bash3, bash2. And not on bash4 with a $SHLVL -gt 1.
Initially I was trying to narrow down a problem around some code that would 
work just fine on bash2, but fail on bash4 after almost 1h (~1800 invocations 
of that while loop) with:  """/home/jpa/myscript.sh: redirection error: cannot 
duplicate fd: Too many open files"""Interestingly, taking the command which is 
having the redirection issue fails at SHLVL 1 outright.
--jpa
  
_
The New Busy think 9 to 5 is a cute idea. Combine multiple calendars with 
Hotmail. 
http://www.windowslive.com/campaign/thenewbusy?tile=multicalendar&ocid=PID28326::T:WLMTAGL:ON:WL:en-US:WM_HMP:042010_5

Re: completion gobbles partial match string

2010-05-01 Thread Chet Ramey
On 4/30/10 2:51 AM, jida...@jidanni.org wrote:
> Put the cursor after the word "list" and hit TAB:
> # find /etc/apt/sources.list.d/*list #|cpio -o|ssh 192.168.44.4 cpio -ivdm
> Emacssources.list  eeepc.list tw.list
> # find /etc/apt/sources.list.d/ #|cpio -o|ssh 192.168.44.4 cpio -ivdm
> 
> Notice how we are shown the completions, but then the "*list" has been
> gobbled up!
> BASH_VERSION='4.1.5(1)-release'

Yep.  Readline relies on matching prefixes: if there are multiple
completions, it replaces the word to be completed with the longest
common prefix.  In this case, there isn't one.

The builtin bash completion won't perform replacement when a globbing
pattern expands to more than one filename, even when they share a common
prefix.  I have to assume that you're using programmable completion,
and the compspec for `find' doesn't impose the same restriction.
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/




Re: Passing variables by reference conflicts with local

2010-05-01 Thread Freddy Vulto
Here's another revised version.

It seems like a lot of bookkeeping (I wish we could transfer to bash?),
but I don't see another way if you want to pass "variables by reference"
in a bash library and prevent both yourself and public users from being
bitten by a conflict with a local variable - other than obfuscating your
library local variables.

I hope we can get it right, so it can be used with a revised version of
the `_get_cword' function of the bash-completion package (= blackbox).

There are still some questions:

I have to give local variables a value (append an equal sign) in order
to get them listed with 'local' in "blackbox()".  Is there a bash
builtin which lists all defined local variable names, even those not
having a value yet?

I also want to let 'blackbox' return array variables, which doesn't seem
to be possible with the 'printf/read' workarounds, so I have to use
'eval' and still need to sanitize the array variable names.  What's
considered good sanitizing: I'm now checkin for $' \n\t;:$' in
"_blackbox_var_sane()"?

Other changes are:

Called private function _after_ collission test.

Output error messages to stderr and return non-zero value.

Added check to enforce private function "_blackbox()" is ALWAYS called
via public "blackbox()".

I thought about whether private function "_blackbox()" should also have
a check for having local conflicts, but I figured this should be covered
by blackbox unit tests :-)

Added an input parameter and return value for the sake of completeness.

Here's the code:

# Output error of variable by reference conflicting with local
# Params: $1  Variable name causing conflict
# $2  Function in which conflict occurs
_blackbox_var_conflict() {
echo "ERROR: variable name conflicts with local variable:"\
"'$1', in function: $2()" 1>&2
}

# Check whether private function is being called by public interface
# Params: $1  Function name of public interface
# Return: False (1) if error
_blackbox_called_by() {
if [[ ${FUNCNAME[2]} != $1 ]]; then
echo "ERROR: ${FUNCNAME[1]}() MUST be called by $1()" 1>&2
return 1
fi
}

# Check whether variable is sane to be used as eval assignment
# Param:  $1  Variable name
# Return: False (1) if not sane
_blackbox_var_sane() {
if [[ ! $1 || ${1//[$' \n\t;:$']} != $1 ]]; then
echo "ERROR: invalid identifier: '$1'"\
"passed to function: ${FUNCNAME[1]}()" 1>&2
return 1
fi
}

# Private library function. Do not call directly. See blackbox()
_blackbox() {
_blackbox_called_by blackbox || return 1
local a b c d e f g h i j arr=( foo "bar cee" )
# ...
# Lots of complicated library code here
# ...
[[ $2 ]] && printf -v $2 %s b# Return value
_blackbox_var_sane "$3" &&   # Return array value
eval $3=\( \"\${a...@]}\" \) || return 1
return 0 # Return exit status
}

# Param: $1  input argument
# Param: $2  variable name to return value to
# Param: $3  variable name to return array value to
# Public library function
blackbox() {
# NOTE: Give all locals a value so they're listed with 'local'
local __2= __3= __x= __v= IFS=$'\n'
# Check arguments conflicting with locals
for __v in $(local); do
case ${__v%=*} in $2|$3)
_blackbox_var_conflict ${__v%=*} $FUNCNAME; return 1;;
esac
done
_blackbox "$1" __2 __3   # Call private function
__x=$?   # Catch exit status
[[ $2 ]] && printf -v $2 %s "$__2"   # Return value
_blackbox_var_sane "$3" &&   # Return array value
eval $3=\( \"\${_...@]}\" \) || return 1
return $__x  # Return exit status
}

blackbox i a b; printf $'%s\n' $a "$...@]}"  # Outputs vars all right
blackbox i __2 __3   # Outputs error
d='ls /;true'; blackbox i "$d" "$d"  # No oops
_blackbox a  # Force public access


Freddy Vulto
http://fvue.nl/wiki/Bash:_passing_variables_by_reference




Re: completion gobbles partial match string

2010-05-01 Thread jidanni
> "CR" == Chet Ramey  writes:
CR> I have to assume that you're using programmable completion,
CR> and the compspec for `find' doesn't impose the same restriction.
Same happens with cat or ":", not only find. It doesn't happen for
# su - nobody
And I've isolated the problem to somewhere in this chunk of $INPUTRC:
set history-preserve-point on
set visible-stats on
set show-all-if-ambiguous on
set meta-flag on
set convert-meta off
set input-meta on
set output-meta on




Re: Passing variables by reference conflicts with local

2010-05-01 Thread Dennis Williamson
In Bash 3.2.0(1)-release, "local" displays local variables that do and
do not have values. In Bash 4.0.33(1)-release and 4.1.0(1)-release
only those with values are printed. Oops.

f () { local var1 var2=abc var3=; local; }; f

Bash 3:
var1=
var2=abc
var3=

Bash 4:
var2=abc
var3=

So it looks like the only way is to use "local var=" instead of "local var".

I can understand the desire to have blackbox_var_sane "$3" called near
the eval, but it seems to me to make sense to have it fail early
rather than waste "# Lots of complicated library code here" first.
This also applies to the placement in the public function.

You might consider sanitizing using something like this: [[ $1 =~
[_[:alpha:]][_[:alnum:]]* ]] then you won't have to worry that you're
forgetting something.

On Sat, May 1, 2010 at 5:19 PM, Freddy Vulto  wrote:
> Here's another revised version.
>
> It seems like a lot of bookkeeping (I wish we could transfer to bash?),
> but I don't see another way if you want to pass "variables by reference"
> in a bash library and prevent both yourself and public users from being
> bitten by a conflict with a local variable - other than obfuscating your
> library local variables.
>
> I hope we can get it right, so it can be used with a revised version of
> the `_get_cword' function of the bash-completion package (= blackbox).
>
> There are still some questions:
>
> I have to give local variables a value (append an equal sign) in order
> to get them listed with 'local' in "blackbox()".  Is there a bash
> builtin which lists all defined local variable names, even those not
> having a value yet?
>
> I also want to let 'blackbox' return array variables, which doesn't seem
> to be possible with the 'printf/read' workarounds, so I have to use
> 'eval' and still need to sanitize the array variable names.  What's
> considered good sanitizing: I'm now checkin for $' \n\t;:$' in
> "_blackbox_var_sane()"?
>
> Other changes are:
>
> Called private function _after_ collission test.
>
> Output error messages to stderr and return non-zero value.
>
> Added check to enforce private function "_blackbox()" is ALWAYS called
> via public "blackbox()".
>
> I thought about whether private function "_blackbox()" should also have
> a check for having local conflicts, but I figured this should be covered
> by blackbox unit tests :-)
>
> Added an input parameter and return value for the sake of completeness.
>
> Here's the code:
>
>    # Output error of variable by reference conflicting with local
>    # Params: $1  Variable name causing conflict
>    #         $2  Function in which conflict occurs
>    _blackbox_var_conflict() {
>        echo "ERROR: variable name conflicts with local variable:"\
>            "'$1', in function: $2()" 1>&2
>    }
>
>    # Check whether private function is being called by public interface
>    # Params: $1  Function name of public interface
>    # Return: False (1) if error
>    _blackbox_called_by() {
>        if [[ ${FUNCNAME[2]} != $1 ]]; then
>            echo "ERROR: ${FUNCNAME[1]}() MUST be called by $1()" 1>&2
>            return 1
>        fi
>    }
>
>    # Check whether variable is sane to be used as eval assignment
>    # Param:  $1  Variable name
>    # Return: False (1) if not sane
>    _blackbox_var_sane() {
>        if [[ ! $1 || ${1//[$' \n\t;:$']} != $1 ]]; then
>            echo "ERROR: invalid identifier: '$1'"\
>                "passed to function: ${FUNCNAME[1]}()" 1>&2
>            return 1
>        fi
>    }
>
>    # Private library function. Do not call directly. See blackbox()
>    _blackbox() {
>        _blackbox_called_by blackbox || return 1
>        local a b c d e f g h i j arr=( foo "bar cee" )
>        # ...
>        # Lots of complicated library code here
>        # ...
>        [[ $2 ]] && printf -v $2 %s b            # Return value
>        _blackbox_var_sane "$3" &&               # Return array value
>            eval $3=\( \"\${a...@]}\" \) || return 1
>        return 0                                 # Return exit status
>    }
>
>    # Param: $1  input argument
>    # Param: $2  variable name to return value to
>    # Param: $3  variable name to return array value to
>    # Public library function
>    blackbox() {
>        # NOTE: Give all locals a value so they're listed with 'local'
>        local __2= __3= __x= __v= IFS=$'\n'
>        # Check arguments conflicting with locals
>        for __v in $(local); do
>            case ${__v%=*} in $2|$3)
>                _blackbox_var_conflict ${__v%=*} $FUNCNAME; return 1;;
>            esac
>        done
>        _blackbox "$1" __2 __3                   # Call private function
>        __x=$?                                   # Catch exit status
>        [[ $2 ]] && printf -v $2 %s "$__2"       # Return value
>        _blackbox_var_sane "$3" &&               # Return array value
>            eval $3=\( \"\${_...@]}\" \) || return 1
>        return $__x                              # Return exit status
>    }
>
>    b