क्या यूनिक्स में एक और प्रक्रिया के पर्यावरण चर को बदलने का एक तरीका है?


105

यूनिक्स पर, क्या कोई तरीका है कि एक प्रक्रिया दूसरे के पर्यावरण चर को बदल सकती है (यह मानते हुए कि वे सभी एक ही उपयोगकर्ता द्वारा चलाए जा रहे हैं)? एक सामान्य समाधान सबसे अच्छा होगा, लेकिन यदि नहीं, तो उस विशिष्ट मामले के बारे में क्या है जहां एक दूसरे का बच्चा है?

संपादित करें: gdb के माध्यम से कैसे?


यह मुझे बदसूरत से ज्यादा मारता है। वास्तविक समस्या क्या है जिसे आप हल करना चाहते हैं?
जेन्स

1
उदाहरण: मैं एक पर्यावरण वैरिएबल को परिभाषित करना चाहता हूं ताकि यूआई द्वारा लॉन्च किया गया हर नया ऐप मिल जाए। मुझे स्टार्टअप स्क्रिप्ट और RE-LOGIN में से किसी एक में वेरिएबल्स को परिभाषित करने के अलावा किसी भी तरीके का पता नहीं है। हालाँकि मैं फिर से लॉगिन नहीं करना चाहूंगा, लेकिन बस चालू सत्र में चर को परिभाषित करें ताकि नए ऐप प्राप्त हों - बिना यूआई से लॉग आउट किए।
AlikElzin-kilaka

जवाबों:


142

Via gdb:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

यह काफी बुरा हैक है और इसे केवल डिबगिंग परिदृश्य के संदर्भ में ही किया जाना चाहिए।


8
तो इसका अर्थ यह प्रतीत होता है कि आप वास्तव में एक प्रक्रिया के वातावरण को बदल सकते हैं यदि आप इस प्रक्रिया से जुड़ते हैं जैसा कि जीडीबी करता है, और फिर अलग हो जाता है। ऐसा लगता है कि यह केवल ऐसा करने वाले कार्यक्रम को लिखना संभव होगा।
शोक

3
"ऐसा लगता है कि यह एक प्रोग्राम लिखना संभव होगा जो केवल यही करता है" वास्तव में .. यह है।
L --o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e

2
यहां तक ​​कि यह विंडोज़ पर भी काम करता है, जो कि साइबरविन का उपयोग करके संकलित किया जाता है, जो कि साइबरविन का उपयोग करके संकलित नहीं किया जाता है!
जुआन कार्लोस मुनोज़

11
ध्यान दें कि यह केवल तभी काम करता है जब प्रक्रिया ने पहले प्राप्त करने के बाद स्थायी रूप से मूल्य को कैश नहीं किया है।
जुआन

1
ptrace: Operation not permitted
गेरिट

22

आप शायद इसे तकनीकी रूप से कर सकते हैं (अन्य उत्तर देखें), लेकिन यह आपकी मदद नहीं कर सकता है।

अधिकांश कार्यक्रमों से उम्मीद की जाएगी कि स्टार्टअप के बाद env var को बाहर से नहीं बदला जा सकता है, इसलिए अधिकांश शायद वे ही var को पढ़ेंगे जिनकी वे स्टार्टअप में रुचि रखते हैं और उसी के आधार पर आरंभ करते हैं। इसलिए उन्हें बाद में बदलने से कोई फर्क नहीं पड़ेगा, क्योंकि कार्यक्रम उन्हें फिर कभी नहीं पढ़ेगा।

यदि आपने इसे एक ठोस समस्या के रूप में पोस्ट किया है, तो आपको संभवतः एक अलग दृष्टिकोण लेना चाहिए। अगर यह जिज्ञासा से बाहर था: अच्छा सवाल :-)।


1
सबसे आम उपयोग का मामला जहां यह उपयोगी होगा, बाल प्रक्रियाओं को नए पर्यावरण चर के वारिस बनाना है, उदाहरण के लिए, डेस्कटॉप वातावरण में जहां आप नए टर्मिनल का उपयोग करना चाहते हैं।
हजूल

13

पर्याप्त रूप से, नहीं। यदि आपके पास पर्याप्त विशेषाधिकार (रूट, या उपचार) थे और / dev / kmem (कर्नेल मेमोरी) के आसपास, और आपने प्रक्रिया के वातावरण में परिवर्तन किए, और यदि प्रक्रिया ने वास्तव में पर्यावरण चर को फिर से संदर्भित किया (तो, प्रक्रिया) पहले से ही env var की एक प्रति नहीं ली थी और केवल उस प्रति का उपयोग नहीं कर रहा था), तो हो सकता है, अगर आप भाग्यशाली और चतुर थे, और हवा सही दिशा में बह रही थी, और चंद्रमा का चरण सही था, शायद, आप कुछ हासिल कर सकते हैं।


2
मुझे जवाब नहीं मिला।
AlikElzin-kilaka

