$ 0 ve $ 1 kabuk / ortam değişkenleri gibi değişkenler var mı?


17

Gibi kabuk değişken vardır $0, $1, $2, $?, vb

Aşağıdaki komutu kullanarak kabuk ve ortam değişkenlerini yazdırmayı denedim:

set

Ancak bu değişkenler listede yoktu.

Temel olarak bu değişkenler kabuk / ortam değişkenleri olarak kabul edilmez, değil mi? (bunların çıktısını almanıza rağmen $, kabuk / ortam değişkenlerinde yaptığınız gibi a'dan önce gelmeniz gerekir )


3
Konumsal parametreler değişken değildir. Sen olamaz export 3açmak için $3çevre değişkene. Yapamazsınız unset 3; ve tuşlarını $3kullanarak yeni bir değer atayamazsınız 3=val.
Kaz

Yanıtlar:


25

Değişkenler kabuktaki üç farklı parametre çeşidinden biridir.

  1. Bir değişken , adı geçerli bir kabuk tanımlayıcı bir parametredir; _veya bir harfle başlar , ardından sıfır veya daha fazla harf, rakam veya _.
  2. Konumsal parametreler numaralı parametrelerdir $1, $2...
  3. Özel parametreler tüm tek karakterlik isimler var, ve bir kenara gelen $0, hepsi çeşitli noktalama karakterlerdir.

set yalnızca kabuğun değişkenlerini görüntüler.

Kabuk değişkenlerinin bir alt kümesi, kabuk başlatıldığında değerleri ortamdan devralınan ya da exportözniteliğin geçerli bir adla ayarlanmasıyla oluşturulan ortam değişkenleridir .


1
Not o setgörüntüler tüm parametreler zsh(değil $ 1, $ 2 ... ama $ *, $ @) ve bash ve bosh fonksiyonlar. Ksh93 ve bazı dash çıktı env sürümleri gibi bazı mermiler, kabuk değişkenleriyle eşlenmemiş çeşitlilik gösterir. ( env 1=foo ksh -c setBasacaktır 1=foo)
Stéphane Chazelas

11

Ortam Değişkenleri ve Konumsal Parametreler

$INTEGERDeğişken türlerini tartışmaya başlamadan önce , gerçekte ne olduklarını ve ortam değişkenlerinden nasıl farklı olduklarını anlamamız gerekir. Gibi değişkenler $INTEGERpozisyon parametreleri olarak adlandırılır. Bu, POSIX (Taşınabilir İşletim Sistemi Arayüzü) standardı, bölüm 2.1'de (vurgu mayın) açıklanmaktadır:

  1. Kabuk, bir işlevi (bkz. İşlev Tanım Komutu), yerleşik (bkz. Özel Yerleşik Yardımcı Programlar), yürütülebilir dosya veya komut dosyası yürütür ve bağımsız değişkenlerin adlarını 1 ila n numaralı konumsal parametreler olarak verir ve komutun adı (veya komut dosyası içindeki bir işlev durumunda, komut dosyasının adı) 0 numaralı konumsal parametre olarak (bkz. Komut Arama ve Yürütme).

Buna karşılık, $HOMEve gibi değişkenler$PATH gibi değişkenler ortam değişkenleridir. Tanımları standardın 8. bölümünde açıklanmıştır :

Bu bölümde tanımlanan ortam değişkenleri çoklu yardımcı programların, işlevlerin ve uygulamaların çalışmasını etkiler. Yalnızca belirli yardımcı programların ilgisini çeken başka ortam değişkenleri de vardır. Yalnızca tek bir yardımcı program için geçerli olan ortam değişkenleri, yardımcı program açıklamasının bir parçası olarak tanımlanır.

Açıklamalarına dikkat edin. Konumsal parametrelerin bir komutun önünde görünmesi amaçlanmıştır, yani command positional_arg_1 positional_arg_2.... Kullanıcılara komutun özel olarak ne yapması gerektiğini söylemesi sağlanmalıdır. Bunu yaptığınızda echo 'Hello' 'World', Hellove Worlddizeleri yazdırır , çünkü bunlar üzerinde çalışmak echoistediğiniz şeyler için konumsal parametrelerdir echo. Veecho konum parametrelerini yazdırılacak dizeler olarak anlayacak şekilde oluşturulmuştur (isteğe bağlı bayraklardan biri olmadıkça -n). Bunu farklı bir komutla yaparsanız, ne olduğunu anlamayabilir HelloveWorldbelki de bir sayı beklemesidir. Konumsal parametrelerin "kalıtsal" olmadığına dikkat edin - bir alt süreç, alt sürece açıkça geçmedikçe üst öğenin konum parametreleri hakkında bilgi sahibi değildir. Genellikle sarmalayıcı komut dosyalarıyla iletilen konumsal parametrelerin görüldüğünü görürsünüz - bir komutun zaten var olan örneğini kontrol eden veya çağrılacak gerçek komuta ek konum parametreleri ekleyenler.

Aksine, ortam değişkenleri birden fazla programı etkilemek içindir. Bunlar ortam değişkenleridir, çünkü programın dışında ayarlanmıştır (daha fazlası aşağıdadır). Gibi belirli ortam değişkenleri HOMEveya PATHbelirli bir biçim, belirli bir anlamı var ve onlar her program için aynı anlama edeceğiz. HOMEdeğişken , betiğin kök ayrıcalıklarıyla çalışıp çalışmadığını kontrol etmek ve buna göre belirli eylemlere dallanmak için ortam değişkeni gibi harici bir yardımcı programla aynı anlama gelecektir . Ortam değişkenleri kalıtsaldır - alt süreçler üst ortamın kopyasını alır. Ayrıca bkz. İşlemler ebeveyn ortamını devralıyorsa, neden dışa aktarmaya ihtiyacımız var?/usr/bin/find veya kabuğunuzla (ve dolayısıyla bir komut dosyasıyla) - işlemin altında çalıştığı kullanıcı adının ana dizini. Çevresel değişkenlerin belirli komut davranışlarını açıklamak için kullanılabileceğine dikkat edin, örneğinUID

Kısacası, ana ayrım, ortam değişkenlerinin komutun dışında ayarlanması ve değiştirilmemesi (genellikle) amaçlanırken, konumsal parametreler, komut tarafından işlenmesi gereken şeylerdir ve değişirler.


Sadece kabuk kavramları değil

Yorumlardan fark ettiğim şey, terminal ve kabuğu karıştırdığınız ve gerçekten bir zamanlar fiziksel cihazlar olan gerçek terminalleri okumanızı tavsiye etmesidir. Günümüzde, tipik olarak bahsettiğimiz "terminal", siyah arka planlı ve yeşil metinli pencere aslında yazılım, bir işlemdir. Terminal bir kabuk çalıştıran bir programdır, kabuk ise bir programdır ancak yürütmek için yazdığınız şeyi okuyan programdır (yani, etkileşimli kabuk ise; etkileşimli olmayan kabuklar komut dosyaları ve sh -c 'echo foo'çağrı türleridir). Burada mermiler hakkında daha fazla bilgi .

Bu önemli bir ayrımdır, ancak terminalin bir program olduğunu ve bu nedenle aynı çevre kurallarına ve konum parametrelerine uyduğunu bilmek de önemlidir. Başladığınız gnome-terminalzaman, SHELLortam değişkeninize bakar ve başka bir komut belirtmediğiniz sürece sizin için uygun varsayılan kabuğu oluşturur -e. Diyelim ki varsayılan kabuğumu değiştirdim ksh - kshbunun yerine gnome-terminal ortaya çıkacak bash. Bu aynı zamanda ortamın programlar tarafından nasıl kullanıldığının bir örneğidir. Ben açıkça söylersem gnome-terminalile -ebelirli bir kabuk çalıştırmak için - bunu yapmak, ancak kalıcı olmayacaktır. Aksine, çevre çoğunlukla değiştirilmemelidir (bundan sonra daha fazla).

Gördüğünüz gibi, çevre ve konumsal değişkenler yalnızca kabuk değil, bir işlem / komutun da özellikleridir. Kabuk betikleri söz konusu olduğunda, C programlama dili tarafından belirlenen modeli de takip ederler. Örneğin, maintipik olarak aşağıdaki gibi görünen C işlevini ele alalım.

int main(int argc, char **argv)

, burada argckomut satırı argümanlarının sayısı ve argvetkili bir şekilde komut satırı parametreleri dizisidir ve daha sonra kullanıcının ana dizin yolu, yürütülebilir dosyaları arayabileceğimiz dizinlerin listesi gibi şeylere erişmek için environişlev (Linux'ta man -e 7 environ) vardır PATH. Kabuk betikleri de benzer şekilde modellenir. Kabuk terminoloji, biz konumsal parametrelere sahip $1, $2süre, vb ve $#konumsal parametrelerin sayısıdır. Ne olmuş $0? Bu yine C programlama dilinden de modellenmiş olan argv[0]yürütülebilir dosyanın adıdır - C "çalıştırılabilirinizin" adı olacaktır. Bu, çoğu programlama ve komut dosyası dili için oldukça doğrudur .

Etkileşimli ve etkileşimli olmayan kabuklar

Zaten ima ettiğim şeylerden biri, etkileşimli ve etkileşimli olmayan mermiler arasındaki ayrım . Komutları yazdığınız istem - bu etkileşimli, kullanıcıyla etkileşime girer. Buna karşılık bir kabuk betiğiniz olduğunda veya çalıştırdığınızda bash -c''bu etkileşimli değildir.

Ve bu, ayrımın önemli hale geldiği yerdir. Çalıştırdığınız kabuk, konumsal parametrelerle ortaya çıkan bir işlemdir ( bashgiriş kabuğu için bir "... sıfır bağımsız değişkeninin ilk karakteri bir - veya biri --login seçeneğiyle başlatılmıştır." ( Başvuru ) )

Aksine, -cseçenekle başlatılan komut dosyaları ve kabuklar $1ve $2argümanlardan yararlanabilir . Örneğin,

$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
  File: '/etc/passwd'
  Size: 2913        Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 6035604     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
 Birth: -

Ben de shorada kullandığım dikkat edin , çünkü -cseçenek küçük tuhaf ilk konumsal parametre almak ve atamak $0, genellikle programın bir adından farklı olarak.

Dikkat edilmesi gereken bir diğer şey ise konumsal parametrelerin "çerçeveli" dediğim şey olduğudur. İlk önce bashkendi konum parametreleriyle başlattığımıza dikkat edin , ancak bu konum parametreleri echove parametrelerine dönüştü stat. Ve her program kendi yolunda anlıyor. Eğer statbir dizgeye verdiysek Hello Worldve dosya yoksa Hello Worldbir hata oluşturur; bashbasit bir dize gibi davranır, ancak statbu dizenin mevcut bir dosya adı olmasını bekler. Aksine, tüm programlar ortam değişkeninin HOMEbir dizin olduğu konusunda hemfikirdir (programcı bunu mantıksız bir şekilde kodlamadığı sürece).


Çevre değişkenleri ve konumsal parametrelerle uğraşabilir miyiz?

Teknik olarak, hem etrafında karışıklık can, ama biz olmamalı sık sık konumsal parametreler sağlamak zorunda ise, çevre değişkenleri ile etrafında karışıklık. Komutları kabuk içinde bir değişken ekleyerek çalıştırabiliriz, örneğin:

$ hello=world bash -c 'echo $hello'
world

Değişkenleri yalnızca export variable=valuekabuktan veya komut dosyasından kullanarak ortama yerleştirebiliriz . Veya tamamen boş bir ortam ile bir komut çalıştırabiliriz env -c command arg1 arg2. Ancak, özellikle büyük harfli değişkenler kullanarak veya zaten var olan ortam değişkenlerinin üzerine yazarak ortamla uğraşmanız önerilmez. Standart olmasa da tavsiye edilir.

Konumsal parametreler için, bunları ayarlamanın yolu açıktır, sadece komuta ekleyin, ancak bunları diğer akıllıca ayarlamanın yanı sıra shiftkomut aracılığıyla bu parametrelerin listesini değiştirme yolları da vardır .

Sonuç olarak, bu ikisinin amacı farklıdır ve bir nedenle var olurlar. Umarım insanlar bu cevaptan biraz içgörü kazanırlar ve bu yanıtı yazmak benim için olduğu gibi okumak çok eğlenceliydi.


Set komutu hakkında not

setKomut, bu gibi manuel davranacaktır göre (Bash manuel, vurgu eklenmiştir):

Seçenekler olmadan, her kabuk değişkeninin adı ve değeri, o anda ayarlanan değişkenleri ayarlamak veya sıfırlamak için giriş olarak yeniden kullanılabilecek bir biçimde görüntülenir.

Diğer bir deyişle set, mesela bazıları çevrede olan kabuğa özgü değişkenlere bakar HOME. Buna karşılık komutlar , bir komutun çalıştığı gerçek ortam değişkenini beğenir envve printenvbakar. Ayrıca bkz bu .


"Etkileşimli kabukta, $ 1, $ 2 ve benzerlerine başvuramazsınız." Bunun doğrudan bir referansı var mı? Bunların etkileşimli bir kabuk ortamında ayarlandığı garip durumlarda karşılaştım ve bunun 'standart dışı' olarak kabul edilip edilmeyeceğinden emin değilim.
user5359531

@ user5359531 Dürüst olmak gerekirse, bunu nereden aldığımdan emin değilim. Muhtemelen 2017'de cevabı gönderdiğimde muhtemelen böyle bir şey yapamayacağınıza atıfta bulundum, 1="foo"ancak daha sonra POSIX tanımı ile bir "kelime" nin (değişken veya fonksiyon gibi bir nesnenin adı) başlayamadığını öğrendim. bir rakamla ( konuyla ilgili gönderdiğim bir soruya bakın ). Görünüşe göre konumsal parametreler bu kurala istisnadır.
Sergiy Kolodyazhnyy

@ user5359531 Özellikle doğru olmadığı için cevabın bir kısmını kaldırdım. Başvurabileceğiniz $1, $2vb etkileşimli kabukta ve ile bitti aslında setkomuta, genellikle etrafında almak /bin/shdiziler olmamasından sınırlandırılmasını. Bunu dikkatime sunduğunuz için teşekkürler. Ayrıca, bir kaç ekstra cilaya ve bir güncellemeye ihtiyaç duyduğundan, cevabı önümüzdeki birkaç gün içinde düzenleyeceğim.
Sergiy Kolodyazhnyy

Açıklama için teşekkürler. I am having problem ile olmasıdır condaçalıştırdığınızda, source conda/bin/activate, ister için denetler $1, $2vb, bu argümanları veya olmasın bir komut dosyası olarak çalıştırıldı olmadığını belirlemek amacıyla, ayarlanır. Bu, bir nedenden ötürü etkileşimli ortamda ayarlanan sistemlere son verir. Bu standart dışı davranışın etkileşimli ortamda bu değişkenleri ayarlamak için sistemde bir kusur olup olmadığını veya bir komut dosyası olarak çalıştırılıp çalıştırılmadığını belirlemek için bunları kullanmak için programda anlamaya umuyorum.
user5359531

@ user5359531 Parametreleri condakontrol etmek ${N}kesinlikle yanlış yol olduğu için, geliştiricilere veya böyle bir komut dosyasının orijinal yazarı olana bir hata raporu göndermenizi öneririm . Burada ve burada aynı konuyla ilgili sorular var ve daha fazla veya daha az taşınabilir yol, ${0}komut dosyası adıyla aynı olup olmadığını kontrol etmektir, bashaslında bu amaç için ortam değişkeni vardır
Sergiy Kolodyazhnyy

4

$1, $2, $3, ..., ${10}, ${11}Değişkenler konumsal parametreler denir ve bash manuel bölümünde kaplıdır3.4.1

3.4.1 Konumsal Parametreler

Konumsal parametre, tek basamaklı 0 dışında bir veya daha fazla basamakla gösterilen bir parametredir. Konumsal parametreler çağrıldığında kabuğun bağımsız değişkenlerinden atanır ve set yerleşik komutu kullanılarak yeniden atanabilir. Konumsal parametre N'ye $ {N} veya N tek bir rakamdan oluştuğunda $ N olarak atıfta bulunulabilir. Konum parametreleri, atama ifadeleriyle atanamaz. Set ve shift yerleşimleri bunları ayarlamak ve ayarlamak için kullanılır (bkz. Kabuk Yerleşik Komutları). Kabuk işlevi yürütüldüğünde konumsal parametreler geçici olarak değiştirilir (bkz. Kabuk İşlevleri).

Tek basamaktan fazlasını içeren bir konum parametresi genişletildiğinde, küme parantezleri içine alınmalıdır.

Ve için $?ise $0, bu özel parametreler bir sonraki bölümde ele alınmıştır.3.4.2

3.4.2 Özel Parametreler

Kabuk birkaç parametreyi özel olarak ele alır. Bu parametrelere yalnızca başvurulabilir; bunlara atanmasına izin verilmez.

...

?

($?) En son yürütülen ön plan boru hattının çıkış durumuna genişler.

0

($ 0) Kabuk veya kabuk betiğinin adına genişler. Bu kabuk başlatma sırasında ayarlanır. Bash bir komut dosyasıyla çağrılırsa (bkz. Kabuk Betikleri), $ 0 o dosyanın adına ayarlanır. Bash -c seçeneğiyle başlatılırsa (bkz. Bash Çağırma), varsa 0 $ yürütülecek dizeden sonraki ilk bağımsız değişken olarak ayarlanır. Aksi takdirde, sıfır argümanı tarafından verildiği gibi Bash'i çağırmak için kullanılan dosya adına ayarlanır.


4

$1, $2... konumsal parametrelerdir , ortam değişkenleri değil, değişken değildirler.

Bourne gibi kabuk terminoloji olarak $somethingadlandırılan bir parametre genişleme (aynı zamanda kapak ${something#pattern}ve benzeri bazı kabukları ${array[x]}, ${param:offset}, ${x:|y}ve çok daha fazla genleşme operatörleri).

Farklı türde parametreler vardır:

  • gibi değişkenler$foo ,$PATH
  • konumsal parametreler ( $1, $2... betiğinizin aldığı bağımsız değişkenler)
  • diğer özel parametreler gibi $0, $-, $#, $*, $@, $$, $!, $?...

Bourne'daki kabuklar gibi değişken isimler bir alfabetik karakterle (yerel ayar tarafından tanınan veya kabuğa bağlı olarak a-zA-Z ile sınırlı) ve alt çizgi ile başlamalı ve ardından sıfır veya daha fazla alfasayısal karakter veya alt çizgi içermelidir.

Kabuğa bağlı olarak, değişkenler farklı türlere (skaler, dizi, karma) sahip olabilir veya belirli özellikler (salt okunur, dışa aktarılmış, küçük harf ...) verilebilir.

Bu değişkenlerin bazıları kabuk tarafından oluşturulan veya kabuğuna özel anlama sahip olan (gibi $OPTIND, $IFS, $_...)

Export özelliğine sahip kabuk değişkenleri , kabuğun yürüttüğü komutlara otomatik olarak ortam değişkeni olarak dışa aktarılır.

Ortam değişkeni kabuk değişkenlerinden ayrı bir kavramdır. Bir kabuk değişkenini dışa aktarmak, bir ortam değişkenini komutun yürütülmesine geçirmenin tek yolu değildir.

VAR=foo
export VAR
printenv VAR

komuta bir VARortam değişkeni printenviletir (içeriğini yazdırmayı söylüyoruz), ancak şunları da yapabilirsiniz:

env VAR=foo printenv VAR

veya:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

Örneğin.

Ortam değişkenleri herhangi bir ada sahip olabilir (herhangi bir karakter içerebilir ancak =boş da olabilir). Bir ortam değişkenine Bourne benzeri kabuk değişkeni adıyla uyumlu olmayan bir ad vermek iyi bir fikir değildir, ancak mümkündür:

$ env '#+%=whatever' printenv '#+%'
whatever

Onlar Kabuklar ortam değişkenleri eşler almak sadece ismi geçerli kabuk değişkenleri (ve bazı kabukları gibi bazı özel olanları görmezden olanlar ortam değişkenleri için değişkenleri kabuk için $IFS).

Böylece, 1bir komuta ortam değişkeni iletebileceksiniz :

$ env '1=whatever' printenv 1
whatever

Bu, bu ortam değişkeniyle bir kabuk çağrıldığında $1parametrenin değerini ayarlayacağı anlamına gelmez :

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo

3

Hayır, bunlar komut dosyasının parametreleri. Örneğin betiğinizi şöyle çağırırsanız:

mynicescript.sh one two three

daha sonra komut dosyasının içinde şu parametreler bulunur:

$1 = one
$2 = two
$3 = three

$ 0 ise betiğin kendisinin adıdır.

Komut dosyasının dışında olduğunuzda, bu değişkenler kullanılamaz (/ bin / bash - kabuğun kendisini gösteren 0 $ hariç).


"Yani komut dosyasının dışında olduğunuzda, bu değişkenler kullanılamaz" Terminalin içinde bu değişkenlerin değerlerini görebildiğim için "komut dosyasının dışında " ile ne demek istiyorsun .
user7681202

2
@ user7681202: Terminalinizde hangilerini görebilirsiniz? $0geçerli terminal işleminize (muhtemelen bash) işaret eder ve $?yalnızca son işlemin çıkış kodudur.
Jesse_b

The gnome-terminalarguments ( gnome-terminal Hello World) ile çalıştırmayı denedim . Görebiliyordum $0ama göremiyordum $1ve $2.
user7681202

@Jesse_b Teşekkür ederim, cevaba 0 dolarlık içeriği ekledim.
Jaroslav Kucera

1
@ user7681202 GNOME terminali kabuk değil, terminal emülatörüdür (xterm, konsole vb. gibi). Kabuk terminalin içinde çalışır ve bash / sh / zsh / tcsh ve daha fazlası olabilir. Komut dosyası, uygun başlık (#! / Bin / bash gibi) ve maskede belirtilen kabuk tarafından yorumlanabilen yürütülebilir dosyadır. Genellikle .sh
Jaroslav Kucera
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.