Yes, _
is an environment variable of the new Bash shell; you can see that by running
tr '\0' '\n' < /proc/$$/environ | grep _=
inside the shell: that shows the contents of the shell’s initial environment. You won’t see it in the first shell because there wasn’t a previous shell to set it before it started.
Expanding $_
inside Bash refers to the _
special parameter, which expands to the last argument of the previous command. (Internally Bash handles this by using a _
shell variable, which is updated every time a command is parsed, but that’s really an implementation detail. It is “unexported” every time a command is parsed.) export
doesn’t show _
because it isn’t a variable which is marked as exported; you can however see it in the output of set
.
In the first example, the new Bash shell parses and executes the commands in its startup files, so when running explore | grep '-='
, _
has already been overwritten and marked as not exported.
In the dash
example, it doesn't seem to execute any start-up file, so you’re seeing the variable as an environment variable that was set by Bash before running dash
.
These curly braces are left alone by bash; they belong to find
and xargs
, respectively, and are described in their man-pages.
man find
-exec
command ;
Execute command; true if 0 status is returned. All following arguments to find are
taken to be arguments to the command until an argument consisting of ;
is encountered. The string {}
is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is
alone, as in some versions of find
. Both of these constructions might need to be
escaped (with a \
) or quoted to protect them from expansion by the shell. See
the EXAMPLES section for examples of the use of the -exec
option. The specified
command is run once for each matched file. The command is executed in the starting
directory. There are unavoidable security problems surrounding use of the -exec
action; you should use the -execdir
option instead.
-exec
command {}
+
This variant of the -exec
action runs the specified command on the selected files,
but the command line is built by appending each selected file name at the end; the
total number of invocations of the command will be much less than the number of
matched files. The command line is built in much the same way that xargs
builds
its command lines. Only one instance of {}
is allowed within the command. The
command is executed in the starting directory. If find
encounters an error, this
can sometimes cause an immediate exit, so some pending commands may not be run at
all. This variant of -exec
always returns true.
-execdir
command ;
-execdir
command {}
+
Like -exec
, but the specified command is run from the subdirectory containing the
matched file, which is not normally the directory in which you started find. This
a much more secure method for invoking commands, as it avoids race conditions during resolution of the paths to the matched files. As with the -exec
action, the
+
form of -execdir
will build a command line to process more than one matched
file, but any given invocation of command will only list files that exist in the
same subdirectory. If you use this option, you must ensure that your $PATH
environment variable does not reference .
; otherwise, an attacker can run any commands they like by leaving an appropriately-named file in a directory in which you
will run -execdir
. The same applies to having entries in $PATH
which are empty or
which are not absolute directory names. If find
encounters an error, this can
sometimes cause an immediate exit, so some pending commands may not be run at all.
The result of the action depends on whether the +
or the ;
variant is being used;
-execdir
command {}
+
always returns true, while -execdir
command {}
;
returns true
only if command returns 0.
man xargs
-I
replace-str
Replace occurrences of replace-str in the initial-arguments with names read from
standard input. Also, unquoted blanks do not terminate input items; instead the
separator is the newline character. Implies -x
and -L
1
.
-i
[replace-str], --replace
[=
replace-str]
This option is a synonym for -I
replace-str if replace-str is specified. If the replace-str argument is missing, the effect is the same as -I{}
. This option is deprecated; use -I
instead.
Edit: and here WHY bash ignores those curly braces:
man bash
{
list;
}
list is simply executed in the current shell environment. list must be terminated with a newline or semicolon. This is known as a group command. The return status is the exit status of
list. Note that unlike the metacharacters ( and ), { and } are reserved words and must occur
where a reserved word is permitted to be recognized. Since they do not cause a word break,
they must be separated from list by whitespace or another shell metacharacter.
For emphasis: list must be terminated with a newline or semicolon.
Best Answer
You can basically use it anytime you want to "inject" the environment variables passed into a shell script (as arguments) as if they were set within the environment via
export
, but without having to have them permanently reside inexport
's list prior to running commands.NOTE: There's also the long form of the
-k
switch,set -o keyword
.Example
Now if I
set -k
:But if I just were to run the above script:
What's export doing?
So if we were to add
export | grep VAR
to our script like so:And we ran our above tests again:
But without
set -k
:So
set -k
is allowing us to temporarily export variables in mass.Another example
When we set multiple variables they're all exported:
So then it's just injecting all the environment variables?
No
-k
is doing a very explicit thing here. It's only exporting variables that were included on the command line when a command was executed.Example
Say I set this variable:
Now when we run the same command omitting
VARCMD1="hi"
:But why does this exist?
I found this source which explains a bit about this feature, titled: "Keyword Parameter Assignment Strings". NOTE: The source URL uses an IP address so I cannot link to it directly here on SE.