Başka bir işlemin ortam değişkenlerini nasıl kaynaklarım?


24

İncelersem /proc/1/environ, boş bayt ayrılmış bir işlemin 1ortam değişkenleri dizesini görebilirim . Bu değişkenleri mevcut ortamıma getirmek istiyorum. Bunu yapmanın kolay bir yolu var mı?

procAdam sayfa bana bir satır-satır bazında her ortam değişkeni yazdırmak olmak yardımcı olan bir pasajı verir (cat /proc/1/environ; echo) | tr '\000' '\n'. Bu, içeriğin doğru olduğunu doğrulamama yardımcı oluyor, ancak gerçekten yapmam gereken bu değişkenleri mevcut bash oturumuma aktarıyor.

Bunu nasıl yaparım?

Yanıtlar:


23

Aşağıdakiler, her ortam değişkenini exportbir kabuğa okumak için uygun şekilde alıntılanan bir ifadeye dönüştürecektir (çünkü LS_COLORS, içinde noktalı virgül olması muhtemeldir), sonra onu kaynaklamaktadır.

[ printfİçinde /usr/binmaalesef genellikle desteklemediği %qbiz yerleşik bir çağırmanız gerekir, böylece bash.]

. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)

Ben önermek . <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)düzgün yanı onları tırnak değişkenleri idare edecek olan.
John Kugelman,

@JohnKugelman "$@"yerine , geliştirme için çok teşekkür ederiz '{}'. Merak edenler için --onun geliştirilmiş yanıtında argüman: pozisyonel argümanları bash -c command_stringbaşlayan atanır $0ederken, "$@"genişlediğinde başlayan argümanlar dahil etmek $1. Argüman --atanır $0.
Mark Plotnick

10

İçinde bashaşağıdakileri yapabilirsiniz. Bu, değişkenlerin tüm olası içerikleri için işe yarar ve önler eval:

while IFS= read -rd '' var; do declare +x "$var"; done </proc/$PID/environ

Bu, okunan değişkenleri çalışan kabuktaki kabuk değişkenleri olarak ilan edecektir. Değişkenleri çalışan kabuk ortamına dışa aktarmak için:

while IFS= read -rd '' var; do export "$var"; done </proc/$PID/environ

10

Bu cevapta, /proc/$pid/environişlem ortamını belirtilen PID ile, değişken tanımları arasında boş baytlarla döndüren bir sistem olduğunu varsayıyorum . ( Öyleyse Linux, Cygwin veya Solaris (?) ).

zsh

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

(Zsh olarak Oldukça basit gider: Bir hayır komutuyla giriş yönlendirme <FILE eşdeğerdir cat FILEkomut ikamesi uğrar çıktısını ile genişleme parametresi. Bayrakları ps:\000: “boş bayt üzerinde bölünmüş” anlamına gelen ve @anlam “Her şey daha sonra çift tırnak tedavi ise Her bir dizi öğesi ayrı bir alan olarak ”(genelleştirme "$@").

Bash, mksh

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

(Bu kabuklar, boş sınırlayıcı geçirilen readboş sonuçların ayırıcılar olmak. Kullandığım bayt PWDithal kalabilmektedir başka bir değişken clobbering önlemek için geçici bir değişken adı olarak. Teknik olarak alabiliriz iken PWDde, sadece kadar koymak sürdüreceğine Bir sonraki cd.)

POSIX

POSIX taşınabilirliği, bu soru için o kadar da ilginç değildir, çünkü yalnızca sahip olan sistemler için geçerlidir /proc/PID/environ. Bu yüzden asıl soru Solaris sed'in desteklediği - ya da Solaris'in kullanıp /proc/PID/environkullanmadığı, kullanmadığı ama Solaris özellikleri eğrisinin çok gerisinde olduğum için bugünlerde olabilir. Linux'ta, GNU yardımcı programları ve BusyBox hem sıfır güvenlidir, hem de oyundur.

POSIX taşınabilirliği konusunda ısrar edersek, boş byte'ları işlemek için POSIX metin yardımcı programlarından hiçbiri gerekmez, bu nedenle bu zordur. İşte awk'nin kayıt sınırlayıcı olarak boş bir baytı desteklediğini varsayan bir çözüm (nawk ve gawk, BusyBox awk'in yaptığı gibi ama mawk'ın yapmadığını).

eval $(</proc/$pid/environ awk -v RS='\0' '{gsub("\047", "\047\\\047\047"); print "export \047" $0 "\047"}')

(Yaygın gömülü Linux sistemlerinde bulunan versiyonudur) BusyBox awk destek boş bayt ancak ayar yok RSetmek "\0"bir de BEGINdeğil komut satırı sözdizimi yukarıdaki blok ve; ancak destekliyor -v 'RS="\0"'. Nedenini araştırmamıştım, bu versiyonumdaki bir hataya benziyor (Debian wheezy).

( Değerlerin içindeki tek tırnak işaretlerinden kaçtıktan sonra tüm satırları boş tırnaklı kayıtları tek tırnak "\047"işaretleri içine alın.)

Uyarılar

Bunlardan herhangi birinin salt okunur değişkenleri ayarlamaya çalışabileceğini unutmayın (kabuğunuzun salt okunur değişkenleri varsa).


Sonunda buna geri döndüm. Bunu ya da basitçe bildiğim tüm kabuklarda boş işlem yapmanın kusursuz bir yolunu buldum. Yeni cevabımı gör.
mikeserv

6

Bununla gittim ve etrafa döndüm. Boş baytların taşınabilirliği konusunda sinirliydim. Benimle iyi oturmuyor, onları bir kabukta kullanmanın güvenilir bir yolu yoktu. Ben de bakmaya devam ettim. Gerçek şu ki, bunu yapmanın birkaç yolunu buldum, sadece birkaçını diğer cevabımda belirtmiştim. Ancak sonuçlar şöyle çalışan en az iki kabuk işlevi idi:

_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file

İlk önce \0sınırlandırma hakkında konuşacağım . Aslında yapmak oldukça kolaydır. İşte fonksiyon:

_zedlmt() { od -t x1 -w1 -v  | sed -n '
    /.* \(..\)$/s//\1/
    /00/!{H;b};s///
    x;s/\n/\\x/gp;x;h'
}

Temel olarak, her satır onaltılık olarak aldığı her bayt odalır stdinve yazar 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

Bahse girerim hangisi olduğunu tahmin edebilirsin \0null, değil mi? Bu şekilde yazılmış herhangi biriyle başa çıkmak kolaydır sed. sedsadece her iki satırdaki son iki karakteri kaydeder, bu noktada ortadaki yeni satırları printfdostça format koduyla değiştirir ve dizeyi yazdırır. Sonuç, \0nullayrılmış bir onaltılık bayt dizisi dizisidir. Bak:

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
.

Yukarıdakileri teeyayınladım , böylece hem suslama emri çıktısını hem de işlemin sonucunu görebilirsiniz printf. Umarım alt kabuğun aslında kote olmadığını ama printfhala \0nullsınırlayıcıda ayrıldığını farkedersiniz . Bak:

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
.

Bu genişlemeden hiçbir alıntı yok; alıntı yapıp yapmamanız önemli değil. Bunun nedeni, ısırık değerlerinin \n, her zaman sedbir dize basması için oluşturulan bir ewline hariç, ayrılmamış olarak gelmesidir . Sözcük bölme geçerli değildir. Ve bunu mümkün kılan şey bu:

_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

Yukarıdaki fonksiyon kullanımları _zedlmtbirine ${pcat}bulunabilir herhangi bir işlem ortam kaynak için bayt kod hazırlanmış bir akımı /procya da doğrudan .dot ${psrc}, mevcut kabuk aynı ya da bir parametre olmadan gibi uç aynı işlenmiş bir görüntü çıkışı setya da printenvolacak. Tek ihtiyacınız olan bir $pid- okunabilir herhangi bir/proc/$pid/environ dosya yapacak.

Bunu böyle kullanıyorsun:

#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} 

Ama insan dostu ve kaynaklanabilir arasındaki fark nedir ? Aradaki fark, bu cevabı burada diğerlerinden farklı kılan şeydir - benim diğerini de dahil. Diğer tüm cevaplar, tüm kenar davalarını ele almak için kabuğun bir şekilde veya başka bir şekilde alıntı yapmasına bağlıdır. Sadece o kadar iyi çalışmıyor. Lütfen bana inan - ben TRIED ettik Bak:

_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")

HAYIR miktarda funky karakter veya içerilen alıntı bu içerikten kaynaklanana kadar her değer için bayt değerlendirilmediğinden bunu bozabilir. Ve biz zaten en az bir kere bir değer olarak çalıştığını biliyoruz - burada ayrıştırma veya fiyat teklifi koruması gerekmiyor çünkü bu orijinal değerin bayt bayt kopyası.

Bu işlev ilk önce $varisimleri değerlendirir ve .dotburada dosya-tanımlayıcı 3'e beslenen here-doc kaynağını almadan önce kontrollerin tamamlanmasını bekler. Kaynaklanmadan önce göründüğü gibi. Bu aptal kanıtı. Ve POSIX taşınabilir. Eh, en azından \ 0null işleme POSIX taşınabilirdir - / process dosya sistemi açıkça Linux'a özgüdür. İşte bu yüzden iki fonksiyon var.


3

İkamenin kullanılması sourceve işlenmesi :

source <(sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ)

kısaca:

. <(sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ)

Değiştirme evalve komut değiştirme :

eval `sed -r -e 's/([^\x00]*)\x00/export \1\n/g' /proc/1/environ`

sedÇağrısı ile değiştirilebilir awkçağrı:

awk -vRS='\x00' '{ print "export", $0 }' /proc/1/environ

Ancak unutma 1’de olmayan herhangi bir çevre değişkenini temizlemediğini unutmayın.


İhracat @ fr00tyl00p'nin yanıtında gereksiz mi? Sebep olmasa da çok önemli görünüyor
Dane O'Connor

Evet, ihracat gerekli. Düzelteceğim.
Pavel Šimerda

3
Bu komutların tümü yeni satırlar ve (komuta bağlı olarak) diğer karakterleri içeren değerleri boğar.
Gilles 'SO- kötülük olmayı'

Doğru. Yine de referans için cevap tutacak.
Pavel Šimerda

3

İşlemlerin, geçerli olmayan Bash / Sh / * sh değişkenleri olmayan ortam değişkenleri olabileceğini belirtmekte fayda var - POSIX, ortam değişkenlerinin ad eşleştirmesi olmasını önerir, ancak gerektirmez ^[a-zA-Z0-9_][a-zA-Z0-9_]*$.

Bash'te başka bir işlemin ortamından kabuk uyumlu değişkenlerin bir listesini oluşturmak için:

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
}

Benzer şekilde, onları yüklemek için:

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
}

Bu sorun yalnızca zaman zaman ortaya çıkıyor, ancak ortaya çıktığında ...


0

Bunun POSIX taşınabilir olduğunu düşünüyorum:

. <<ENV /dev/stdin
    $(sed -n 'H;${x;s/\(^\|\x00\)\([^=]*.\)\([^\x00]*\)/\2\x27\3\x27\n/gp}' \
       /proc/$pid/environ)
ENV

Fakat @Gilles iyi bir noktaya değindi - sedmuhtemelen null'larla başa çıkacak, ama belki de değil İşte bu var (Gerçekten bu kez düşünüyorum) aslında POSIX taşınabilir yöntemi de var:

s=$$SED$$
sed 's/'\''/'$s'/;1s/^./'\''&/' </proc/"$$"/environ |
tr '\0' "'" |
sed 's/'\''/&\n&/g' |
sed '1d;$d;s/^\('\''\)\([^=]*.\)/\2\1/;s/'$s'/'\\\''/g'

Yine de, GNU'nuz sedvarsa, yalnızca yapmanız gereken:

sed -z 's/^[^=]*./&'\''/;s/$/'\''\n/' </proc/"$$"/environ

  #BOTH METHODS OUTPUT:

görüntü tanımını buraya girin

Peki, /dev/...belirtilmemiş olanlar haricinde POSIX taşınabilir, ancak sözdiziminin çoğu Unices'de aynı şekilde davranmasını bekleyebilirsiniz.

Şimdi, bunun diğer sorunuzla ilgisi varsa, bu şekilde kullanmak isteyebilirsiniz:

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