@ तिलक: कुंजी शब्द दूसरा है - नहीं । शेष उत्तर यह कह रहा है कि यदि आपके पास रूट विशेषाधिकार हैं या डिबगर चल रहे हैं, तो शायद आप इसे कर सकते हैं, लेकिन सभी व्यावहारिक उद्देश्यों के लिए, उत्तर नहीं है
जोनाथन लेफ़लर

आपको एक शेल स्क्रिप्ट चल रही है; आप अपनी शेल स्क्रिप्ट की मूल प्रक्रिया में वातावरण को बदलना चाहते हैं ... इसलिए शेल स्क्रिप्ट gdbमूल प्रक्रिया पर लॉन्च होती है और इसे परिवर्तन करने में स्क्रिप्ट किया जाता है, और यह मूल प्रक्रिया को क्रैश किए बिना काम करता है। ठीक है - आप शायद यह कर सकते हैं, लेकिन यह कुछ ऐसा नहीं है जो आप नियमित आधार पर करने जा रहे हैं। व्यावहारिक उद्देश्यों के लिए, इसलिए, उत्तर नहीं रह गया है । बाकी का जवाब सैद्धांतिक रूप से संभव है, कुछ हद तक अव्यावहारिक विकल्प।
जोनाथन लेफलर

7

जैरी पीक को उद्धृत करते हुए:

आप एक पुराने कुत्ते को नए गुर नहीं सिखा सकते।

केवल एक चीज आप इसे शुरू करने से पहले बच्चे की प्रक्रिया के पर्यावरण चर को बदल सकते हैं : यह माता-पिता के वातावरण की प्रतिलिपि प्राप्त करता है, क्षमा करें।

देखें http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm जानकारी के लिए।

उपयोग / खरीद के बारे में जवाब पर एक टिप्पणी। लिनक्स के तहत / proc समर्थित है लेकिन, यह काम नहीं करता है, आप फ़ाइल को बदल नहीं सकते हैं/proc/${pid}/environ , भले ही आप रूट हों: यह बिल्कुल रीड-ओनली है।


जो अभी भी इस सवाल को छोड़ देता है: वास्तव में कहाँ संग्रहीत हैं? क्या वह कर्नेल द्वारा किया जाता है? या शेल मूल्यों को संग्रहीत करता है, और / proc / <pid> / environ उन्हें वहां से मिलता है?
जैतून

यह एक कार्यान्वयन विवरण है, और यह एक (अलग) अच्छा प्रश्न हो सकता है। मुझे लगता है कि हर UNIX भंडारण के लिए अपने तरीके का उपयोग करता है, लेकिन वे सभी ऊपर वर्णित व्यवहार को साझा करते हैं, जो विनिर्देशों का हिस्सा है।
डेविड ऑक्ट

7

मैं ऐसा करने के लिए बल्कि वंचित तरीके के बारे में सोच सकता था, और यह मनमानी प्रक्रियाओं के लिए काम नहीं करेगा।

मान लीजिए कि आप अपनी खुद की साझा लाइब्रेरी लिखते हैं जो 'char * getenv' को लागू करता है। उसके बाद, आप 'LD_PRELOAD' या 'LD_LIBRARY_PATH' को सेट करें। vars ताकि आपकी दोनों प्रक्रियाएँ आपके साझा किए गए पुस्तकालय के साथ चलें।

इस तरह, आपको अनिवार्य रूप से 'गेटेनव' फ़ंक्शन के कोड पर नियंत्रण होगा। तब, आप हर तरह के गंदे काम कर सकते थे। आपका 'गेटेनव' एनवी वर्जन के वैकल्पिक मूल्यों के लिए बाहरी विन्यास फाइल या एसएचएम सेगमेंट से परामर्श कर सकता है। या आप अनुरोधित मानों पर regexp खोज / प्रतिस्थापित कर सकते हैं। या ...

मैं ऐसा करने के लिए एक आसान तरीका नहीं सोच सकता कि मनमाने ढंग से चलने वाली प्रक्रियाओं के लिए (भले ही आप जड़ हैं), डायनामिक लिंकर (ld-linux.so) को फिर से लिखना।


यह करने योग्य होना चाहिए। आपके पास var = value जोड़े के लिए थोड़ा gdbm डेटाबेस हो सकता है। मेरे पास स्ट्रोमबर्ग
dstromberg

मुझे लगता है कि इस पद्धति के लिए पूर्वजन्म की आवश्यकता है। आपको यह भी ध्यान रखना होगा कि गलती से भी कई प्रक्रियाओं में इसे लागू न करें।
dstromberg

3

या नई प्रक्रिया के लिए एक विन्यास फाइल को अद्यतन करने के लिए अपनी प्रक्रिया प्राप्त करें और फिर:

  • अद्यतन कॉन्फ़िगरेशन फ़ाइल को फिर से पढ़ने के लिए नई प्रक्रिया पर एक किल -HUP करें, या
  • हर बार अपडेट के लिए कॉन्फिगर फाइल को चेक करने की प्रक्रिया करें। यदि परिवर्तन पाए जाते हैं, तो कॉन्फ़िगरेशन फ़ाइल को फिर से चलाएँ।

2

