Я з цим ходив кругом. Мене розчарувало перенесення нульових байтів. Зі мною не було добре, що не було надійного способу поводження з ними в оболонці. Тому я продовжував шукати. Правда в тому, що я знайшов кілька способів зробити це, лише пару з них відзначені в моїй іншій відповіді. Але в результаті були принаймні дві функції оболонки, які працюють так:
_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
дружним кодом формату та надрукує рядок. Результат - це \0null
розділений масив шістнадцяткових байтових рядків. Подивіться:
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
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")
НЕ кількість фанк-символів чи вміщене цитування може порушити це, оскільки байти для кожного значення не оцінюються до того самого моменту, коли вміст не з’явиться. І ми вже знаємо, що воно працювало як значення хоча б один раз - тут немає необхідного розбору або захисту цитат, оскільки це байт-за-байтом копія вихідного значення.
Функція спочатку оцінює $var
імена та чекає завершення перевірок перед тим, як .dot
джерело подає тут-док, який подає його на файл-дескриптор 3. Перед тим, як джерело, воно виглядає, як воно виглядає. Це нерозумно. І POSIX портативний. Ну, принаймні обробка \ 0null є портативною POSIX - файлова система / process очевидно специфічна для Linux. І тому є дві функції.
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
, які також будуть обробляти змінні з цитатами в них належним чином.