回答:
以下は、各環境変数をexport
ステートメントに変換し、シェルに読み込むために適切に引用されます(LS_COLORS
たとえば、セミコロンが含まれている可能性が高いため)。
[ 残念ながら、printf
in /usr/bin
は一般的にサポートしていないため%q
、に組み込まれているものを呼び出す必要がありますbash
。]
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
"$@"
代わりにを使用して、改善してくれてありがとう'{}'
。--
彼の改善された答えの引数について疑問に思う人のために:でbash -c command_string
始まる位置の引数はで始まり、$0
で"$@"
始まる引数を含むように展開されます$1
。引数--
はに割り当てられ$0
ます。
この回答で/proc/$pid/environ
は、指定されたPIDでプロセスの環境を返すシステムを想定しています。変数定義の間にはヌルバイトがあります。(だからLinux、Cygwin、またはSolaris(?))。
export "${(@ps:\000:)$(</proc/$pid/environ)}"
(zshのように非常に単純です:コマンドなしの入力リダイレクト <FILE
はに相当しcat FILE
ます。コマンド置換の出力は、「nullバイトで分割」を意味するフラグ ps:\000:
と@
「すべてが二重引用符で囲まれている場合は、各配列要素を個別のフィールドとして」(一般化"$@"
)。
while IFS= read -r -d "" PWD; do export "$PWD"; done </proc/$pid/environ
PWD=$(pwd)
(これらのシェルでは、空の区切り文字が渡されると、ヌルバイトread
がセパレータになります。PWD
一時変数名として使用して、インポートされる可能性のある別の変数が上書きされるのを防ぎます。技術的にインポートすることもできますがPWD
、次cd
。)
POSIXの移植性は、この質問に対してはそれほど興味深いものではありません/proc/PID/environ
。だから、問題はSolaris sedが何をサポートしているか/proc/PID/environ
、あるいはSolarisが何を使用しているかということです。しかし、それは使用していませんでした。Linuxでは、GNUユーティリティとBusyBoxは両方ともnullセーフですが、注意が必要です。
POSIXの移植性を主張する場合、POSIXテキストユーティリティはどれもヌルバイトを処理する必要がないため、これは困難です。これは、awkがレコード区切り文字としてnullバイトをサポートすることを前提とするソリューションです(nawkとgawkはBusyBox awkと同様にサポートしますが、mawkはサポートしません)。
eval $(</proc/$pid/environ awk -v RS='\0' '{gsub("\047", "\047\\\047\047"); print "export \047" $0 "\047"}')
BusyBox awk(組み込みLinuxシステムで一般的に見られるバージョン)は、nullバイトをサポートしますが、上記のコマンドライン構文ではなく、ブロックに設定RS
すること"\0"
はBEGIN
できません。ただし、サポートしてい-v 'RS="\0"'
ます。理由を調査していませんが、これは私のバージョンのバグのようです(Debian wheezy)。
(値内の単一引用符をエスケープした後、すべての行をヌルで区切られたレコードを単一引用符"\047"
でラップします。)
これらのいずれかが読み取り専用変数を設定しようとする可能性があることに注意してください(シェルに読み取り専用変数がある場合)。
これでぐるぐる回りました。nullバイトの移植性に不満を感じました。シェルでそれらを処理するための信頼できる方法がなかったということは、私にはうまくいきませんでした。だから私は見続けました。真実は、これを行うためのいくつかの方法を見つけたということです。そのうちのいくつかだけが、他の回答に記載されています。しかし、結果は次のように機能する少なくとも2つのシェル関数でした。
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
最初に、\0
区切りについて説明します。実際には非常に簡単です。関数は次のとおりです。
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
基本的od
にstdin
、stdout
受信した各バイトを1行に16進数で1つずつ受け取り、書き込みます。
printf 'This\0is\0a\0lot\0\of\0\nulls.' |
od -t x1 -w1 -v
#output
0000000 54
0000001 68
0000002 69
0000003 73
0000004 00
0000005 69
0000006 73
#and so on
どちらが\0null
正しいか推測できると思いますよね?anyで 簡単に扱えるように書かれていますsed
。sed
nullが見つかるまで各行の最後の2文字を保存するだけで、その時点で中間改行をわかりprintf
やすいフォーマットコードに置き換え、文字列を出力します。結果は、\0null
16進バイト文字列の区切り配列です。見て:
printf %b\\n $(printf 'Fewer\0nulls\0here\0.' |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x77\x65\x72
\x6e\x75\x6c\x6c\x73
\x68\x65\x72\x65
\x2e
Fewer
nulls
here
.
tee
コマンドの置換の出力とprintf
の処理結果の両方を見ることができるように、上記をパイプしました。サブシェルも実際には引用符で囲まれておらずprintf
、\0null
区切り文字でのみ分割されていることに気づくと思います。見て:
printf %b\\n $(printf \
"Fe\n\"w\"er\0'nu\t'll\\'s\0h ere\0." |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x0a\x22\x77\x22\x65\x72
\x27\x6e\x75\x09\x27\x6c\x6c\x27\x73
\x68\x20\x20\x20\x20\x65\x72\x65
\x2e
Fe
"w"er
'nu 'll's
h ere
.
その展開にも引用符はありません-引用するかどうかは関係ありません。これは、文字列を印刷する\n
たびに生成される1つのewline を除き、バイト値が分離されずに通過するためsed
です。単語分割は適用されません。そして、それがこれを可能にします:
_pidenv() { ps -p $1 >/dev/null 2>&1 &&
[ -z "${1#"$psrc"}" ] && . /dev/fd/3 ||
cat <&3 ; unset psrc pcat
} 3<<STATE
$( [ -z "${1#${pcat=$psrc}}" ] &&
pcat='$(printf %%b "%s")' || pcat="%b"
xeq="$(printf '\\x%x' "'=")"
for x in $( _zedlmt </proc/$1/environ ) ; do
printf "%b=$pcat\n" "${x%%"$xeq"*}" "${x#*"$xeq"}"
done)
#END
STATE
上記の関数は_zedlmt
、${pcat}
で見つけることができるプロセスの環境ソースのためのバイトコードの準備されたストリーム/proc
、または.dot
${psrc}
現在のシェルで直接同じ、またはパラメータなしで、同じような処理された出力を端末に表示するために使用しますset
またはprintenv
意志。必要なのはある$pid
- すべての読み込み可能な/proc/$pid/environ
ファイルが行います。
次のように使用します。
#output like printenv for any running process
_pidenv $pid
#save human friendly env file
_pidenv $pid >/preparsed/env/file
#save unparsed file for sourcing at any time
_pidenv ${pcat=$pid} >/sourcable/env.save
#.dot source any pid's $env from any file stream
_pidenv ${pcat=$pid} | sh -c '. /dev/stdin'
#feed any pid's env in on a heredoc filedescriptor
su -c '. /dev/fd/4' 4<<ENV
$( _pidenv ${pcat=$pid} )
ENV
#.dot sources any $pid's $env in the current shell
_pidenv ${psrc=$pid}
しかし、人間に優しいものと調達可能なものの違いは何ですか?さて、ここでの違いは、この答えを他のすべてのものとは違うものにしていることです-私の他のものも含めて。他のすべての答えは、すべてのエッジケースを処理するために何らかの方法でシェルクォートに依存しています。それは単にうまく機能しません。私を信じてください- 私はトライしました。見て:
_pidenv ${pcat=$$}
#output
LC_COLLATE=$(printf %b "\x43")
GREP_COLOR=$(printf %b "\x33\x37\x3b\x34\x35")
GREP_OPTIONS=$(printf %b "\x2d\x2d\x63\x6f\x6c\x6f\x72\x3d\x61\x75\x74\x6f")
LESS_TERMCAP_mb=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_md=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_me=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_se=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_so=$(printf %b "\x1b\x5b\x30\x30\x3b\x34\x37\x3b\x33\x30\x6d")
LESS_TERMCAP_ue=$(printf %b "\x1b\x5b\x30\x6d")
NO各値のバイトは、コンテンツが供給されて非常にインスタントまで評価されないので、ファンキーな文字の量や引用含んでいたが、これを破ることはできません。そして、それが少なくとも一度は値として機能したことは既に知っています。これは、元の値のバイト単位のコピーであるため、ここでは解析や引用の保護は必要ありません。
関数は最初に$var
名前を評価し、チェックが完了するのを待って.dot
から、file-descriptor 3 に渡されたhere-docをソースします。それは誰にでもできることです。そしてPOSIXポータブル。少なくとも、\ 0nullの処理はPOSIXポータブルです-/ processファイルシステムは明らかにLinux固有です。そして、それが2つの機能がある理由です。
使用source
およびプロセス置換:
source <(sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ)
まもなく:
. <(sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ)
eval
とコマンド置換の使用:
eval `sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ`
sed
呼び出しは置き換えることができますawk
呼び出し:
awk -vRS='\x00' '{ print "export", $0 }' /proc/1/environ
ただし、pid 1にない環境変数はクリアされないことを忘れないでください。
プロセスは、有効なBash / Sh / * sh変数ではない環境変数を持つことができることに注意する価値があります。POSIXは、環境変数の名前が一致することを推奨しますが、必須ではありません^[a-zA-Z0-9_][a-zA-Z0-9_]*$
。
別のプロセスの環境からシェル互換の変数のリストを生成するには、Bashで:
function env_from_proc {
local pid="$1" skipped=( )
cat /proc/"$pid"/environ | while read -r -d "" record
do
if [[ $record =~ ^[a-zA-Z_][a-zA-Z0-9_]*= ]]
then printf "export %q\n" "$record"
else skipped+=( "$record" )
fi
done
echo "Skipped non-shell-compatible vars: ${skipped[@]%%=*}" >&2
}
同様に、それらをロードするには:
function env_from_proc {
local pid="$1" skipped=( )
while read -r -d "" record
do
if [[ $record =~ ^[a-zA-Z_][a-zA-Z0-9_]*= ]]
then export "$(printf %q "$record")"
else skipped+=( "$record" )
fi
done < /proc/"$pid"/environ
echo "Skipped non-shell-compatible vars: ${skipped[@]%%=*}" >&2
}
この問題はときどき発生しますが、発生した場合は...
これはPOSIXポータブルだと思います:
. <<ENV /dev/stdin
$(sed -n 'H;${x;s/\(^\|\x00\)\([^=]*.\)\([^\x00]*\)/\2\x27\3\x27\n/gp}' \
/proc/$pid/environ)
ENV
しかし、@ Gillesは良い点を示します- sed
おそらくヌルを処理しますが、そうでないかもしれません。したがって、実際にはPOSIXポータブルメソッドもあります(今回は本当にそう思います)。
s=$$SED$$
sed 's/'\''/'$s'/;1s/^./'\''&/' </proc/"$$"/environ |
tr '\0' "'" |
sed 's/'\''/&\n&/g' |
sed '1d;$d;s/^\('\''\)\([^=]*.\)/\2\1/;s/'$s'/'\\\''/g'
それでも、GNUをsed
お持ちの場合、必要なことは次のとおりです。
sed -z 's/^[^=]*./&'\''/;s/$/'\''\n/' </proc/"$$"/environ
#BOTH METHODS OUTPUT:
さて、POSIXポータブル/dev/...
は、指定されていないものを除きますが、ほとんどのUnicesで同じ構文が動作することを期待できます。
これが他の質問と関係がある場合は、次のように使用できます:
nsenter -m -u -i -n -p -t $PID /bin/bash 5<<ENV --rcfile=/dev/fd/5
$(sed -z 's/^[^=]*./&'\''/;s/$/'\''\n/' </proc/"$$"/environ)
ENV
here-docは、サブシェルで処理するのが.dot
難しいクォートのいずれかでシェルがねじ込むのを防ぎ、サブシェルまたはシェルではなく、ソース可能なファイルへの信頼できるパスを提供するという点で非常に役立ちます変数。ここの他の人たち<(process substitution)
はほとんど同じように機能するバシズムを使用しています-それは間違いなく匿名で|pipe
あり、POSIX iohere
はhere-docs のみを指定しているため、実際には通常はtemp
ファイルです。(dash,
一方、|pipes
here-docsにはanonymous を使用します)。ただし、プロセスの置換に関する不幸な点は、シェルに依存していることですinit
。
|pipes
もちろんこれも機能しますが、|pipe's
サブシェルで状態が蒸発すると、最終的に再び環境を失います。そして再び、これは動作します:
sed '...;a\exec <>/dev/tty' /proc/$pid/environ | sh -i
sed
文自体は、それが世界的な引用の取り扱いとヌルに固定することによって、適切な改行を挿入する置き換えを行い、その時点で、それが最後に到達するまで、メモリ内のすべての行を保持することによって動作します。本当に簡単です。
でdash
絵私は、\混乱を避けるために選んだと追加表示されますGNU
特定の-r
ためのオプションをsed
。しかし、それは単に入力する回数が少なかったためです。zsh
画像でわかるように、どちらの方法でも機能します。
ここにありzsh
ます:
そして、ここでもdash
同じことをやっています:
ターミナルエスケープでさえ無傷で通過します。
/proc/PID/environ
はSolarisのsedがサポートするもの、つまりSolarisがサポートしているかどうかという/proc/PID/environ
ことです。 Solaris上の曲線の背後にある、それは、今日かもしれないのでます)。
sed
、ASCIIバイトの16進数を処理するために必要です。そのうち、ヌルバイトは1です。その上、私は実際に、これを行うはるかに簡単な方法がまだあるかどうかを考えました。
\xNN
POSIXでは構文は必要ありません\OOO
。8進構文でも(C文字列やawk では必要ですが、sed正規表現では必要ありません)。
/proc/PID/environ
(にはLinuxに似たエントリがいくつかありますが/proc/PID
、にはありませんenviron
)。そのため、移植可能なソリューションは、結局Linuxツールを超える必要はありません。つまり、GNU sedまたはBusyBox sedです。どちらも\x00
正規表現でサポートされているため、コードは必要に応じて移植可能です(POSIXではありません)。ただし、非常に複雑です。
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
引用符を含む変数も適切に処理することをお勧めします。