Neden bütün bir bash betiğini fonksiyonlara yazmalı?


59

İşte, bash scriptlerini sık sık yazıyorum. Danışmanım, aşağıdaki komut örneğine benzer bir şekilde tüm komut dosyasının fonksiyonlara bölünmesini önerdi:

#!/bin/bash

# Configure variables
declare_variables() {
    noun=geese
    count=three
}

# Announce something
i_am_foo() {
    echo "I am foo"
    sleep 0.5
    echo "hear me roar!"
}

# Tell a joke
walk_into_bar() {
    echo "So these ${count} ${noun} walk into a bar..."
}

# Emulate a pendulum clock for a bit
do_baz() {
    for i in {1..6}; do
        expr $i % 2 >/dev/null && echo "tick" || echo "tock"
        sleep 1
    done
}

# Establish run order
main() {
    declare_variables
    i_am_foo
    walk_into_bar
    do_baz
}

main

Bunu, birkaç yorum ve bazı satır aralıklarında eşit derecede iyi kurulabileceğini düşündüğüm “okunabilirlik” dışında yapmak için herhangi bir neden var mı?

Komut dosyasının daha verimli çalışmasını sağlıyor mu (gerçekten varsa bir tersini beklerdim) veya kodu yukarıda belirtilen okunabilirlik potansiyelinin ötesinde değiştirmeyi kolaylaştırıyor mu? Yoksa bu gerçekten sadece bir stilistik tercih mi?

Lütfen senaryoyu iyi göstermemesine rağmen, asıl komut dosyalarımızdaki fonksiyonların "çalıştırma sırası" çok doğrusal olma eğilimindedir - walk_into_baryapılan şeylere bağlıdır i_am_foove do_bazayarlanan şeylere göre hareket eder walk_into_bar- öyleyse rastgele çalıştırma sırasını değiştirebilmek genel olarak yapacağımız bir şey değildir. Örneğin, aniden koymak istemem declare_variablessonra walk_into_barşeyleri kırmak olacağını.

Yukarıdaki betiği nasıl yazacağımın bir örneği:

#!/bin/bash

# Configure variables
noun=geese
count=three

# Announce something
echo "I am foo"
sleep 0.5
echo "hear me roar!"

# Tell a joke
echo "So these ${count} ${noun} walk into a bar..."

# Emulate a pendulum clock for a bit
for i in {1..6}; do
    expr $i % 2 >/dev/null && echo "tick" || echo "tock"
    sleep 1
done

30
Patronunu beğendim. Senaryolarımda ayrıca main()üstüne koyup main "$@"çağırmak için altına ekledik. Bu, ilk açtığınızda üst düzey komut dosyası mantığını görmenizi sağlar.
John Kugelman

22
Okunabilirliğin "birkaç yorum ve bazı satır aralıklarıyla eşit derecede iyi tesis edilebileceği" fikrine katılmıyorum. Belki kurgu dışında, her bölüm ve bölüm için bir içindekiler tablosu ve açıklayıcı isimler içermeyen bir kitapla uğraşmak istemem. Programlama dillerinde, işlevlerin sağlayabildiği bir tür okunabilirlik budur ve yorum yapamaz.
Rhymoid 30:16

6
İşlevlerde bildirilen değişkenlerin bildirilmesi gerektiğini unutmayın local- bu, önemsiz olmayan herhangi bir komut dosyasında inanılmaz derecede önemli olan değişken kapsamı sağlar .
Örümcek Boris,

8
Patronuna katılmıyorum. Komut dosyanızı işlevlere ayırmanız gerekiyorsa, muhtemelen en başta bir kabuk komut dosyası yazmamalısınız. Bunun yerine bir program yazın.
el.pescado

6
İşlevler, komut dosyası içinde veya birden fazla komut dosyasında yinelenen işlemler içindir. Ayrıca, üniform metodolojilerin yerine getirilmesine izin verir. Örneğin syslog'a yazmak için bir fonksiyon kullanmak. Herkes aynı işlevi kullandığı sürece, syslog girişleriniz daha tutarlıdır. Tek kullanımlık örneğiniz gibi işlevler gereksiz yere betiği karmaşıklaştırır. Bazı durumlarda, sorunları ortaya koyarlar (değişken kapsam belirleme).
Xalorous

