Namespace problem with pipe into a braced group

2010-02-23 Thread tobi
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc -I/usr/src/packages/BUILD/bash-3.1 
-L/usr/src/packages/BUILD/bash-3.1/../readline-5.1
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-suse-linux-gnu' 
-DCONF_VENDOR='suse' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL 
-DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib   -O2 -fmessage-length=0 -Wall 
-D_FORTIFY_SOURCE=2 -g -D_GNU_SOURCE -DRECYCLES_PIDS -Wall -pipe -g -fPIE 
-fbranch-probabilities
uname output: Linux t60 2.6.18.8-0.13-default #1 SMP Thu Nov 6 13:35:13 UTC 
2008 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-suse-linux-gnu

Bash Version: 3.1
Patch Level: 17
Release Status: release

Description:
I would have expected the output to be 2 in both cases.  My mistake or 
yours?  :-)

Repeat-By:
a=1; echo foo;{ a=2; }; echo $a # output: 2
a=1; echo foo|{ a=2; }; echo $a # output: 1

Bug or feature?




Re: SHELLOPTS environment variable causes shell options to cascade

2025-01-06 Thread Tobi Laskowski
> | It is not possible to have a naive SHELLOPTS=myopt configured outside
> | the shell without all future options being exported implicitly.

> I have never used SHELLOPTS, and have never tested this, but:

> Does "unset SHELLOPTS" not work?

It gives:

bash: unset: SHELLOPTS: cannot unset: readonly variable

> ps: as it is safe, and portable, to unset variables that are not
> set, in any shell, there's no reason not to include the unset in
> all sh scripts, whatever shell variant they are to be interpreted by.

It may be safe, however, it is a bit tedious to such an extent where it seems 
like it's a misuse of SHELLOPTS to try to pre-initialise as an environment 
variable like this to enable an option.


Re: SHELLOPTS environment variable causes shell options to cascade

2025-01-07 Thread Tobi Laskowski
> This precdence question is really the only one. Is this issue serious
> enough to change previous behavior in an incompatible way?

To me it seems most intuitive for flags to be applied after the environment 
variable, but I do not mind too much about this.

> No. That is not consistent with the historical behavior of SHELLOPTS,
> and not consistent with the behavior of environment variables.

Agreed, thanks for the detailed explanations. I see now that the patch does not 
make sense and would only make things more confusing.

> I'm not sure why the setup-ocaml authors chose the method they did, but
> it seems like that's where this issue starts. 

Yes, given that there is this side effect of storing what is normally a shell 
variable in the environment instead, this does not seem like the correct way to 
achieve the goal of a globally set option.