Burada-doc, kabuğun alt kabukta işlemek için çok .dotuğraştığımız alıntılardan herhangi birine vidalanmamasını ve bize tekrar alt kabuk veya kabuk yerine kaynaklanabilir bir dosyaya güvenilir bir yol sağlamasında son derece yararlıdır. değişken. Buradaki diğer <(process substitution)insanlar da aynı şekilde çalışan faşizmi kullanırlar - sadece kesinlikle isimsizdir, |pipeoysa POSIX sadece iohereburada-docs için bir kural belirtir ve bu nedenle pratikte genellikle bir tempdosyadır. ( dash,diğer taraftan, |pipesburada-doktorlar için adsız kullanıyor ) . İşlem değiştirme konusunda talihsiz şey, buna bağlı olarak kabuğuna da bağlı. Bu, özellikle çalışıyorsanız can sıkıcı bir sorun olabilir init.

Bu aynı zamanda |pipeselbette işe yarıyor , fakat sonra |pipe'sdevlet, deniz kabuğu ile buharlaştığında , sonunda tekrar çevreyi kaybediyorsunuz . Sonra tekrar, bu işe yarıyor:

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

sedDeyim kendisi son ulaşıncaya kadar küresel bir alıntı ve ekleme yeni satır işleme yerine gerçekleştirir ki bu süre zarfında bellekte her satırını tutarak nerede çalıştığını nulls üzerinde ankraj tarafından uygun. Gerçekten çok basit.

Gelen dashresme ben \ karışıklık eschew ve katma seçti göreceksiniz GNUbelirli -rseçeneği sed. Ama bu sadece yazması daha az olmasının nedeni. Her iki şekilde de çalışır, zshresimde gördüğünüz gibi .

İşte zsh:

görüntü tanımını buraya girin

Ve burada da dashaynı şeyi yapıyorum:

görüntü tanımını buraya girin

Terminal kaçarlar bile pasifleştirilmez:

görüntü tanımını buraya girin


Bu POSIX ile taşınabilir değildir, çünkü boş baytları işlemek için sed gerekli değildir. (Söylendiği gibi, POSIX taşınabilirliği bu soru için o kadar da ilginç değildir, çünkü sadece sahip olan sistemler için geçerlidir /proc/PID/environ. Dolayısıyla, Solaris sed'in desteklediği soru - ya da Solaris’in kullanıp /proc/PID/environkullanmadığı, ama kullanmadığım bir yol) Solaris özellikleri eğrisinin ardında, bugünlerde olabilir.)
Gilles 'ÇÖZÜM'

@Gilles sayılı ama sedboş bayt biri olan bir sap ASCII onaltılı, gereklidir. Ayrıca, aslında bunu yapmanın çok daha kolay bir yolu olup olmadığını düşündüm.
mikeserv

Hayır, POSIX “Giriş dosyaları metin dosyaları olacaktır” (sed ve diğer metin programları için) diyor ve metin dosyalarını “bir veya daha fazla satırda düzenlenen karakterleri içeren dosya” olarak tanımlıyor . Satırlar NUL karakterleri içermiyor (…) ”. Ve bu arada, \xNNsözdizimi POSIX'te gerekli değildir, hatta \OOOsekizlik sözdizimi bile (C dizelerinde ve awk'de, evet, fakat sed regexps'de değil).
Gilles 'SO- kötü olmayı bırak'

@Gilles'in bir anlamı var. Her yere baktım ve daha önce yapabileceğimi düşündüğümü bulamadım. Bu yüzden farklı yaptım. Şimdi düzenleniyor.
mikeserv

Söyleyebileceğim kadarıyla, Solaris her /proc/PID/environşeyden önce sahip değil (içinde Linux gibi başka birçok giriş var /proc/PID, ancak yok environ). Bu nedenle, taşınabilir bir çözümün GNU sed veya BusyBox sed anlamına gelen Linux araçlarının ötesine geçmesi gerekmez. Her ikisi de \x00bir regexp'te desteklediğinden kodunuz gerektiği kadar taşınabilir (ancak POSIX değil). Yine de aşırı karmaşık.
Gilles 'SO- kötü olmayı bırak'

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.