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

Re: Doesn't MY_ENV=abc printf "${MY_ENV}\n" suppose to print abc?



On Sun, Aug 03, 2003 at 01:50:18AM +0300, Shaul Karl wrote:
>   Your proposal has some side effects which might be undesirable. More
> specifically, with your proposal MY_ENV will be set until you
> explicitly unset it or exit the shell. With what I tried to do, MY_ENV
> will only be set for the following command. There will be no need to
> explicitly unset it or exit the shell in order for it to disappear
> afterwards. In addition, the construct I am trying to use is a well
> known construct and the man page says it should work. Is it a bug?

I think you're a little confused on how the shell does variable
expansion. Anything in soft quotes (the double quote) is expanded before
the command is executed. Thus, the value of MY_ENV is expanded before
the printf program is run. The printf command *does* have the MY_ENV
variable in its environment; it just doesn't use it.

If you read the man page more closely, you'll see that it explicitly
says that what you want will *not* work. Specifically:

   SIMPLE COMMAND EXPANSION
       When  a  simple  command  is executed, the shell performs the following
       expansions, assignments, and redirections, from left to right.
                                                                                
       1.     The words that the parser has  marked  as  variable  assignments
              (those  preceding  the  command name) and redirections are saved
              for later processing.
                                                                                
       2.     The words that are not variable assignments or redirections  are
              expanded.   If  any words remain after expansion, the first word
              is taken to be the name of the command and the  remaining  words
              are the arguments.

       3.     Redirections are performed as described above under REDIRECTION.
                                                                                
       4.     The text after the = in each variable assignment undergoes tilde
              expansion, parameter expansion, command substitution, arithmetic
              expansion, and quote removal before being assigned to the  vari-
              able.

       If no command name results, the variable assignments affect the current
       shell environment.  Otherwise, the variables are added to the  environ-
       ment  of the executed command and do not affect the current shell envi-
       ronment.  If any of the assignments attempts to assign  a  value  to  a
       readonly  variable,  an error occurs, and the command exits with a non-
       zero status.

Thus, the variables are not assigned until step 4, while the expansion
is done in step 2. In addition, pay extra attention to the last
paragraph, which says "variables are added to the environment of the
executed command and do not affect the current shell environment".

Using your original problem as an example:

  MY_ENV=foo printf "${MY_ENV}\n"

Step 1, set aside variable assignments, leaving

  printf "${MY_ENV}\n"

Step 2, expand variables, leaving

  printf "\n"

Step 3, perform redirections (none applicable).

Step 4, expand variable assignments and add them to the environment of
the printf command (NOT to the environment of the shell) and run the
command.

Thus, printf runs with a single parameter (``\n'') and with MY_ENV in
its environment.

Here's what happens if you try to prevent expansion by using hard
quotes:

 $ MY_ENV=abc printf 'My env is ${MY_ENV}\n'
 My env is ${MY_ENV}

So you see, printf doesn't actually handle environment variables. If you
want a demonstration that this really works the way it's documented, you
need to run a program that lets you examine environment variables. 

Observe:

  # FOO is unset
  $ echo $FOO
   
  $ env | grep FOO
  $ perl -e 'print $ENV{FOO}, "\n";'
   
  # Now, set FOO as a local shell variable
  $ FOO=bar
  $ env | grep FOO
  $ perl -e 'print $ENV{FOO}, "\n";'
  
  # Now, export FOO to the environment
  $ export FOO
  $ env | grep FOO
  FOO=bar
  $ perl -e 'print $ENV{FOO}, "\n";'
  bar
  # Un-set FOO
  $ unset FOO
  $ env | grep FOO
  $ perl -e 'print $ENV{FOO}, "\n";'
  
  # Now, use variable assignment notation to set FOO for a subcommand
  $ FOO=bar env | grep FOO
  FOO=bar
  $ FOO=bar perl -e 'print $ENV{FOO}, "\n";'
  bar
  # Note that FOO is still not set in the current shell
  $ echo $FOO
   
  $ env | grep FOO
  $

-- 
Dave Carrigan
Seattle, WA, USA
dave@rudedog.org | http://www.rudedog.org/ | ICQ:161669680
UNIX-Apache-Perl-Linux-Firewalls-LDAP-C-C++-DNS-PalmOS-PostgreSQL-MySQL



Reply to: