Daha büyük komut dosyasını birden çok komut dosyasına bölmek ve bunları ana komut dosyasında kaynaklamak yaygın mıdır?


23

Şu anda daha büyük bir Bash senaryosu geliştiriyorum (bu benim açık kaynaklı bir projem) ve karışıklık yaratmaya başlıyor. Mantığı fonksiyonlara böldüm, yerel değişkenleri kullanabildiğim ve sadece birkaç genel değişken tanımladığım. Yine de bakımı oldukça zorlaşıyor.

Komut dosyasını çoklu komut dosyalarına bölmeyi ve ana komut dosyasımda (diğer dillerdeki içe aktarma işlemlerine benzer şekilde) kaynak yapmayı düşündüm.

Ama bunun uygulanabilir bir yaklaşım olup olmadığını merak ediyorum. İlk olarak, çok sayıda komut dosyası oluşturmak, komut dosyasının yürütme süresini ciddi şekilde yavaşlatabilir ve ikincisi, dağıtımı zorlaştırır.

Öyleyse, bu iyi bir yaklaşım mı ve diğer (Açık Kaynak) projeler de aynı şekilde mi çalışıyor?


4
Gerçekten uzun bir kabuk senaryosu aramaya başladım ve 3500 satır ve 125KB'de, bunu sürdürmek istemem. Kabuk, programları kapatırken gerçekten kolay, ancak hesaplama yapmaya çalıştığında, oldukça çirkinleşiyor. En çok kullandığınız kodun ve taşıma maliyetlerinin yüksek olduğunu biliyorum, ancak gelecekte başka bir şey düşünebilirsiniz.
msw

1
Aynı problemle karşılaştım. Orta derecede büyük bir bash projem var sourceforge.net/projects/duplexpr . Şu anda, her bir komut dosyası kendi içinde bulunuyor, ancak tüm ortak işlevleri ayrı bir dosyaya taşımayı ve bunları birden çok yerde güncellemek zorunda kalmamak için gereken yere dahil etmeyi düşünüyorum. Genel olarak, ardışık her betiği kaynaklamak yerine sadece çağırmanın daha iyi olacağını düşünüyorum. Parçaları bağımsız olarak çalıştırmayı mümkün kılar. O zaman, değişkenleri argüman olarak veya parametre dosyalarında iletmeniz gerekir (veya bağımsız istemiyorsanız bunları dışa aktarabilirsiniz.)
Joe

Yanıtlar:


13

Evet, yaygın bir uygulamadır. Örneğin, Unix'in ilk günlerinde, sistemi önyükleme aşamalarında çok kullanıcılı çalışmaya yönlendiren sorumlu kabuk kodu tek bir dosyaydı /etc/rc,. Günümüzde önyükleme işlemi, merkezi konumlardan ihtiyaç duyulan ortak fonksiyonlar ve değişkenlerle, fonksiyonlara göre ayrılmış birçok kabuk betiği tarafından kontrol edilmektedir. Linux dağıtımları, Mac'ler, BSD'ler, hepsi bu yaklaşımı farklı derecelerde benimsemiştir.


2
Bu durumda, tekrar kullanılabilirlik için daha fazla. Farklı komut dosyaları, ortak bir kabuk işlevleri kütüphanesi kullanır.
Stéphane Chazelas

16

Shell bu noktada iş için doğru araç mı? Kodun aşılmasıyla ilgili sorunları çözen bir geliştirici olarak size bir yeniden yazmanın düşünülmemesi gerektiğini söyleyebilirim, bunun yerine parçaları ölçeklendirmek için daha uygun bir parçaya ayırmayı düşünerek uygulamanızı büyütmek için - belki de piton veya yakut veya perl ?

Shell yardımcı bir dildir - bir betik dilidir - bu yüzden onu bu boyutlarda büyütmek zor olacaktır.


Bu tam olarak göndermek üzereydim.
zwol

özellikle Solaris gibi daha eski işletim sistemlerinde bile şimdi perl ve python vb. Daha eski sistemlerin kabuk komut dosyalarının kullanılmasının bir nedeni, kabuğun her zaman hazır bulunmasının garanti edilmesiydi, ancak HP-UX ve Solaris ve AIX gibi daha büyük Unices'in başka araçları içereceği garanti edilemiyordu.
Tim Kennedy,

7

Bakımınızı kolaylaştırırsa, her ikisine de sahip olabilirsiniz. Kolayca saklayabilmeniz için mantıksal parçalara bölün, ardından dağıtmak için hepsini bir araya getirmek için bir Makefile yazın (örn.) Yazmak için işlevleri hızlı bir şekilde eklemek için bazı hızlı komut dosyaları yazabilirsiniz. sourcehat veya sadece bu gibi önemsiz bir şey yapmak (gibi, bu yeniden tabify gerekecek makesekmeleri gerekir):

all: myscript

myscript: includes/* body/*
    cat $^ > "$@" || (rm -f "$@"; exit 1)

Daha sonra bir "kaynak" versiyonuna (düzenleme için kullanılır) ve "ikili" versiyonuna (önemsiz kurulum için kullanılır) sahipsin.


1
Aha! Basit kedi yaklaşımını kullanan bir başkası :)
Clayton Stanley

4

Anlattığınız gibi bir senaryo bozulabilir - hemen hemen her şey yapılabilir. “İyi yaklaşımın” büyük senaryoyu bölümlere ayırmak, IPC mekanizmaları aracılığıyla iletişim kurmak için bölümlerinin ayrı bir süreç olarak nerede çalıştırılabileceğini bulmak olduğunu söyleyebilirim.

Bunun ötesinde, bir kabuk betiği için, onu tek bir dosya olarak paketlerdim. Söylediğiniz gibi dağıtımı zorlaştırıyor: ya 'kütüphane' komut dosyalarının nerede olduğunu bilmek zorundasınız - kabuk komut dosyaları için iyi bir standart yok - ya da yollarını doğru bir şekilde ayarlamak için kullanıcıya güveniyorsunuz.

Bunları sizin için idare eden, dosyaları açarak, uygun yere koyarak export PROGRAMDIR=$HOME/lib/PROGRAM, ~ / .bashrc dosyasına benzer bir şey eklemesini söyleyen bir yükleme programı dağıtabilirsiniz . Ardından, $PROGRAMDIRayarlanmamışsa veya beklediğiniz dosyaları içermiyorsa ana program başarısız olabilir .

Diğer senaryoları doldurmanın yükü kadar endişelenmem. Tepegöz gerçekten sadece bir dosya açıyor; metnin işlenmesi, özellikle işlev tanımları ise aynıdır.


1

Yaygın uygulama veya değil, bir dizi ihracattan başka bir şey tedarik etmenin iyi bir fikir olduğunu sanmıyorum. Kaynak kodu kullanarak kod çalıştırmanın sadece kafa karıştırıcı olduğunu ve yeniden kullanımı sınırladığını biliyorum, çünkü çevresel ve diğer değişken ayarları kaynak kodunu kaynak koduna oldukça bağımlı hale getiriyor.

Uygulamanızı daha küçük, kendi kendine yeten komut dosyalarına bölmek için daha iyi durumdasınız, ardından bunları bir dizi komut olarak uygulayın. Bu, her bir komut istemi arasında kendi içerdiği her bir betiği etkileşimli bir kabukta çalıştırabilir, dosyaları, günlükleri vb. İnceleyebilir. Tek, büyük uygulama komut dosyanız hata ayıklamayı tamamladıktan sonra yalnızca bir dizi komut çalıştıran daha basit bir kontrol komut dosyasına dönüşür.

Bir grup küçük, kendi kendine yeten komut dosyası, kurulumu zor bir problemle karşılaşır.


1

Senaryoları kaynak göstermenin bir alternatifi, basitçe onları argümanlarla çağırmaktır. İşlevselliğinizin çoğunu kabuk işlevlerine zaten ayırdıysanız, muhtemelen bunu zaten yapabilmeniz için oldukça yakınsınızdır. Aşağıdaki Bash pasajı, bir komut dosyasında belirtilen herhangi bir işlevin alt komut olarak kullanılmasına izin verir:

if [[ ${1:-} ]] && declare -F | cut -d' ' -f3 | fgrep -qx -- "${1:-}"
then "$@"
else main "$@" # Try the main function if args don't match a declaration.
fi

Olmamasının nedeni sourceçevre ve seçenek kirliliğinden kaçınmaktır.


0

İşte benim büyük bir bash betiğinin birden fazla dosyaya nasıl bölündüğü ve daha sonra sonuçtaki bir betiğe nasıl yerleştirilebileceğine dair bir örnek: https://github.com/zinovyev/bash-project

Bunun için bir kullanıyorum Makefile:

TARGET_FILE = "target.sh"
PRJ_SRC = "${PWD}/src/main.sh"
PRJ_LIB = $(shell ls -d ${PWD}/lib/*) # All files from ./lib

export PRJ_LIB

SHELL := /bin/env bash
all: define_main add_dependencies invoke_main

define_main:
    echo -e "#!/usr/bin/env bash\n" > ${TARGET_FILE}
    echo -e "function main() {\n" >> ${TARGET_FILE}
    cat "${PRJ_SRC}" | sed -e 's/^/  /g' >> ${TARGET_FILE}
    echo -e "\n}\n" >> ${TARGET_FILE}

invoke_main:
    echo "main \$$@" >> ${TARGET_FILE}

add_dependencies:
    for filename in $${PRJ_LIB[*]}; do cat $${filename} >> ${TARGET_FILE}; echo >> ${TARGET_FILE}; done
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.