Yanıtlar:


39

Kfir Lavi'nin "Defensive Bash Programming" blog yazısını okuduktan sonra bu aynı bash programlama stilini kullanmaya başladım . Epeyce iyi sebepler veriyor ama ben şahsen bunları en önemli buluyorum:

  • prosedürler açıklayıcı hale gelir: kodun belirli bir bölümünün ne yapması gerektiğini anlamak çok daha kolaydır. Kod duvarı yerine "Ah, find_log_errorsişlev bu günlük dosyasını hatalar için okur " u görürsünüz . Tanrının kullanıldığı tüm awk / grep / sed satırlarını bulmakla karşılaştırın, uzun bir komut dosyasının ortasında ne tür bir regex olduğunu biliyor - yorum yapmadıkça orada ne yaptığını bilmiyorsunuz.

  • set -xve içine ekleyerek işlevleri hata ayıklayabilirsiniz set +x. Kodun geri kalanının iyi çalıştığını öğrendikten sonra, bu numarayı yalnızca belirli bir işlevde hata ayıklamaya odaklanmak için kullanabilirsiniz. Tabii ki, senaryonun bölümlerini içine alabilirsin, ama eğer uzun bir bölümse? Böyle bir şey yapmak daha kolaydır:

     set -x
     parse_process_list
     set +x
  • baskı kullanımı ile cat <<- EOF . . . EOF. Kodumu daha profesyonel hale getirmek için birkaç kez kullandım. Buna ek olarak, parse_args()birlikte getoptsfonksiyonu oldukça uygundur. Yine, bu, her şeyi metnin dev duvarı olarak senaryoya sokmak yerine okunabilirliğe yardımcı olur. Bunları tekrar kullanmak da uygundur.

Ve tabii ki, bu C veya Java'yı veya Vala'yı bilen, ancak sınırlı bash tecrübesi olan biri için çok daha okunaklı. Verimlilik söz konusu olduğunda yapabileceklerinizden çok şey yoktur - bash en verimli dil değildir ve insanlar hız ve verimlilik söz konusu olduğunda perl ve python'u tercih ederler. Ancak, nicebir işlevi yapabilirsiniz :

nice -10 resource_hungry_function

Her kod satırında hoş bir çağrı yapmakla kıyaslandığında, bu tüm yazmayı çok azaltır ve komut dosyanızın yalnızca bir bölümünün daha düşük önceliğe sahip olmasını istediğinizde rahatlıkla kullanılabilir.

Arka planda çalışan işlevleri, benim görüşüme göre, arka planda çalıştırmak için tüm ifadeler demet istediğinizde de yardımcı olur.

Bu stili kullandığım örneklerden bazıları:


3
Bu yazının herhangi bir önerisini çok ciddiye almanız gerektiğinden emin değilim. Kabul edilirse, birkaç iyi fikri vardır, fakat açıkça betik yazmayı amaçlayan biri değildir. Örneklerin hiçbirinde tek bir değişken değil (!) Alıntılanmıştır ve mevcut env değişkenleriyle çakışabildiklerinden genellikle çok kötü bir fikir olan UPPER CASE değişken adlarının kullanılmasını önermektedir. Sizin bu yanıtında noktalar mantıklı fakat bağlantılı makale sadece diğer dillere kullanılır ve bash üzerine kendi tarzını zorlamak için çalışan biri tarafından yazıldığı gibi görünüyor.
terdon

1
@ terdon Makaleye geri döndüm ve tekrar okudum. Yazarın büyük harfli değişken isimlendirmesinden söz ettiği tek yer "Değiştirilebilir Global Değişkenler" dir. Global değişkenleri, fonksiyonun ortamında olması gerekenler olarak görürseniz, bunları sermaye haline getirmek mantıklı olur. Yan notta, bash el kitabında değişken durum için bir sözleşme belirtilmemiştir. Burada bile kabul edilmiş cevap "genellikle" diyor ve tek "standart" tüm BT endüstrisini temsil etmeyen Google’dan geliyor.
Sergiy Kolodyazhnyy

Bir başka notta @ terdon, makalede değişken alıntıdan bahsedilmesi gerektiği ve blogdaki yorumlarda da belirtildiği gibi% 100 katılıyorum. Ayrıca, başka bir dile alışık olup olmadıklarına bakılmaksızın, bu kodlama tarzını kullanan birini yargılamam. Tüm bu soru ve cevaplar açıkça bunun avantajları olduğunu gösteriyor ve kişinin başka bir dile alıştıkları derecesi muhtemelen burada önemli değil.
Sergiy Kolodyazhnyy

1
@terdon kuyusu, makale "kaynak" malzemenin bir parçası olarak gönderildi. Her şeyi kendi düşüncelerim olarak yayınlayabilirdim, ancak makaleden öğrendiğim bazı şeylerin ve zamanla bunların araştırılmasından kaynaklandığına dair kredi vermek zorunda kaldım. Yazarın linkedin sayfası genel olarak Linux ve IT ile iyi bir deneyime sahip olduklarını gösteriyor, bu yüzden makalenin gerçekten göstermediğini tahmin ediyorum, ancak Linux ve kabuk komut dosyası konusunda deneyiminize güveniyorum, bu yüzden haklı olabilirsiniz. .
Sergiy Kolodyazhnyy

1
Bu mükemmel bir cevap ama ben Bash'deki değişken kapsamı eklemek çok eğlenceli. Bu nedenle değişkenlerimi işlevler içinde kullanarak localve çağırmak suretiyle main()işlevlerimin içinde bildirmeyi tercih ederim . Bu, işleri daha yönetilebilir hale getirir ve potansiyel olarak dağınık bir durumdan kaçınabilirsiniz.
Housni

65

Okunabilirlik bir şeydir. Ancak, modülerleşmenin sadece bundan daha fazlası var . ( Yarı modülerleştirme belki fonksiyonlar için daha doğrudur.)

Fonksiyonlarda bazı değişkenleri yerel olarak tutabilirsiniz, bu da güvenilirliği artırarak işlerin karışması olasılığını azaltır.

Diğer bir fonksiyon uzmanı yeniden kullanılabilirliktir . Bir fonksiyon kodlandıktan sonra, komut dosyasında birçok kez uygulanabilir. Ayrıca başka bir betiğe de yerleştirebilirsiniz.

Kodunuz şimdi doğrusal olabilir, ancak gelecekte Bash dünyasında çoklu iş parçacığı veya çoklu işlem alanlarına girebilirsiniz . İşlevlerde bir şeyler yapmayı öğrendiğinizde, paralel adım için iyi bir donanıma sahip olacaksınız.

Eklemek için bir nokta daha. Etsitpab Nioliv aşağıdaki yorumda dikkat çektiği gibi, fonksiyonlardan tutarlı bir varlık olarak yönlendirmek kolaydır. Ancak, işlevli yönlendirmelerin bir yönü daha var. Yani, yeniden yönlendirme fonksiyon tanımı boyunca ayarlanabilir. Örneğin.:

f () { echo something; } > log

Artık işlev çağrıları için açık bir yeniden yönlendirme gerekmez.

$ f

Bu, birçok tekrarlamayı kaldırabilir, bu da tekrar güvenilirliği arttırır ve işleri düzenli tutmaya yardımcı olur.

Ayrıca bakınız


55
Çok iyi cevap olsa da, fonksiyonlara ayrılsaydı daha iyi olurdu.
Pierre Arlaud

1
Belki de bu işlevleri başka bir komut dosyasına içe aktarmanıza olanak sağlar ( sourceya da . scriptname.sh, ve bu işlevleri yeni komut dosyanızda olduğu gibi kullanın.)
SnakeDoc

Bu zaten başka bir cevapta ele alındı.
Tomasz

1
Buna minnettarım. Ama diğer insanların da önemli olmasına izin vermeyi tercih ederim.
Tomasz

