export
makes a variable something that will be included in child process environments. It does not affect other already existing environments. In general there isn't a way to set a variable in one terminal and have it automatically appear in another terminal, the environment is established for each process on its own.
Adding it to your .profile
makes it so that your environment will be setup to include that new variable each time you log in though. So it's not being exported from one shell to another, but instead is instructing a new shell to include it when it sets up the initial environment.
Then answer is that sudo
has a bug. First, the workaround: I put this in my /etc/sudoers.d/zabbix file
:
zabbix ALL=(root) NOPASSWD: /bin/env SHELL=/bin/sh /usr/local/bin/zabbix_raid_discovery
and now subcommands called from zabbix_raid_discovery
work.
A patch to fix this will be in sudo 1.8.15. From the maintainer, Todd Miller:
This is just a case of "it's always been like that". There's not
really a good reason for it. The diff below should make the behavior
match the documentation.
- todd
diff -r adb927ad5e86 plugins/sudoers/env.c
--- a/plugins/sudoers/env.c Tue Oct 06 09:33:27 2015 -0600
+++ b/plugins/sudoers/env.c Tue Oct 06 10:04:03 2015 -0600
@@ -939,8 +939,6 @@
CHECK_SETENV2("USERNAME", runas_pw->pw_name,
ISSET(didvar, DID_USERNAME), true);
} else {
- if (!ISSET(didvar, DID_SHELL))
- CHECK_SETENV2("SHELL", sudo_user.pw->pw_shell, false, true);
/* We will set LOGNAME later in the def_set_logname case. */
if (!def_set_logname) {
if (!ISSET(didvar, DID_LOGNAME))
@@ -984,6 +982,8 @@
if (!env_should_delete(*ep)) {
if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
ps1 = *ep + 5;
+ else if (strncmp(*ep, "SHELL=", 6) == 0)
+ SET(didvar, DID_SHELL);
else if (strncmp(*ep, "PATH=", 5) == 0)
SET(didvar, DID_PATH);
else if (strncmp(*ep, "TERM=", 5) == 0)
@@ -1039,7 +1039,9 @@
if (reset_home)
CHECK_SETENV2("HOME", runas_pw->pw_dir, true, true);
- /* Provide default values for $TERM and $PATH if they are not set. */
+ /* Provide default values for $SHELL, $TERM and $PATH if not set. */
+ if (!ISSET(didvar, DID_SHELL))
+ CHECK_SETENV2("SHELL", runas_pw->pw_shell, false, false);
if (!ISSET(didvar, DID_TERM))
CHECK_PUTENV("TERM=unknown", false, false);
if (!ISSET(didvar, DID_PATH))
Best Answer
The
_=
at the start of a line in the output of plain set means that there is a variable called_
(underscore) in bash. And its value is what follows the=
. Like setting a variable namedtest_var
to12345
will yield (in bash):That special bash variable will be set to the last argument of the previous line:
Note the two
=
in that output.Longer description
When you execute
set -a var=99
, three distinct things happen (related to your question):-a
) (reverse by doingset +a
) to export vars.$1
set tovar=99
).$_
is set to the last parameter (expanded).set -a
The execution of
set -a
marks all subsequent (new or changed) variables as exported (in all shells, exceptcsh
and some related shells).To recover from this setting, just change the
-
to a+
:set var=99
Which should actually be
set -- var=99
to avoid interpretation of an option (and set has a lot) with values that start with a dash (-
).Sets the list of arguments (the list of positional parameters) to that after the
--
. That is valid in all reasonable shells (not in csh et al). Positional arguments are printed with "$@" (or similar "$*", not equal).#_=last_argument And, the value of the internal shell variable
_
change to the last argument of the executed line. That is NOT true in almost all shells (jsh, ash, yash, dash, lksh, mksh, ksh93, attsh and of course csh and tcsh) except bash.Please note that the value in
$_
is the value after expansion:That's why when you execute:
You get a description of the shell variable '$_'. This also works: