Neden env çıktısında görebildiğim bir değişkeni yazdıramıyorum?


9

Bir kabuk örneğinin çevresel değişkenlerini diğerinden ayarlamakla ilgileniyorum. Bu yüzden biraz araştırma yapmaya karar verdim. Bir okuduktan sonra numarayı ait sorular hakkında bu ben bunu test etmeye karar verdi.

Her ikisi de çalışan iki A ve B mermisi (PID 420) ürettim zsh. Kabuk AI'dan aşağıdakileri koştu.

sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach

Kabuk B çalıştığımda envdeğişken FOO gerçekten bar değeri ile ayarlandığını görebilirsiniz. Bu, FOO'nun B kabuğu ortamında başarılı bir şekilde başlatıldığını düşündürüyor. Ancak, FOO yazdırmaya çalışırsam ayarlanmadığını belirten boş bir satır alıyorum. Bana göre burada bir çelişki varmış gibi geliyor.

Bu hem kendi Arch GNU / Linux sistemimde hem de bir Ubuntu VM'de test edildi. Ayrıca bashdeğişkenin env'de bile görünmediği yerde bunu test ettim . Bu benim için hayal kırıklığı yaratıyor olsa da, kabuk yumurtlama zamanında ortamının bir kopyasını önbelleğe alır ve sadece bunu kullanır (bağlantılı sorulardan birinde önerilmiştir). Bu hala zshdeğişkeni neden görebildiğini cevaplamıyor .

Çıktı neden echo $FOOboş?


DÜZENLE

Yorumlardaki girdiden sonra biraz daha test yapmaya karar verdim. Sonuçlar aşağıdaki tablolarda görülebilir. İlk sütunda, FOOdeğişkenin enjekte edildiği kabuk bulunur . İlk satır, çıktısı altında görülebilen komutu içerir. Değişken FOO: kullanılarak enjekte edildi sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'. Zsh: komutuna özgü komutlar zsh -c '...'da bash kullanılarak test edildi. Sonuçlar aynıydı, çıktıları kısalık için çıkarıldı.

Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

Yukarıdaki sonuçların dağılım agnostik olduğu ima edilmektedir. Bu bana daha fazlasını anlatmaz zshve bashdeğişkenlerin ayarını farklı şekilde ele almaz . Ayrıca, export FOObu bağlamda kabuğa bağlı olarak çok farklı davranışlar vardır. Umarım bu testler başkası için net bir şey yapabilir.


Bunun zsh -c 'echo $FOO'yerine (tek tırnak kullanın!) Yaparsanız ne olur ? O zaman görebiliyor musun?
user1934428

Doğru değer yeni bir alt kabuktan yazdırılır (bash alt öğesi için de test edilir). Açıkça görülüyor ki, çocuk onu miras alabildiği için çevre bir şekilde kalıcıdır, ancak ebeveyn neden onurlandırmaz?
rlf

3
Bende böyle düşünmüştüm. Sanırım kabuğun bir yerde bir değişkenler tablosu vardır, bazıları "ihraç" olarak işaretlenmiştir, yani bir alt kabuk açıldıktan sonra alt sürecin ortamına yerleştirilirler. Başlangıçta (kabuk başladığında), o zaman ortamdaki değişkenler sembol tablosuna kopyalanır (elbette "dışa aktarılan" değişkenler olarak da). Ortamı değiştirdiğinizde, kabuk sembol tablolarını güncellediği fark edilmez - ancak alt işlemler (gibi env) değiştirilmiş ortamı görür.
user1934428

2
Ubuntu 16.04 üzerinde zsh 5.1.1 ve bash 4.3.48 (1) ile test ettim ve GDB'de bir ortam değişkeninin ayarlanması zshonu kabuk değişkeni olarak görünür kılmıyor , ancak alt süreçlere ( Eğer bir tane ayarlarken,) gözlemledim bash gelmez bir kabuk değişkeni olarak görünür hale getirmek ancak yok değil çocuğun süreçlerine üzerine geçirilecek neden! Görünüşe göre zsh ve bash değişkenleri yönetmek için farklı stratejiler kullanıyor, zsh çevre dışı değişkenleri izliyor ve bash (alt kabuk olmayan) bir çocuğu başlatırken dezenfekte ettiği her şeyi kendi ortamında saklıyor.
Eliah Kagan

@EliahKagan, ilginç; bunu bir cevap olarak göndermelisiniz. Koşarsan bir fark yaparsa ben de merak export FOOiçinde bash?
Wildcard

Yanıtlar:


2

Çoğu kabuk getenv()/ setenv()/ putenv()API kullanmaz .

Başlangıçta, her ortam değişkeni için kabuk değişkenleri oluştururlar. Bunlar, değişkenin dışa aktarılıp dışa aktarılıp aktarılmayacağı gibi diğer bilgileri taşıması gereken iç yapılarda depolanacaktır ... Bunun için libc'leri kullanamazlar environ.

Benzer şekilde ve bu nedenle, komutları yürütmek için kullanmazlar execlp(), execvp()ancak dışa aktarılan değişkenlerin listesine göre diziyi execve()hesaplayarak sistem çağrısını doğrudan envp[]çağırırlar.

Bu nedenle, içinde gdb, değişkenlerin dahili tablosunu taşıyan bir giriş eklemeniz veya büyük olasılıkla export VAR=valuebu tabloyu kendi başına güncellemesi için bir kodu yorumlamasını sağlayacak doğru işlevi çağırmanız gerekir.

Eğer arasında bir fark görebilirsiniz neden olarak bashve zshAradığınızda setenv()içinde gdb, ben aradığınız de ondan şüpheleniyoruz setenv()girdikten sonra, örneğin kabuk başlatır önce main().

bash'S main()olduğunu fark edersiniz int main(int argc, char* argv[], char* envp[])(ve bashbu değişkenlerin değişkenlerini eşler envp[]), zsh' s ise int main(int argc, char* argv[])ve bunun yerine zshdeğişkenleri alır environ. yerinde değişiklik setenv()yapar environancak değiştiremez envp[](çeşitli sistemlerde ve bu işaretçilerin işaret ettiği dizelerde salt okunur).

Her durumda, kabuk environbaşlangıçta okuduktan sonra, kabuk setenv()artık kullanılmadığı environ(veya getenv()) kullanılamadığı için kullanma etkisiz olacaktır .

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.