7
Bugün, bir betiğin çıktısının bir kısmını eko yapmak yerine bir dosyaya (e-postayla göndermek için) yönlendirmek zorunda kaldığım bir durumla karşılaştım. İstenilen fonksiyonların çıkışını yönlendirmek için myFunction >> myFile yapmak zorunda kaldım. Oldukça uygun. İlgili olabilir.
Etsitpab Nioliv

39

Benim yorumumda, fonksiyonların üç avantajından bahsettim:

  1. Doğruluğunu test etmek ve doğrulamak kolaydır.

  2. İşlevler gelecekteki komut dosyalarında kolayca yeniden kullanılabilir (kaynak olarak kullanılabilir)

  3. Patronun onlardan hoşlanıyor.

Ve hiçbir zaman 3 numaraların önemini küçümseme.

Bir konuyu daha ele almak istiyorum:

... dolayısıyla çalışma sırasını keyfi bir şekilde değiştirebilmek genel olarak yapacağımız bir şey değil. Örneğin, aniden koymak istemem declare_variablessonra walk_into_barşeyleri kırmak olacağını.

Kodları fonksiyonlara bölme avantajından yararlanmak için, fonksiyonların mümkün olduğunca bağımsız olmasına çalışılmalıdır. Başka walk_into_baryerde kullanılmayan bir değişken gerektiriyorsa, bu değişken tanımlanmalı ve yerel olarak belirtilmelidir walk_into_bar. Kodu işlevlere ayırma ve bağımlılıklarını en aza indirme süreci kodu daha net ve basit hale getirmelidir.

İdeal olarak, fonksiyonların ayrı ayrı test edilmesi kolay olmalıdır. Eğer etkileşimlerden dolayı test edilmesi kolay değilse, bu yeniden yapılanmadan fayda sağlayabileceklerinin bir işaretidir.


Bu bağımlılıkları modellemenin ve uygulamanın bazen mantıklı olduğunu savunuyorum, onlardan kaçınmak için yeniden refaktasyona uğramak (çünkü eğer yeterince varsalar ve yeterince kıllılarsa, bu durumların artık modüler hale gelmediği bir duruma yol açabilir) tüm işlevler). Çok karmaşık kullanımlı bir durum bir zamanlar bunun için bir çerçeveye ilham verdi .
Charles Duffy

4
Fonksiyonlara bölünmesi gereken şey olmalı, ancak örnek çok ileri götürüyor. Beni gerçekten rahatsız eden tek şeyin değişken bildirim işlevi olduğunu düşünüyorum. Global değişkenler, özellikle statik olanlar, global olarak bu amaca yönelik yorumlanmış bir bölümde tanımlanmalıdır. Dinamik değişkenler, bunları kullanan ve değiştiren işlevlerde yerel olmalıdır.
Xalorous

@Xalorous Küresel değişkenlerin bir prosedürde başlatılmış olduğu bir uygulama gördüm , değerlerini harici bir dosyadan okuyan bir prosedür geliştirilmeden önce orta ve hızlı bir adım olarak ... Tanımlamayı ayırmanın daha temiz olması gerektiğine katılıyorum. başlatma, ancak nadiren, 3;-)
16’daki

13

Kodu, C / C ++, python, perl, ruby ​​veya herhangi bir programlama dili kodu için yaptığınız gibi, fonksiyonlara bölersiniz. Daha derin sebep soyutlamadır - daha düşük seviyeli görevleri daha üst seviyedeki ilkellere (fonksiyonlara) dahil edersiniz, böylece işlerin nasıl yapıldığına zahmet etmenize gerek kalmaz. Aynı zamanda, kod daha okunaklı (ve sürdürülebilir) hale gelir ve program mantığı daha belirgin hale gelir.

Ancak, kodunuza bakarak, değişkenleri bildirmek için bir işleve sahip olmak oldukça tuhaf buluyorum; Bu gerçekten beni bir göz kaş yükselişi yapar.


Yetersiz yanıt IMHO. mainÖyleyse , işlev / yöntem içindeki değişkenleri bildirmeyi önerir misiniz ?
David Tabernero M.,

12

Patronların yeniden kullanılabilirliği , okunabilirliği ve dikkatlice öpülmesi ile tamamen aynı fikirdeyken , fonksiyonlarının bir başka avantajı var : değişken kapsam . As LDP gösterileri :

