검사 /proc/1/environ
하면 null 바이트로 구분 된 프로세스 1
환경 변수 문자열을 볼 수 있습니다 . 이 변수를 현재 환경으로 가져오고 싶습니다. 이 작업을 수행하는 쉬운 방법이 있습니까?
proc
매뉴얼 페이지 나에게 라인별로 각각의 환경 변수를 출력 할 데 도움이되는 미리보기를 제공합니다 (cat /proc/1/environ; echo) | tr '\000' '\n'
. 이것은 내용이 올바른지 확인하는 데 도움이되지만 실제로해야 할 일은 이러한 변수를 현재 bash 세션으로 가져 오는 것입니다.
어떻게합니까?
답변
다음은 각 환경 변수를 export
명령문 으로 변환 하고 쉘로 읽기 위해 올바르게 인용 한 다음 인용합니다 ( LS_COLORS
예 : 세미콜론이 포함되어 있기 때문에).
[ 안타깝게도 printf
in은 /usr/bin
일반적으로 지원하지 않으므로에 %q
내장 된 것을 호출해야합니다 bash
.]
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
답변
에서 bash
당신이 다음을 수행 할 수 있습니다. 변수의 가능한 모든 내용에 대해 작동하며 다음을 피합니다 eval
.
while IFS= read -rd '' var; do declare +x "$var"; done </proc/$PID/environ
이렇게하면 실행중인 쉘에서 읽은 변수를 쉘 변수로 선언합니다. 대신 실행중인 쉘 환경으로 변수를 내보내려면 다음을 수행하십시오.
while IFS= read -rd '' var; do export "$var"; done </proc/$PID/environ
답변
이 답변에서는 /proc/$pid/environ
변수 정의 사이에 null 바이트를 사용하여 지정된 PID로 프로세스 환경을 반환 하는 시스템을 가정합니다 . ( 따라서 Linux, Cygwin 또는 Solaris (?) ).
Zsh
export "${(@ps:\000:)$(</proc/$pid/environ)}"
(zsh가 진행하는 것처럼 매우 간단 합니다 . 명령 <FILE
이 없는 입력 리디렉션 은에 해당합니다 cat FILE
. 명령 대체의 출력은 “null 바이트에 분할”이라는 플래그를 사용하여 매개 변수 확장을 수행하고 “전체가 큰 따옴표로 묶인 경우 각 배열 요소를 별도의 필드로 “(일반화 ).)ps:\000:
@
"$@"
배쉬, mksh
while IFS= read -r -d "" PWD; do export "$PWD"; done </proc/$pid/environ
PWD=$(pwd)
(이 셸에서 빈 구분 기호가 전달되면 read
null 바이트가 구분 기호가됩니다. PWD
가져 오기 PWD
로 끝날 수있는 다른 변수를 방해하지 않기 위해 임시 변수 이름으로 사용 합니다. 기술적으로 가져올 수는 있지만 계속 가져올 때까지만 유지됩니다. 다음 cd
.)
POSIX
POSIX 이식성은이 질문에 흥미롭지 않습니다. 왜냐하면이 시스템은 /proc/PID/environ
. 그래서 문제는 솔라리스 sed가 지원하는 것, 또는 솔라리스의 지원 여부입니다. /proc/PID/environ
하지만 사용하지 않았지만 요즘에는 솔라리스 기능에 뒤쳐져 있습니다. Linux에서 GNU 유틸리티와 BusyBox는 모두 널 안전하지만 경고가 있습니다.
POSIX 이식성을 고집한다면 POSIX 텍스트 유틸리티 중 어느 것도 널 바이트를 처리 할 필요가 없으므로 이것은 어렵다. 다음은 awk가 레코드 구분 기호로 null 바이트를 지원한다고 가정하는 솔루션입니다 (BuckyBox awk와 마찬가지로 nawk 및 gawk는 수행하지만 mawk는 그렇지 않습니다).
eval $(</proc/$pid/environ awk -v RS='\0' '{gsub("\047", "\047\\\047\047"); print "export \047" $0 "\047"}')
(일반적으로 내장형 리눅스 시스템에서 발견 된 버전)의 비지 박스 AWK 지원 NULL의 바이트이지만 설정하지 않는 RS
로 "\0"
(A)에 BEGIN
없는 명령 행 구 위에 블록과; 그러나 그것은 지원 -v 'RS="\0"'
합니다. 나는 왜 내 버전 (Debian wheezy)의 버그처럼 보이는지 조사하지 않았습니다.
( 작은 따옴표를 값 내부로 이스케이프 한 후 모든 행에서 널로 분리 된 레코드를 작은 따옴표로 묶으십시오 "\047"
.)
경고
이 중 하나라도 읽기 전용 변수를 설정하려고 시도 할 수 있습니다 (쉘에 읽기 전용 변수가있는 경우).
답변
나는 이것으로 빙글 빙글 갔다. null 바이트의 이식성에 좌절했습니다. 쉘에서 처리 할 수있는 확실한 방법이 없다는 것은 나와 함께 잘 앉아 있지 않았습니다. 그래서 나는 계속 찾고 있었다. 진실은 내가 이것을 할 수있는 몇 가지 방법을 찾았다는 것인데, 그중 두 가지만이 내 대답에 나와 있습니다. 그러나 결과는 다음과 같이 작동하는 적어도 두 개의 쉘 함수였습니다.
_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
각 바이트가 라인 당 진수 한 수신한다.
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
? 이 취급이 용이하다는처럼 서면 어느 sed
. sed
중간 줄 바꿈을 printf
친숙한 형식 코드로 바꾸고 문자열을 인쇄 하는 null이 발생할 때까지 각 줄의 마지막 두 문자를 저장 합니다. 결과는 \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
명령 susbstitution의 출력과 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
때마다 생성 된 하나의 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
파일 설명자 3에 공급 된 here-doc을 소싱 하기 전에 검사가 완료 될 때까지 기다립니다 . 바보입니다. 그리고 POSIX 휴대용. 적어도 \ 0null 처리는 POSIX 이식 가능합니다. / process 파일 시스템은 분명히 Linux에 따라 다릅니다. 이것이 두 가지 기능이있는 이유입니다.
답변
대체 사용 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
을합니다. 아마도 null을 처리 할 것입니다. 그래서 거기에 (내가 정말 이번에는 그렇게 생각) 도 실제로 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)
은 거의 같은 방식으로 작동 하는 bashism을 사용합니다 -POSIX 는 here-docs |pipe
만 지정 iohere
하므로 실제로는 파일입니다.하지만 실제로는 temp
파일입니다. ( dash,
반면, |pipes
here-docs 에는 익명 을 사용합니다 ) . 그러나 프로세스 대체에 대한 불행한 점은 쉘에 의존하기 때문에 작업하는 경우 특히 성가신 문제 일 수 있습니다 init
.
이것은 물론 작동 |pipes
하지만 |pipe's
상태가 하위 셸과 함께 증발 하면 결국 환경을 다시 잃게됩니다 . 그런 다음 다시 작동합니다.
sed '...;a\exec <>/dev/tty' /proc/$pid/environ | sh -i
sed
문 자체가 마지막에 도달 할 때까지 세계가 인용하고 삽입 줄 바꿈을 처리하는 대신 수행하는 시간에 메모리에 모든 라인을 유지하여 작동 여기서 널 (null)에 고정이 적절. 정말 간단합니다.
에서 dash
사진 당신은 내가 \ 혼란을 피하고 추가하기로 볼 수 있습니다 GNU
특정의 -r
에 옵션을 sed
. 그러나 그것은 타이핑하기가 덜한 원인입니다. zsh
이미지 에서 볼 수 있듯이 어느 쪽이든 작동합니다 .
여기 있습니다 zsh
:
그리고 여기에도 dash
같은 일이 있습니다.
터미널 이스케이프조차도 흠없는 상태로 나옵니다.