dash.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* dash unset idiosyncrasies
@ 2015-07-06  2:18 Parke
  2015-07-06  3:23 ` Martijn Dekker
  2015-07-06 16:02 ` Parke
  0 siblings, 2 replies; 3+ messages in thread
From: Parke @ 2015-07-06  2:18 UTC (permalink / raw)
  To: dash

Hi,

The man page for dash says:

     unset [-fv] name ...
            The specified variables and functions are
            unset and unexported.  If -f or -v is speci‐
            fied, the corresponding function or variable
            is unset, respectively.  If a given name cor‐
            responds to both a variable and a function,
            and no options are given, only the variable is
            unset.

The man page does not say what happens if the given name corresponds
only to a function.

Based on experimentation, I have determined that in dash versions
0.5.7, 0.5.8, and git head, "unset name" (without -f) will only unset
variables and will never unset any function.

In addition, during my experiments, I discovered idiosyncrasies that
are demonstrated by the following script.

The script runs a series of tests.  Each test sets a variable and
function, both named "true" (so as to overshadow /bin/true).  The test
then tries to unset either the variable, or the function, or both.
The test then probes the existence of the variable and function, and
compares to the expected result.

----

#! /bin/dash

unit () {

  # $1 is an unset command
  # $2 is the expected result

  n=$(( $n + 1 ))    # $n counts each test

  # define a variable and function named "true".
  # we use "true" because /bin/true will still run
  # successfully even if the function is unset.
  true='var '
  true ()  { echo 'fun' ; }

  # print the test number and the unset command
  printf "%2d  %-30s  "  "$n"  "$1"

  # run the unset command
  $1

  # probe the variable and function
  actual="$true"`true`

  # compare actual to expected
  if [ "$actual" = "$2" ]; then
    printf "   pass\n"
  else
    printf ">> FAIL\n"
    printf "%37s  expect  %s\n" '' "$2"
    printf "%37s  actual  %s\n" '' "$actual"
  fi

}

n=0

unit    'unset'                         'var fun'
unit    'unset       true'              'fun'
unit    'unset -f    true'              'var '
unit    'unset -v    true'              'fun'
unit    'unset -fv   true'              ''
unit    'unset -vf   true'              ''
unit    'unset -f -v true'              ''
unit    'unset -v -f true'              ''
unit    'unset -f true -v true'         ''
unit    'unset -f true -f true'         'var '
unit    'unset -f true -f true -f true' 'var '
unit    'unset -f true -v true -f true' ''
unit    'unset -v true -v true'         'fun'
unit    'unset -v true -f true'         ''

----

Running the above script produces identical output with dash versions
0.5.7, 0.5.8 and git head.  The output is:

 1  unset                              pass
 2  unset       true                   pass
 3  unset -f    true                   pass
 4  unset -v    true                   pass
 5  unset -fv   true                >> FAIL
                                       expect
                                       actual  fun
 6  unset -vf   true                >> FAIL
                                       expect
                                       actual  var
 7  unset -f -v true                >> FAIL
                                       expect
                                       actual  fun
 8  unset -v -f true                >> FAIL
                                       expect
                                       actual  var
 9  unset -f true -v true           >> FAIL
                                       expect
                                       actual  var
10  unset -f true -f true              pass
11  unset -f true -f true -f true      pass
12  unset -f true -v true -f true   >> FAIL
                                       expect
                                       actual  var
13  unset -v true -v true           test.sh: 17: unset: -v: bad variable name

----

In tests 5 through 9, and in test 12, I expect both the variable named
"true" and the function named "true" to be unset.

Unexpectedly, in tests 5 and 7, the function named "true" remains set.

Also unexpectedly, in tests 6, 8, 9, and 12, the variable named "true"
remains set.

Very unexpectedly, the script exits due to a fatal error in the middle
of test 13.  Consequently, test 14 is never run.

Interestingly, there appears to be no way to unset both a variable and
a function with a single unset command.

The following link, apparently to "IEEE Std 1003.1, 2013 Edition", may
be relevant:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset

The current man page in git is here:
http://git.kernel.org/cgit/utils/dash/dash.git/tree/src/dash.1#n2195

Based on my experiments, I would recommend the dash man page be
changed as follows.  Changes are in capital letters.

     unset [-fv] name ...
            The specified VARIABLES OR FUNCITONS
            (BUT NOT BOTH) are
            unset and unexported.  If -f or -v is speci‐
            fied, the corresponding functionS or variableS
            ARE unset, respectively.  IF NEITHER OPTION
            IS GIVEN, ONLY THE NAMED VARIABLES
            ARE UNSET.

Cheers,

Parke

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: dash unset idiosyncrasies
  2015-07-06  2:18 dash unset idiosyncrasies Parke
@ 2015-07-06  3:23 ` Martijn Dekker
  2015-07-06 16:02 ` Parke
  1 sibling, 0 replies; 3+ messages in thread
From: Martijn Dekker @ 2015-07-06  3:23 UTC (permalink / raw)
  To: dash

Parke schreef op 06-07-15 om 04:18:
> The man page does not say what happens if the given name corresponds
> only to a function.

Neither does POSIX, as you've found out: "[...] if a variable by that
name does not exist, it is unspecified whether a function by that name,
if any, shall be unset." I agree the dash man page could do with
clarifying this.

I've found it best, to avoid bugs and confusion, to always use 'unset'
with either the -v or the -f option (but not both). This should work
consistently on all POSIXly shells.

FYI, other shells produce similar output for your test script (except
AT&T ksh halts execution on 'unset' without parameters.) There seem to
be no shells that support unsetting both variables and functions with a
single 'unset' command.

- Martijn


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: dash unset idiosyncrasies
  2015-07-06  2:18 dash unset idiosyncrasies Parke
  2015-07-06  3:23 ` Martijn Dekker
@ 2015-07-06 16:02 ` Parke
  1 sibling, 0 replies; 3+ messages in thread
From: Parke @ 2015-07-06 16:02 UTC (permalink / raw)
  To: dash

On Sun, Jul 5, 2015 at 7:18 PM, Parke <parke.nexus@gmail.com> wrote:

> Based on my experiments, I would recommend the dash man page be
> changed as follows.  Changes are in capital letters.
>
>      unset [-fv] name ...
>             The specified VARIABLES OR FUNCITONS
>             (BUT NOT BOTH) are
>             unset and unexported.  If -f or -v is speci‐
>             fied, the corresponding functionS or variableS
>             ARE unset, respectively.  IF NEITHER OPTION
>             IS GIVEN, ONLY THE NAMED VARIABLES
>             ARE UNSET.

I just realized that, perhaps most importantly, the first line should
be changed to:

unset [ -f | -v ] name ...

Cheers,

Parke

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-07-06 16:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-06  2:18 dash unset idiosyncrasies Parke
2015-07-06  3:23 ` Martijn Dekker
2015-07-06 16:02 ` Parke

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).