#!/bin/bash
# ex62.sh: Global and local variables inside a function.

func ()
{
  local loc_var=23       # Declared as local variable.
  echo                   # Uses the 'local' builtin.
  echo "\"loc_var\" in function = $loc_var"
  global_var=999         # Not declared as local.
                         # Therefore, defaults to global. 
  echo "\"global_var\" in function = $global_var"
}  

func

# Now, to see if local variable "loc_var" exists outside the function.

echo
echo "\"loc_var\" outside function = $loc_var"
                                      # $loc_var outside function = 
                                      # No, $loc_var not visible globally.
echo "\"global_var\" outside function = $global_var"
                                      # $global_var outside function = 999
                                      # $global_var is visible globally.
echo                      

exit 0
#  In contrast to C, a Bash variable declared inside a function
#+ is local ONLY if declared as such.

Bunu gerçek dünyadaki kabuk komut dosyalarında çok sık görmüyorum, ancak daha karmaşık komut dosyaları için iyi bir fikir gibi görünüyor. Azaltılması uyum kod başka bir bölümünde beklenen bir değişken clobbering ediyoruz hataları önlemeye yardımcı olur.

Yeniden kullanılabilirlik, genellikle ortak bir işlev kütüphanesi oluşturmak ve sourcebu kütüphaneyi tüm komut dosyalarınıza eklemek anlamına gelir . Bu onların daha hızlı çalışmasına yardımcı olmaz, ancak onları daha hızlı yazmanıza yardımcı olur.


Çok az insan açıkça kullanıyor local, ama bence çoğu kişi senaryolara ayrılmış senaryolar yazıyor. Usign, localsadece hataların ortaya çıkmasını zorlaştırır.
Voo

localdeğişkenleri işleve ve onun çocuklarına uygun kılar, bu nedenle, işlev A'dan aşağıya aktarılabilen bir değişkene sahip olmak gerçekten güzeldir, ancak aynı isimle fakat farklı amaçlara sahip değişken isteyebilecek olan B işlevi için kullanılamaz. Bu, kapsamı tanımlamak için iyi bir şey ve Voo'nun dediği gibi - daha az hata
Sergiy Kolodyazhnyy

10

Halihazırda diğer cevaplarda verilenlerden tamamen farklı bir neden: Bu tekniğin bazen kullanılmasının bir nedeni, üst düzeydeki tek işlev tanımı olmayan ifadenin çağrılmasıdır main, komut dosyasının yanlışlıkla kötü bir şey yapmamasını sağlamak komut dosyası kesilmişse. A işleminden B işlemine (kabuk) kadar bağlanırsa, komut dosyası kesilebilir ve A işlemi, tüm komut dosyasını yazmadan önce herhangi bir nedenle sona erer. Bu, özellikle A işlemi betiği uzak bir kaynaktan alırsa gerçekleşir. Güvenlik nedeniyle bu iyi bir fikir değildir, ancak yapılması gereken bir şeydir ve bazı senaryolar sorunu öngörmek için değiştirilmiştir.


5
İlginç! Ancak bunun programların her birinde bu şeylerle ilgilenmesi gerektiğini rahatsız edici buluyorum. Öte yandan, bu main()model tam olarak Python'da olağandır ve burada if __name__ == '__main__': main()dosyanın sonunda kullanılır.
Martin Ueding

1
Python deyimi, diğer betiklerin importgeçerli betiği çalıştırmadan çalıştırmasına izin verme avantajına sahiptir main. Sanırım benzer bir gardiyan bash betiğine yerleştirilebilir.
Jake Cobb

@Jake Cobb Evet. Bunu şimdi tüm yeni bash scriptlerinde yapıyorum. Tüm yeni komut dosyalarının kullandığı temel işlev altyapısını içeren bir komut dosyasını kullanıyorum. Bu senaryo kaynak veya çalıştırılabilir. Kaynaklanırsa, ana işlevi yerine getirilmez. Kaynağa karşı yürütmenin algılanması, BASH_SOURCE uygulamasının yürütme komut dosyasının adını içermesi nedeniyle gerçekleşir. Çekirdek komut dosyasıyla aynıysa, komut dosyası yürütülmektedir. Aksi takdirde, kaynak ediliyor.
DocSalvager

7

Bir işlem bir dizi gerektirir. Çoğu görev sıralıdır. Siparişi karıştırmak hiç mantıklı değil.

Ancak programlama hakkında - komut dosyası içeren - süper büyük şey test ediyor. Test etme, test etme, test etme. Hangi test komut dosyalarının şu anda komut dosyalarınızın doğruluğunu onaylaması gerekiyor?

Patronunuz bir senaryo çocuğu olmaktan programcı olmak için size rehberlik etmeye çalışıyor. Bu, içeri girmek için iyi bir yön. Sizden sonra gelen insanlar sizden hoşlanacak.

FAKAT. Proses odaklı köklerinizi daima hatırlayın. İşlevlerin tipik olarak yürütüldükleri sıraya göre düzenlenmiş olması mantıklıysa, en azından ilk geçiş olarak yapın.

Daha sonra, bazı işlevlerinizin girdi işleme, diğerleri çıktı, diğerleri işleme, diğerleri modelleme verileri ve diğerlerinin verileri işlediğini göreceksiniz. Bu nedenle, benzer yöntemleri gruplamak akıllıca olabilir, hatta bunları ayrı dosyalara bile ayırabilirsiniz. .

Daha sonra, şimdi komut dosyalarınızın çoğunda kullandığınız küçük yardımcı fonksiyonların kütüphanelerini yazdığınızı fark edebilirsiniz.


6

Yorum ve aralık olabilir değil fonksiyonları, ben gösterecektir gibi okunabilirliği yakın yerde olsun. İşlevler olmadan ağaçları ormanı göremezsiniz - büyük sorunlar birçok ayrıntıya gizlenir. Başka bir deyişle, insanlar eşzamanlı olarak ince detaylara ve büyük resme odaklanamazlar. Bu kısa bir komut dosyasında açık olmayabilir; Kısa kaldığı sürece yeterince okunabilir. Yazılım daha da büyür, fakat küçülmez ve kesinlikle şirketinizin tüm yazılım sisteminin bir parçasıdır, bu kesinlikle çok daha büyük, muhtemelen milyonlarca satırdır.

Size bunun gibi talimatlar verip vermediğimi düşünün:

Place your hands on your desk.
Tense your arm muscles.
Extend your knee and hip joints.
Relax your arms.
Move your arms backwards.
Move your left leg backwards.
Move your right leg backwards.
(continue for 10,000 more lines)

Yarı yarıya, hatta% 5'ine kadar, ilk birkaç adımın ne olduğunu unutmuş olacaktın. Sorunların çoğunu tespit edemezsiniz, çünkü ağaçlar için ormanı göremiyordunuz. İşlevlerle karşılaştırın:

stand_up();
walk_to(break_room);
pour(coffee);
walk_to(office);

Satır sıralı versiyona kaç yorum yazdığınızdan bağımsız olarak, bu kesinlikle çok daha anlaşılabilir bir durumdur. Aynı zamanda kahveyi yapmayı unuttuğunuzu ve sonunda sit_down () kodunu unuttuğunuzu fark etmenizi çok daha muhtemel hale getirir . Zihniniz grep ve awk regex'lerin detaylarını düşünürken, büyük resmi düşünemezsiniz - "ya kahve yapılmazsa?"

İşlevler temel olarak büyük resmi görmenize ve kahveyi yapmayı unuttuğuna (veya birinin çayı tercih edebileceğine) dikkat edin. Başka bir zamanda, farklı bir zihin çerçevesinde, detaylı uygulama için endişeleniyorsunuz.

Elbette diğer cevaplarda tartışılan başka faydalar da vardır. Diğer cevaplarda açıkça belirtilmeyen bir başka yarar, fonksiyonların hataları önlemede ve düzeltmede önemli olan bir garanti vermesidir. Walk_to () işlevindeki $ foo değişkeninin yanlış olduğunu keşfederseniz, bu sorundan etkilenebilecek her şeyi ve bu sorundan etkilenebilecek her şeyi bulmak için bu işlevin yalnızca 6 satırına bakmanız gerektiğini bilirsiniz. yanlış olmasına neden oldu. (Uygun) işlevler olmadan, sistemdeki her şey ve her şey $ foo'nun yanlış olmasının bir nedeni olabilir ve her şey ve her şey $ foo'dan etkilenebilir. Bu nedenle, programın her satırını yeniden incelemeden $ foo'yu güvenle düzeltemezsiniz. $ Foo bir işleve yerelse,


1
Bu bashsözdizimi değil . Yine de ayıp; Bu gibi fonksiyonlara girdi aktarmanın bir yolu olduğunu sanmıyorum. (yani pour();< coffee). Daha çok benziyor c++ya da php(sanırım).
sesler

2
Parantez olmadan @ tjt263, bu bash sözdizimi: dökün kahve. Parens ile, hemen hemen her dilde. :)
Ray Morris

5

Programlama ile ilgili bazı gerçekçilikler:

  • Patronunuz böyle olmadığı konusunda ısrar etse bile , programınız değişecektir .
  • Yalnızca kod ve giriş programın davranışını etkiler.
  • Adlandırma zor.

Yorumlar, fikirlerinizi * kodunda açık bir şekilde ifade edememek ve değişiklikle daha kötü (ya da sadece yanlış) olsun diye durma boşluğu olarak başlar. Bu nedenle, eğer mümkünse, kavramları, yapıları, akıl yürütmeyi, anlambilimi, akışı, hata işlemeyi ve kodun kod olarak anlaşılmasıyla ilgili her şeyi ifade edin .

Bununla birlikte, Bash işlevlerinin çoğu dilde bulunmayan bazı sorunları vardır:

  • İsim boşlukları Bash'de korkunç. Örneğin, localanahtar sözcüğü kullanmayı unutmak , genel ad alanını kirletmekle sonuçlanır.
  • Kullanılması local foo="$(bar)"sonuçları kaybetme çıkış kodunubar .
  • Adlandırılmış parametre yoktur, bu nedenle "$@"farklı bağlamlarda ne anlama geldiğini aklınızda tutmalısınız .

* Bu rahatsız edici olursa özür dilerim, ancak birkaç yıl boyunca yorumları kullandıktan ve onlarsız geliştirdikten sonra ** daha uzun yıllar hangisinin daha iyi olduğu açıkça görülüyor.

** Lisanslama için yorumların kullanılması, API dokümantasyonu ve benzerleri hala gereklidir.


Ben ... fonksiyonun başında null onları bildirerek neredeyse tüm yerel değişkenleri ayarlamak local foo=""Sonra ... sonuçlara göre hareket etme komutu yürütme kullanarak onları ayar foo="$(bar)" || { echo "bar() failed"; return 1; }. Bu, gerekli bir değer ayarlanamadığında bizi hızlı bir şekilde fonksiyondan kurtarır. Kıvrımlı kaşlı ayraçlar return 1, yalnızca arıza durumunda çalıştırıldığından emin olmak için gereklidir .
DocSalvager

5

Vakit nakittir

Orada diğer iyi cevaplar yazmak için teknik nedenlerden ışık yaymak modüler tarafından kullanılmak üzere geliştirilen bir çalışma ortamında geliştirilen potansiyel olarak uzun bir komut dosyası,, kişilik bir grup ve kendi kullanımı için değil sadece.

Beklediğim şeye odaklanmak istiyorum : çalışma ortamında "zaman paradır" . Böylelikle hataların olmaması ve kodunuzun performansları okunabilirlik , test edilebilirlik, bakım kolaylığı, yeniden üretilebilirlik, tekrar kullanılabilirlik ile birlikte değerlendirilir ...

Yazısında "modüller" bir kodla sadece gerekli okuyarak vakit azalacaktır kodlayıcı kendisi ancak test veya patron tarafından kullanılan hatta zaman. Ayrıca, bir patronun zamanının genellikle bir kodlayıcının zamanından daha fazla ödendiğini ve patronunuzun işinizin kalitesini değerlendireceğini unutmayın.

Ayrıca, bağımsız "modüllere" bir kod (bir bash betiği bile) yazmak, ekibinizin diğer bileşenleriyle "paralel" olarak çalışmanıza olanak tanır ve toplam üretim süresini kısaltır ve en iyi kişinin uzmanlığını kullanarak, bir parçayı gözden geçirir veya yeniden yazar. Diğerleri üzerinde hiçbir yan etkisi yoktur, sadece "olduğu gibi" yazdığınız kodu geri dönüştürmek için kullanılır.başka bir program / komut dosyası için, kütüphaneler (veya snippet kütüphaneleri) oluşturmak, toplam boyutu ve ilgili hata olasılığını azaltmak, her bir parçanın hatalarını ayıklamak ve test etmek ... ve elbette mantıksal bölümünde programınızı organize edecektir. / script ve okunabilirliğini arttır. Zamandan ve paradan tasarruf edecek her şey. Dezavantajı standartlara bağlı kalmanız ve işlevlerinizi yorumlamanız (yine de bir çalışma ortamında yapmanız gereken).

Bir standarda uymak , başlangıçta çalışmanızı yavaşlatır, ancak daha sonra diğerlerinin (ve sizin de) çalışmasını hızlandıracaktır. Aslında, işbirliği katılan kişilerin sayısında büyüdüğünde, bu kaçınılmaz bir ihtiyaç haline gelir. Yani, örneğin, ben küresel değişkenler tanımlanmalıdır inanıyoruz bile küresel bir işlev değil, ben adında bir işlevi bunları inizializes bir standart anlayabileceği declare_variables()ilk satırında hep denilen main()biri ...

Son fakat en az değil, modern kaynak kod editörlerinde seçici olarak ayrı rutinler gösterme veya gizleme olasılığını hafife almayın ( Kod katlama ). Bu, kodu küçük tutar ve kullanıcıyı tekrar zaman kazanmaya odaklar.

görüntü tanımını buraya girin

Yukarıda, sadece fonksiyonun nasıl açıldığını görebilirsiniz walk_into_bar(). Her biri 1000 satır uzunluğunda olsalar bile, tüm kodları tek bir sayfada kontrol altında tutabilirsiniz. Değişkenleri bildirmek / başlatmak için gittiğiniz bölümün bile katlandığını unutmayın.


1

Diğer cevaplarda verilen sebeplerin yanı sıra:

  1. Psikoloji: Üretkenliği kod satırlarında ölçülen bir programcının gereksiz yere ayrıntılı kod yazması için bir teşvik olacaktır. Yönetim ne kadar fazla kod satırına odaklanıyorsa, programcının kodunu gereksiz karmaşıklıkla genişletmesi o kadar teşvik edicidir. Bu istenmeyen bir durumdur, çünkü artan karmaşıklık, bakım maliyetinin artmasına ve hata onarımı için gereken çabanın artmasına neden olabilir.

Cevapların söylediği gibi o kadar da kötü bir cevap değil. Not: agc diyor ki, bu da bir olasılık ve evet, öyle. Tek olasılık olacağını söylemez ve kimseyi suçlamaz, sadece gerçekleri belirtir. Her ne kadar bugün neredeyse hiç duyulmamış olsa da, doğrudan bir "kod satırı" -> "$$" tarzı sözleşme işi duyulmasa da, dolaylı olarak, oldukça yaygın olduğu, evet, üretilen kodun kütlesinin liderler / patronlar tarafından sayıldığı anlamına gelir.
kullanıcı259412

0

Genellikle göz ardı edilen başka bir neden bash'ın sözdizimi ayrıştırmasıdır:

set -eu

echo "this shouldn't run"
{
echo "this shouldn't run either"

Bu betik açıkça bir sözdizimi hatası içeriyor ve bash hiç çalışmamalı, değil mi? Yanlış.

~ $ bash t1.sh
this shouldn't run
t1.sh: line 7: syntax error: unexpected end of file

Kodu bir fonksiyona satarsak, bu olmaz:

set -eu

main() {
  echo "this shouldn't run"
  {
  echo "this shouldn't run either"
}

main
~ $ bash t1.sh
t1.sh: line 10: syntax error: unexpected end of file
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.