Eu voltei e voltei com isso. Fiquei frustrado com a portabilidade de bytes nulos. Não me ocorreu bem que não havia uma maneira confiável de lidar com eles em uma concha. Então eu continuei olhando. A verdade é que encontrei várias maneiras de fazer isso, das quais apenas duas são mencionadas na minha outra resposta. Mas os resultados foram pelo menos duas funções de shell que funcionam assim:
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
Primeiro vou falar sobre a \0delimitação. Na verdade, é muito fácil de fazer. Aqui está a função:
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
Basicamente, odleva stdine grava em stdoutcada byte que recebe em hexadecimal um por linha.
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
Aposto que você pode adivinhar qual é o \0nullcerto? Escrito assim, é fácil lidar com qualquer um sed . sedapenas salva os dois últimos caracteres em cada linha até encontrar um nulo; nesse ponto, substitui as novas linhas intermediárias pelo printfcódigo de formato amigável e imprime a string. O resultado é uma \0nullmatriz delimitada de cadeias de bytes hexadecimais. Veja:
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
.
Eu canalizei o acima para teeque você pudesse ver a saída do comando susbstitution e o resultado do printfprocessamento. Espero que você observe que o subshell também não é citado, mas printfainda é dividido apenas no \0nulldelimitador. Veja:
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
.
Também não há aspas nessa expansão - não importa se você citou ou não. Isso ocorre porque os valores da mordida são apresentados sem separação, exceto pela linha de \new gerada para cada vez que seduma string é impressa. A divisão de palavras não se aplica. E é isso que torna isso possível:
_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
A função acima usa _zedlmtpara ${pcat}um fluxo preparado de código de bytes para a origem do ambiente de qualquer processo que possa ser encontrado /procou diretamente para .dot ${psrc}o mesmo no shell atual, ou sem um parâmetro, para exibir uma saída processada do mesmo para o terminal, como setou printenvvontade. Tudo que você precisa é de $pid- qualquer/proc/$pid/environ arquivo legível fará.
Você o usa assim:
#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}
Mas qual é a diferença entre humano amigável e fonte ? Bem, a diferença é que faz com que essa resposta seja diferente de todas as outras aqui - incluindo a minha outra. Qualquer outra resposta depende do shell citar de uma maneira ou de outra para lidar com todos os casos extremos. Simplesmente não funciona tão bem. Por favor, acredite em mim - eu tentei. Veja:
_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")
NENHUMA quantidade de caracteres descolados ou citações contidas pode quebrar isso porque os bytes de cada valor não são avaliados até o instante em que o conteúdo é originado. E já sabemos que funcionou como um valor pelo menos uma vez - não há proteção de análise ou cotação necessária aqui, porque esta é uma cópia de byte a byte do valor original.
A função primeiro avalia os $varnomes e aguarda a conclusão das verificações antes .dotde fornecer o documento aqui, alimentado pelo descritor de arquivo 3. Antes de fornecê-lo, é assim que parece. É à prova de idiotas. E POSIX portátil. Bem, pelo menos a manipulação \ 0null é POSIX portátil - o sistema de arquivos / process é obviamente específico do Linux. E é por isso que existem duas funções.
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ), que também manipulará variáveis com aspas.