वहां तक ​​तो नहीं, जहां तक ​​मुझे पता है। वास्तव में आप एक प्रक्रिया से दूसरी प्रक्रिया के लिए संवाद करने की कोशिश कर रहे हैं, जो आईपीसी विधियों में से एक (साझा की गई मेमोरी, सेमाफोर, सॉकेट्स आदि) के लिए कहता है। इनमें से किसी एक विधि द्वारा डेटा प्राप्त करने के बाद आप पर्यावरण चर निर्धारित कर सकते हैं या अन्य क्रियाओं को अधिक सीधे कर सकते हैं।


1

यदि आपका यूनिक्स फाइल / सिस्टम को सपोर्ट करता है, तो यह ईएनडी को पढ़ाने के लिए मामूली है - आप पर्यावरण, कमांडलाइन, और किसी भी प्रक्रिया के कई अन्य गुणों को पढ़ सकते हैं जो आपके पास हैं। इसे बदलना ... खैर, मैं एक तरह से सोच सकता हूं, लेकिन यह एक बुरा विचार है।

अधिक सामान्य मामला ... मुझे नहीं पता, लेकिन मुझे संदेह है कि एक पोर्टेबल जवाब है।

(संपादित: मेरे मूल उत्तर ने माना कि ओपी env को पढ़ाना चाहता था, इसे नहीं बदलना)


ऊओप्स, मेरे जवाब को संपादित किया - मैं मान रहा था कि वह एनवी को पढ़ना चाहता था, इसे नहीं बदलना।
माइक जी।

1
मुझे फांसी मत छोड़ो। आपका बुरा विचार क्या है?
रलड़ी

लिनक्स पर, मेरा मानना ​​है कि आप अन्य प्रक्रिया जो आप चाहते हैं, उसके लिए आप राइट / प्रॉप / <pid> / मेम रीड-राइट खोल सकते हैं ... मुझे यकीन नहीं है, हालांकि। कोशिश करना, और वास्तव में पर्यावरण के साथ खिलवाड़ करना, क्या बुरा विचार होगा। इसलिए मैं आपको यह कोशिश करने का सुझाव नहीं दे रहा हूं ...
माइक जी।

1

UNIX अंतर-प्रक्रिया संचार से भरा है। जाँच करें कि क्या आपके लक्ष्य उदाहरण में कुछ है। Dbus "डेस्कटॉप" IPC में एक मानक बन रहा है।

मैं भयानक क्लाइंट के साथ भयानक विंडो मैनेजर के अंदर पर्यावरण चर को बदल देता हूं, जो लुआ कोड का "डबस" प्रेषक है।


1

इसका सीधा उत्तर नहीं है लेकिन ... रेमंड चेन के पास [विंडोज-आधारित] औचित्य है केवल दूसरे दिन : -

... हालाँकि इसे करने के निश्चित रूप से असमर्थित तरीके हैं या ऐसे तरीके हैं जो डिबगर की सहायता से काम करते हैं, ऐसी कोई भी चीज़ नहीं है जो किसी अन्य प्रक्रिया के कमांड लाइन तक प्रोग्रामेटिक एक्सेस के लिए समर्थित है, कम से कम कर्नेल द्वारा प्रदान की गई कुछ भी नहीं। ...

ऐसा नहीं है कि जानकारी का ट्रैक न रखने के सिद्धांत का परिणाम है जिसकी आपको आवश्यकता नहीं है। कर्नेल को किसी अन्य प्रक्रिया की कमांड लाइन प्राप्त करने की कोई आवश्यकता नहीं है। यह CreateProcessफंक्शन को पास की गई कमांड लाइन को लेता है और इसे लॉन्च की जाने वाली प्रक्रिया के एड्रेस स्पेस में कॉपी करता है, जिस स्थान परGetCommandLine फंक्शन इसे दोबारा प्राप्त कर सकता है। एक बार प्रक्रिया अपनी स्वयं की कमांड लाइन तक पहुंच सकती है, कर्नेल की जिम्मेदारियां पूरी हो जाती हैं।

चूंकि कमांड लाइन को प्रक्रिया के पता स्थान में कॉपी किया जाता है, इसलिए प्रक्रिया उस मेमोरी को भी लिख सकती है जो कमांड लाइन रखती है और इसे संशोधित करती है। यदि ऐसा होता है, तो मूल कमांड लाइन हमेशा के लिए खो जाती है; एकमात्र ज्ञात प्रतिलिपि अधिलेखित हो गई।

दूसरे शब्दों में, ऐसी कोई भी कर्नेल सुविधाएं होंगी

  • लागू करना मुश्किल है
  • संभावित रूप से सुरक्षा की चिंता

हालांकि सबसे संभावित कारण यह है कि ऐसी सुविधा के लिए सीमित उपयोग के मामले हैं।


1

ऐसा लगता है कि putenv अब काम नहीं करता है, लेकिन setenv करता है। मैं बिना किसी सफलता के साथ वर्तमान शेल में चर सेट करने की कोशिश करते हुए स्वीकृत उत्तर का परीक्षण कर रहा था

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

और संस्करण यह कैसे काम करता है:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.