> Maybe they could change things to run `export -n SHELLOPTS' where appropriate.

There is not really a good place to put these  `export -n SHELLOPTS` lines in 
this case. Users of setup-ocaml would have to add these lines to their bash 
scripts which does not seem like a good solution. I think, as you've said, the 
issue starts with misusing SHELLOPTS.


Re: SHELLOPTS environment variable causes shell options to cascade

2025-01-07 Thread Tobi Laskowski
> This is already documented in a couple of different places:

Thanks for providing the relevant sections. This makes sense having read things 
more thoroughly, however, most people do not read documentation from top to 
bottom. Someone looking for a way to enable a shell option globally will likely 
find the SHELLOPTS documentation which says:

> If this variable is in the environment when Bash starts up, each shell option 
> in the list will be enabled before reading any startup files.

This line gives the impression that using SHELLOPTS the way setup-ocaml is 
using it is a reasonable idea, and does not give any indication that doing so 
is going to change shell option behaviour. From my perspective, it would be 
helpful to have had a line here that might discourage such misuse of SHELLOPTS, 
or at least point a user to read the other relevant sections before trying to 
add it to the environment. This way, the behaviour wouldn't come as a surprise.

Here is another project that fell into the same trap: 
https://github.com/infertux/bashcov/issues/50.

--
Tobi


SHELLOPTS environment variable causes shell options to cascade

2025-01-04 Thread Tobi Laskowski
Hello,

I'd like to ask about an odd behaviour relating to the SHELLOPTS environment 
variable. This is present in version 5.2.37(1)-release and in the development 
version.

In this case, the `nounset` option is only applied to the current shell and not 
to nested bash invocations:
> set -o nounset; echo $SHELLOPTS; bash -c "echo \$SHELLOPTS"

On the other hand, if there is a pre-existing SHELLOPTS environment variable 
(set outside the current shell), then the `nounset` option applies to all 
invocations of bash within the current shell. Even with the `+u` flag, it is 
not possible to avoid the `nounset` option being applied to the inner bash 
invocation.

The specific case where I found this behaviour to be problematic is in 
setup-ocaml, which is a github action: 
https://github.com/ocaml/setup-ocaml/pull/915. It applies "SHELLOPTS=igncr" 
globally so that it affects all cygwin bash invocations, however, a side effect 
is that other shell options set via bash option flags cascade down into nested 
bash invocations. Specifically, the `nounset` option applies to places where it 
didn't previously apply (which breaks a configure script of libuv). I know 
`igncr` only applies to cygwin bash, but it can be substituted for any option 
in regular bash and the same behaviour occurs.

To be clear, the intention here was to apply a specific shell option globally 
(namely igncr), and the unintentional side effect was that the behaviour of how 
other shell options are applied has changed.

I'm not sure if this behaviour of SHELLOPTS is intentional, but it is 
definitely confusing particularly from the lens of the given use case. This 
behaviour is not explicitly documented either: 
https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html#index-SHELLOPTS.

It seems the solution would be to either:
1) Document this cascading behaviour of SHELLOPTS, and decide on the correct 
behaviour of +u versus SHELLOPTS=nounset.
or
2) Re-export only the initial value of SHELLOPTS to the new environment, prior 
to modifications due to `set` or bash option flags. I've added a patch below 
that achieves this, if it seems reasonable then I will write a test and format 
it properly as a patch request.

Regards,
Tobi
---
 variables.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/variables.c b/variables.c
index 1a0c2c45..ba65b97f 100644
--- a/variables.c
+++ b/variables.c
@@ -177,6 +177,11 @@ char **export_env = (char **)NULL;
 static int export_env_index;
 static int export_env_size;
 
+/* For the SHELLOPTS environment variable, we must save and re-export
+   the original value as at initialization, ignoring changes resulting from
+   other methods of modifying shell options. */
+static char *shell_opts_value = (char *)NULL;
+
 #if defined (READLINE)
 static int winsize_assignment; /* currently assigning to LINES or 
COLUMNS */
 #endif
@@ -515,7 +520,12 @@ initialize_shell_variables (env, privmode)
  temp_var = bind_variable (name, string, 0);
  if (temp_var)
{
- VSETATTR (temp_var, (att_exported | att_imported));
+ VSETATTR (temp_var, att_imported);
+ if (STREQ (name, "SHELLOPTS"))
+   shell_opts_value = string;
+ else
+   VSETATTR (temp_var, att_exported);
+
  if (ro)
VSETATTR (temp_var, att_readonly);
}
@@ -5129,7 +5139,14 @@ maybe_make_export_env ()
  export_env = strvec_resize (export_env, export_env_size);
  environ = export_env;
}
-  export_env[export_env_index = 0] = (char *)NULL;
+
+  if (shell_opts_value)
+   {
+ export_env[export_env_index = 0] = mk_env_string ("SHELLOPTS", 
shell_opts_value, 0);
+ export_env[export_env_index = 1] = (char *)NULL;
+}
+  else
+export_env[export_env_index = 0] = (char *)NULL;
 
   /* Make a dummy variable context from the temporary_env, stick it on
 the front of shell_variables, call make_var_export_array on the
---


Re: SHELLOPTS environment variable causes shell options to cascade

2025-01-05 Thread Tobi Laskowski
>> On the other hand, if there is a pre-existing SHELLOPTS environment variable 
>> (set outside the current shell), then the `nounset` option applies to all 
>> invocations of bash within the current shell.

> This is documented in the manual:

>> A colon-separated list of enabled shell options.
>> If this variable is in the environment when Bash starts up, each shell 
>> option in the list will be enabled before reading any startup files.

This does not cover the specific behaviour I am concerned with. I would expect 
something like:

"Additionally, if it is in the environment at start up, the variable is 
automatically exported and shell options enabled subsequently through other 
means will be included in the exported value."

I do not find it surprising that the values in SHELLOPTS are applied, I find it 
surprising that the pre-existence of a SHELLOPTS environment variable results 
in any future shell options being "sticky". It is not possible to have a naive 
SHELLOPTS=myopt configured outside the shell without all future options being 
exported implicitly.

Perhaps the problem is that the given use-case abuses SHELLOPTS as if it also 
fulfilled the role of a DEFAULT_SHELLOPTS environment variable, i.e. one that 
sets some initial shell options but does not imply that SHELLOPTS itself should 
be exported.

> Try BASH_ENV instead: 
> https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html#index-BASH_005fENV

If this is the correct way to achieve this, that is fair enough. If SHELLOPTS 
is not intended to be used in this way then I would expect the documentation to 
include enough information that would discourage a user from falling into this 
trap.

--
Tobi