Как я получаю переменные среды другого процесса?

Монтирование думало устройство закольцовывания с offset, могло бы быть полезным.

VDIfile=VirtData.vdi
mountingpoint=/mnt/VDI
offData=$( VBoxManage internalcommands dumphdinfo "$VDIfile" |grep offData | sed 's:.*offData=\([0-9]*\).*:\1:' )
offset=$(( $offData + 32256 ))
mount -t ext4 -o rw,noatime,noexec,loop,offset="$offset" "$VDIfile" "$mountingpoint"

Больше деталей здесь: https://unix.stackexchange.com/a/45019/9689

24
17.04.2014, 03:31
8 ответов
[119583]
-2
27.01.2020, 19:40

Я ходил с этим кругом. Меня разочаровала переносимость нулевых байтов. Меня не устраивало, что не было надежного способа справиться с ними в скорлупе. Так что я продолжал искать. По правде говоря, я нашел несколько способов сделать это, только пара из которых отмечена в моем другом ответе. Но в результате получились, по крайней мере, две функции оболочки, которые работают следующим образом:

_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 , верно? Написанный таким образом, легко справиться с any 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 , чтобы вы могли видеть как вывод команды 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} то же самое в текущей оболочке или без параметра, чтобы отображать обработанный вывод того же самого на терминале, например установить или printenv будет. Все, что вам нужно, это $ pid - любой читаемый / proc / $ pid / окружающий файл.

Вы используете это так:

#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 источник here-doc отправит его в файловый дескриптор 3. Перед тем, как получить его, это На что это похоже. Это надежно. И POSIX портативный. Ну, по крайней мере, обработка \ 0null является переносимой в POSIX - файловая система / process, очевидно, специфична для Linux. И поэтому есть две функции.

6
27.01.2020, 19:40

В 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
10
27.01.2020, 19:40

Стоит отметить, что процессы могут иметь переменные среды, которые не являются допустимыми переменными 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
}

Эта проблема возникает только иногда, но когда это происходит ...

{ {1}}
3
27.01.2020, 19:40

Следующее преобразует каждую переменную среды в оператор export , правильно цитируемый для чтения в оболочку (поскольку, например, LS_COLORS , скорее всего, будет содержать в себе точки с запятой), затем его исходный код.

[ printf в / usr / bin , к сожалению, обычно не поддерживает % q , поэтому нам нужно вызвать встроенный в bash .]

. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
24
27.01.2020, 19:40

Я думаю, что это переносимый 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:

enter image description here

Что ж, переносимый POSIX, за исключением / dev / ... , который не указан, но вы можете ожидать, что этот синтаксис будет вести себя одинаково в большинстве Unix.

Теперь, если это как-то связано с вашим другим вопросом , вы можете использовать его следующим образом:

nsenter -m -u -i -n -p -t $PID /bin/bash 5<<ENV --rcfile=/dev/fd/5 
    $(sed -z 's/^[^=]*./&'\''/;s/$/'\''\n/' </proc/"$$"/environ)
ENV

Здесь-документ чрезвычайно полезен, так как он предотвращает зависание оболочки с любыми цитирования, над обработкой которого мы так усердно трудимся в подоболочке, а также предоставляет нам надежный путь к исходному файлу .dot , а не к подоболочке или переменной оболочки. Другие здесь используют башизм <(подстановка процесса) , который работает примерно так же - только это определенно анонимный | канал , тогда как POSIX указывает только iohere для here-docs, поэтому это может быть файл любого типа, хотя на практике это обычно файл temp . ( тире, с другой стороны, действительно использует анонимные | каналы для here-docs) . К сожалению, подстановка процесса также зависит от оболочки, что может быть особенно неприятной проблемой, если вы работаете с init .

Это также работает с | pipe , конечно, но затем вы снова теряете среду в конце, когда состояние | pipe испаряется вместе с его подоболочкой. С другой стороны, это работает:

sed '...;a\exec <>/dev/tty' /proc/$pid/environ | sh -i 

Оператор sed сам по себе работает, удерживая каждую строку в памяти, пока не достигнет последней, и в это время он выполняет глобальную замену, обрабатывая кавычки и вставляя новые строки, где это необходимо, путем привязки к нули. На самом деле довольно просто.

На изображении тире вы увидите, что я отказался от \ mess и добавил GNU специфичный параметр -r в sed . Но это просто потому, что печатать было меньше. Это работает в любом случае, как вы можете видеть на изображении zsh .

Вот zsh :

enter image description here

А вот тире делает то же самое:

enter image description here

Даже терминальные побеги проходят невредимым:

enter image description here

0
27.01.2020, 19:40

Использование 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.

3
27.01.2020, 19:40

В этом ответе я предполагаю систему, где /proc/$pid/environ возвращает окружение процесса с указанным PID, с нулевыми байтами между определениями переменных. (То есть Linux, Cygwin или Solaris (?)).

Zsh

export "${(@ps:\000:)$(</proc/$pid/environ)}"

(Довольно прост в zsh: перенаправление ввода без команды эквивалентно cat FILE. Вывод подстановки команды подвергается расширению параметров с помощью флагов ps:\000:, означающих "разделять по нулевым байтам", и @, означающего "если все заключено в двойные кавычки, то рассматривать каждый элемент массива как отдельное поле" (обобщение "$@"). )

Bash, mksh

while IFS= read -r -d "" PWD; do export "$PWD"; done </proc/$pid/environ
PWD=$(pwd)

(В этих оболочках пустой разделитель, переданный в read, приводит к тому, что разделителями становятся нулевые байты. Я использую PWD в качестве имени временной переменной, чтобы избежать нагромождения другой переменной, которая в итоге может быть импортирована. Хотя технически вы можете импортировать и PWD, она останется на месте только до следующего cd.)

POSIX

Переносимость POSIX не так интересна для этого вопроса, потому что она применима только к системам, имеющим /proc/PID/environ. Поэтому вопрос в том, что поддерживает Solaris sed - или есть ли в Solaris /proc/PID/environ, раньше не было, но я сильно отстал от жизни в отношении возможностей Solaris, так что теперь может быть. В Linux утилиты GNU и BusyBox являются null-safe, но с оговорками.

Если мы настаиваем на переносимости POSIX, ни одна из текстовых утилит POSIX не обязана обрабатывать нулевые байты, так что это сложно. Вот решение, которое предполагает, что awk поддерживает нулевой байт в качестве разделителя записей (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 системах) поддерживает нулевой байт, но не устанавливает RS в "\0" в блоке BEGIN и не синтаксис командной строки выше; однако он поддерживает -v 'RS="\0"'. Я не выяснял причину, это похоже на ошибку в моей версии (Debian wheezy).

(Обернуть все строки записей, разделенных нулями, в одинарные кавычки "\047", после экранирования одинарных кавычек внутри значений)

Предостережения

Остерегайтесь, что любой из них может попытаться установить переменные только для чтения (если ваш shell имеет переменные только для чтения).

10
27.01.2020, 19:40

Теги

Похожие вопросы