Bash değişkenlerini başlatma - İhtiyaç duyulur, tavsiye edilir veya giderken tanımlanır


9

Gerçek değer atanmadan önce koddaki bir bash değişkeninin değerini ana koddan önce veya bir işlevdeki yerel değişkenleri başlatmanın herhangi bir avantajı / dezavantajı var mı?

Böyle bir şey yapmam gerekiyor mu:

init()
{
    name=""
    name=$1
}

init "Mark"

Değişkenlerin çöp değerleriyle başlatılması (başlatılmamışsa) ve değişkenlerin değerlerini olumsuz etkileme riski var mı?


2
Bu fikri nereden buldun?

6
@DoritoStyle Eğer biri C gibi daha düşük seviyeli diller için kullanılıyorsa, bu endişe duyulması gereken son derece geçerli bir şeydir.
Kusalananda

@Kusalananda Bu kodun C eşdeğeri değil name = ""; name = argv[1];mi? Ve bu anlamsız değil mi?
Joseph Sible-Reinstate Monica

1
@ JosephSible-ReinstateMonica Evet. Gönderdiğiniz C kodu anlamsızdır. Bununla birlikte, C'de, kabuğun aksine, başlatılmamış değişkenlerin belirli bir iyi tanımlanmış değeri yoktur. Bu, C gibi dillerde değişkenlerin başlatılmasının birçok koşulda mantıklı olduğu anlamına gelir. Kabukta bunu yapmak gerekli değildir. Bir değişkeni yalnızca bir başka değere hemen ayarlamak için C'de başlatmak , işaret ettiğiniz gibi anlamsızdır.
Kusalananda

Yanıtlar:


22

Bir değişkene boş bir dize atamanın ve hemen ona bir başka değişken dize atamanın faydası yoktur. Kabuk değişkenine bir değer ataması, önceki değerinin tamamen üzerine yazılır.

Bildiğim kadarıyla, değişkenleri açıkça boş dizelere başlatmanız gerektiğini söyleyen hiçbir öneri yoktur. Aslında, bunu yapmak bazı durumlarda hataları maskeleyebilir (altında çalıştırılırsa açıkça görülen hatalar set -u, aşağıya bakın).

Komut dosyasının başlangıcından bu yana kullanılmayan veya unsetkomutun çalıştırılmasıyla açıkça ayarlanan bir kümelenmemiş değişkenin değeri olmayacaktır. Böyle bir değişkenin değeri hiçbir şey olmayacaktır. Eğer olarak kullanılırsa "$myvariable", eşdeğerini elde edersiniz ""ve asla "çöp verileri" elde edemezsiniz.

Kabuk seçeneği veya nounsetile ayarlanırsa , ayarlanmamış bir değişkene başvurmak kabuğun hata üretmesine neden olur (ve etkileşimli olmayan bir kabuk sona erer):set -o nounsetset -u

$ set -u
$ echo "$myvariable"
/bin/sh: myvariable: parameter not set

veya bash:

$ set -u
$ echo "$myvariable"
bash: myvariable: unbound variable

Değişkenin adı varolan bir ortam değişkenine karşılık geliyorsa, kabuk değişkenleri ortam tarafından başlatılır.

Ortam tarafından bu şekilde başlatılabilecek bir değişken (ve istenmeyen) kullanıyorsanız, komut dosyanızın ana bölümünden önce bunu açıkça kaldırabilirsiniz:

unset myvariable    # unset so that it doesn't inherit a value from the environment

bu da onu bir ortam değişkeni olarak kaldıracaktır ya da yalnızca başlangıç ​​değerini göz ardı edebilir ve bir atama ile üzerine yazabilirsiniz (bu da ortam değişkeninin değerini değiştirmesini sağlar).

Kabuk değişkeninde hiç başlatılmamış çöple karşılaşmazsınız (belirtildiği gibi, aynı adla bir ortam değişkeninde bu çöp zaten mevcut değilse).


3
Bir değişkeni boş bir değere ayarlamak ve hemen bunu tam anlamıyla OP olarak ayarlamak için bir değer olmamasına rağmen, hesaplanan bir değere ayarlamak için bir unsettür forveya whiledöngü çalıştırmadan önce boş bir değer (veya ting) ayarlamada değer vardır. Koşulların karşılanmadığı için döngünün gerçekte çalışma şansı yoksa değer; ve değişken, komut dosyasının miras aldığı ortamdaki başka bir değere ayarlanmış olabilir. Ancak her şeyi bir yere koymak main()ve değişkenleri olarak tanımlamak muhtemelen daha iyidir local.
Monty Harder

Ayrıca atlayarak, parametre genişletme operatörleri kullanarak tanımsız değişkenler tespit edebilir :, mesela${myvariable-defaultvalue}
barmar

3

Düzenleme : Hata! Açıkçası bildirim başlatmadan farklı. Bunu yine de burada bırakacağım, böylece benim gibi acemi kodlayıcıların hatamdan öğrenebilsinler.


Bir işlevde yerel değişkenleri bildirmenin avantajı, kodu kolayca kopyalayabilmenizdir.

Örneğin, bir fonksiyonum olduğunu varsayalım:

foo(){
    local name
    name="$1"
    echo "$name"
}

Bir betiğe dönüştürmek istiyorsanız, sadece localifadeyi görmezden gelir ve diğer her şeyi kopyalarım:

#!/bin/bash
name="$1"
echo "$name"

Beyan ve atama aynı satırdaysa, localparçayı bir betiğe dönüştürmeden önce el ile düzenlemem gerekir :

foo(){
    local name="$1"
    echo "$name"
}

Bu örnekte çok önemli değil, ancak daha büyük, daha karmaşık işlevlerle uğraşıyorsanız daha acı verici olabilir.


1
Soru, beyan ve başlatmayı birleştirmekle ilgili değildi. Gerçek bir değer atamadan önce boş bir değerle başlayıp başlamayacağınızla ilgiliydi.
Barmar

@Barmar Oh, sadece "başlatma" yı aradım. Ben "beyan" ile eşanlamlı olduğunu düşündüm ...
wjandrea
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.