You can inherit the environment variables from PID 1 by iterating over the list of null-terminated strings
in /proc/1/environ
, parsing the first characters up to the first =
as the variable name, setting the
remaining value as that variable, and exporting it.
The Code Snippet
This works with multiline environment variables, and environment variables with arbitrary values, like
strings, including =
or JSON blobs.
Paste this in your current terminal session to inherit the environment variables from PID 1:
while read -r -d $'\0' EVAR ; do
evar_name="$(cut -d'=' -f1 <<< "$EVAR" | head -n1)"
declare $evar_name="${EVAR#${evar_name}=}"
export "$evar_name"
done < /proc/1/environ
Note: This only works with bash
since it uses declare
. But the advantage is that the values
never need to pass through any serialization boundary (like they do when saving to a file, or
printing export
statements to eval them, or various other techniques that don't work for all corner cases )
See also: Unix StackExchange: "How do I source another process's environment variables?"
Why
scenario: You popped a reverse shell in your CI runner and you want to manually run some of your CI scripts. But your SSH session into the CI runner didn't inherit all the environment variables that are available to the actual CI runner. These are set by the CI platform to be environment variables in PID 1.
You can see them with:
cat /proc/1/environ
This file is a concatenation of null-terminated strings of variable assignments. You can reveal the non-printing characters:
cat -vet /proc/1/environ
This is equivalent to cat -v -vE -vT
- it
will show $
for newlines, ^I
for tab characters, and will show non-printing characters,
like the separator ^@
(null byte aka $'\0'
). Note: you probably do not want to parse this
output. It's just useful for debugging and seeing where the separators are.
Why not just
export $(sudo cat /proc/1/environ | tr '\0' '\n' | xargs)
? Is that one of the other techniques you were referring to that fails in some cases?