“A = 10 echo $ A” neden 10 yazdırmıyor?


25

Bu komut:

A=10 echo $A

boş bir satır yazdırır. Neden olmasın 10? Yerinde geçici ortam ayarı neden çalışmıyor?

Çözüm yerine nedenini ve açıklamasını bilmek istiyorum.

kullandım

LANG=C gcc ...

gcc'yi zorlamak için sistem dili (Çince) yerine geri dönüş dilini (İngilizce) kullanın. Dolayısıyla bir VAR=valueönek izleyen komut için geçici bir ortam oluşturacağını varsayıyorum . Ama bazı yanlış anlaşılmalar var gibi gözüküyor.

Yanıtlar:


22

Bir emri değerlendirmenin farklı adımlarının gerçekleştiği düzen meselesidir.

A=10 echo $Ailk önce komutu üç kelimeden oluşan basit bir komuta A=10, echove $A. Daha sonra her bir kelime değişken sübstitüsyona tabi tutulur, yani değişken genişlemelerin $Akendi değerleri gibi dönüşümü olur ( görünür hiçbir şey yapmayan adımları atlıyorum).

Eğer Adeğeri vardır foobaşlangıçta genişleme adımlarının sonucu hala üç kelime var basit komut şudur: A=10, echove foo. (Kabuk, bu noktada başlangıçta hangi karakterlerin tırnak işaretleri içinde olduğunu da hatırlar - bu durumda, hiçbiri.) Bir sonraki adım komutu çalıştırmaktır. Yana A=10eşit işareti ardından geçerli bir değişken adı ile başlar, bu bir görev olarak kabul edilir; değişken komutun çalıştırılması sırasında hem kabukta hem de ortamda Aayarlanır 10. (Normalde , sadece kabuk değişkeni olarak değil, çevrede export Aolması için yazmanız gerekir A; bu bir istisnadır.) Bir sonraki kelime bir ödev değildir, bu yüzden bir komut adı olarak kabul edilir (yerleşik bir komuttur). echokomut herhangi bir değişkene bağlı değildir, bu nedenle A=10 echo $Atam olarak aynı etkiye sahiptir echo $A.

Yalnızca bir komut süresi için değişken ayarlamak istiyorsanız, ancak komutu yürütürken atamayı dikkate alarak bir alt kabuk kullanabilirsiniz. Parantezle gösterilen bir alt kabuk, tüm durum değişikliklerini (değişken atamaları, geçerli dizin, işlev tanımları, vb.) Alt kabukta yerel yapar.

(A=10; echo $A)

Make o export A=10bunu harici programlar tarafından görülür şekilde çevreye değişkeni ihraç etmek istiyorum.


Teşekkürler diyebilir A=10 (echo $A)ve alabilir 10miyim?
Dünya Motoru

2
@EarthEngine Hayır, bu bir sözdizimi hatası olurdu. Atama basit bir komutun başında olmalıdır (örn. Sadece bir komut adı ve bazı parametreler ve isteğe bağlı olarak bazı başlangıç ​​atamaları ve bazı yönlendirmeler). A=10; (echo $A)çıktılar, 10ancak Akomut dosyasının geri kalanı için de ayarlar .
Gilles 'SO- kötülük' dur

2
@EarthEngine Ama diyebilirsiniz A=10 eval 'echo $A'. Tek tırnak $Atüm çizgi değerlendirilinceye kadar yorumlanmayı durdurur ... Bu sırada A = 10. Bu cevabı kabul edilenden daha doğru görüyorum .
Oli

Bence bu doğru açıklama. Davranışın sebebi, sadece genişlemenin $Ave atamalarının ne zaman Agerçekleşeceğidir. Örneğin, A=5; A=6 let 'a=A'; echo $adöner 6değil 5ve letyerleşik bir komut olduğundan, bir alt kabuk başlattığını sanmıyorum .
David Ongaro

@EarthEngine: Doğru açıklama olduğunu söyledi zamanlarda düzen değerlendirmenin, bu yanıltıcı olabilir: A=10 echo $Aolacak değil set A=10sonradan herhangi komutlar için, farklı çizgileri (atama ne zaman açıkça olsa bile oldu zaten değerlendirilir). Bu siparişle ilgili değil, kapsamla ilgili
MestreLion

37

Eğer kullandığınız zaman LANG=C gcc ... ne olur kabuk için LANG setleri olmasıdır gccbireyin çevreye sadece ve değil için geçerli bir ortamda kendisi ( nota bakın ). Bu yüzden gccbittikten sonra LANGönceki değerine geri döner (veya ayarlanmadan).

Ek olarak, onu kullandığınızda , eko yerine, $ A'nın yerine A=10 echo $Ageçen kabuktur ve bu değiştirme ("genişleme" olarak adlandırılır) ifadenin değerlendirilmesinden önce gerçekleşir (atama dahil), bu nedenle beklenen Adeğerin önceden ayarlanmış olması gerekir. içinde geçerli olduğunu açıklamaya öncesinde çevre.

Bu yüzden A=10 echo $Abeklendiği gibi çalışmaz: A=10yankı için ayarlanır, ancak yankı içsel olarak ortam değişkeninin değerini yok sayar A. Ve $Aşu anki kabuğunda ayarlanan (hiçbiri olmayan) değerle değiştirilir ve sonra yankıya bir argüman olarak iletilir.

Sizin varsayım doğruysa Yani: VAR=value command does işi, ancak bu yalnızca alakalı commandiçten kullandığı VAR. Değilse, hala geçebilir valuebir şekilde argüman için command, ama argümanlar ile değiştirilir akım onlar kullanım öncesinde ayarlanmalıdır böylece, kabuk:VAR=value; command "$VAR"

Yürütülebilir bir komut dosyasının nasıl oluşturulduğunu biliyorsanız, bunu bir test olarak deneyebilirsiniz:

#!/bin/sh
echo "1st argument is $1"
echo "A is $A"

Farklı kaydet testscriptve dene:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5

Son fakat en az değil, kabuk ve çevre değişkenleri ve program argümanları arasındaki farkı bilmeye değer .

İşte bazı iyi referanslar:

.

(*) Not: Teknik olarak kabuk gelmez Bazı komutlar gibi: neden burada da mevcut ortamda ayarlanır ve var echo, readve testolan kabuk yerleşikleri ve bu nedenle onlar bir çocuk süreç yumurtlamaya yoktur. Mevcut ortamda koşuyorlar. Ancak, kabuk atama için sadece komut çalışana kadar devam eder, bu nedenle tüm pratik amaçlar için etki aynıdır: atama sadece o tek komut tarafından görülür.


2
Bu açıklama aslında yanlıştır, ancak birkaç köşe davası dışında hepsinde doğru sonuca varır. Gerçek açıklama, genişleme sırasıdır: $Aödev gerçekleşmeden önce değerlendirilir. Açıklamanızın yalnızca davranışı değişkenin değerine bağlı olan düzenli yerleşik yardımcı programlar söz konusu olduğunda başarısız olduğunu düşünüyorum: yerleşik atanan değeri görüyor. İki IFS=: read one two three restnokta üst üste ayrılmış alanları okuyan yaygın bir örnek : readyerleşik, değerini görüyor IFS.
Gilles 'SO- kötülükten

“Mevcut kabuğun kendisi için değil” yanlıştır: değişken geçerli kabuğun içinde ayarlanır, ancak yalnızca geçerli basit komut için sürer. echodeğeri görecekti 10için Ao umursasaydın.
Gilles 'SO- kötülük yapmayı bırak'

@Gilles: Açıklama için çok teşekkürler! Bu incelikten haberdar değildim. Doğru anladım yüzden, eğer bash vardır için setine akım ortamda (yeni yumurtlamaya yok aksi builtins pidöteki "regurlar" komutları olduğu gibi atama görmeyecektir). Ancak atama kapsamını sınırlamak için komut yapıldıktan sonra kararsız hale gelir . Bu doğru mu, cevabımı buna göre düzelteceğim. Not: teknikler bir yana, hala bir cevabın değerlendirme sırasını değil kapsamı üzerinde durması gerektiğini düşünüyorum, aksi halde birinin A=10 test; echo $A10
31'de

3

İstediğiniz gibi yapmak için muhtemelen temiz bir yol, komutu vermektir:

A=10 eval 'echo $A'

Aslında bu, 10 değerinin A $ yerine bir sonraki bağlamda yerine geçmesini erteleyecektir (yani, atamayı zaten bilen eval içinde). Tekli tekliflerin gerekli olduğunu unutmayın. Bu tür bir yapı, mevcut ortamınızı kirletme riski taşımadan istediğiniz komutu (bu durumda yankı) istediğiniz atamayı net bir şekilde iletir.

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.