Apakah biasa membagi skrip yang lebih besar menjadi beberapa skrip dan sumbernya dalam skrip utama?


23

Saat ini saya sedang mengembangkan skrip Bash yang lebih besar (ini adalah proyek Open Source milik saya) dan mulai berantakan. Saya telah membagi logika menjadi beberapa fungsi, menggunakan variabel lokal di mana saya bisa dan hanya mendeklarasikan beberapa variabel global. Namun, ini menjadi sangat sulit untuk dipertahankan.

Saya berpikir tentang memecah skrip menjadi beberapa skrip dan sumber mereka dalam skrip utama saya (mirip dengan impor dalam bahasa lain).

Tapi saya ingin tahu apakah ini merupakan pendekatan yang layak. Pertama, sumber beberapa skrip bisa sangat memperlambat waktu eksekusi skrip, dan kedua, membuat distribusi lebih sulit.

Jadi, apakah ini pendekatan yang baik, dan apakah proyek (Sumber Terbuka) lainnya melakukannya dengan cara yang sama?


4
Saya pergi mencari skrip shell yang sangat panjang dan pada 3.500 baris dan 125KB, saya tidak ingin mencoba untuk mempertahankannya. Shell sangat ramah ketika menghubungkan program, tetapi ketika mencoba melakukan perhitungan, itu menjadi sangat jelek. Saya tahu kode Anda sebagian besar berfungsi dan biaya portasinya tinggi, tetapi Anda mungkin ingin mempertimbangkan hal lain di masa depan.
msw

1
Saya mengalami masalah yang sama. Saya memiliki proyek bash source sourceforge.net/projects/duplexpr . Saat ini, setiap skrip mandiri, tetapi saya berpikir untuk memindahkan semua fungsi umum ke file terpisah dan memasukkannya di mana diperlukan untuk menghilangkan keharusan memperbaruinya di banyak tempat. Secara umum, saya pikir akan lebih baik untuk hanya memanggil setiap script berturut-turut daripada sumbernya. Itu membuat menjalankan bagian secara mandiri menjadi mungkin. Kemudian, Anda harus meneruskan variabel sebagai argumen atau dalam file parameter (atau Anda bisa mengekspornya jika Anda tidak ingin mandiri.)
Joe

Jawaban:


13

Ya, itu adalah praktik umum. Sebagai contoh, pada hari-hari awal Unix kode shell yang bertanggung jawab untuk memandu sistem melalui fase boot ke operasi multiuser adalah file tunggal /etc/rc,. Saat ini proses boot dikontrol oleh banyak skrip shell, dipecah oleh fungsi, dengan fungsi umum dan variabel bersumber seperti yang diperlukan dari lokasi pusat. Distribusi Linux, Mac, BSD, semuanya telah mengadopsi pendekatan ini dengan tingkat yang bervariasi.


2
meskipun dalam kasus itu, itu lebih untuk penggunaan kembali. Skrip yang berbeda menggunakan pustaka umum fungsi shell.
Stéphane Chazelas

16

Apakah shell alat yang tepat untuk pekerjaan pada saat itu? Sebagai seorang pengembang yang mengalami masalah kode tumbuh saya dapat memberitahu Anda bahwa penulisan ulang tidak boleh dipertimbangkan tetapi mempertimbangkan memisahkan potongan menjadi sesuatu yang lebih cocok untuk skala yang Anda cari untuk mengembangkan aplikasi Anda - mungkin python atau ruby ​​atau bahkan perl ?

Shell adalah bahasa utilitas - ini adalah bahasa scripting - dan karenanya akan sulit untuk mengembangkannya ke ukuran itu.


Inilah yang akan saya posting.
zwol

terutama mengingat bahwa bahkan OS yang lebih tua seperti Solaris dikirim dengan perl, dan python, dll, sekarang. salah satu alasan sistem yang lebih lama menggunakan skrip shell adalah bahwa shell dijamin selalu tersedia, tetapi Unices yang lebih besar, seperti HP-UX dan Solaris, dan AIX, tidak dapat dijamin untuk menyertakan alat lain.
Tim Kennedy

7

Jika itu membuat perawatan Anda lebih mudah, Anda dapat memiliki keduanya. Membaginya menjadi bagian-bagian yang logis sehingga Anda dapat mempertahankannya dengan mudah, lalu menulis (mis., Makefile untuk menyatukannya kembali untuk distribusi. Anda dapat menulis beberapa skrip cepat untuk menyalin fungsi dari file include ke file output sebagai pengganti yang sourcegaris atau hanya melakukan sesuatu yang sepele seperti ini (Anda harus kembali tabify-ini, sebagai makemembutuhkan tab):

all: myscript

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

Anda kemudian memiliki versi "sumber" (digunakan untuk mengedit) dan versi "biner" (digunakan untuk instalasi sepele).


1
Aha! Orang lain yang menggunakan pendekatan kucing sederhana :)
Clayton Stanley

4

Sebuah skrip dapat dipecah seperti yang Anda gambarkan - apa saja dapat dilakukan. Saya akan mengatakan bahwa 'pendekatan yang baik' adalah untuk mengkotak-kotakkan skrip besar Anda, mencari tahu di mana bagian-bagian itu dapat dijalankan sebagai proses terpisah, berkomunikasi melalui mekanisme IPC.

Selain itu, untuk skrip shell, saya akan mengemasnya sebagai satu file. Seperti yang Anda katakan, ini membuat distribusi lebih sulit: Anda juga harus tahu di mana skrip 'pustaka' berada - tidak ada standar yang bagus untuk skrip shell - atau mengandalkan pengguna untuk menetapkan jalurnya dengan benar.

Anda bisa mendistribusikan program instalasi yang menangani semua ini untuk Anda, mengekstrak file-file itu, meletakkannya di tempat yang tepat, memberi tahu pengguna untuk menambahkan sesuatu seperti export PROGRAMDIR=$HOME/lib/PROGRAMke file ~ / .bashrc. Maka program utama bisa gagal jika $PROGRAMDIRtidak disetel atau tidak berisi file yang Anda harapkan.

Saya tidak akan terlalu khawatir tentang overhead memuat skrip lain. Overhead sebenarnya hanya membuka file; pemrosesan teks adalah sama, terutama jika mereka adalah definisi fungsi.


1

Praktik umum atau tidak, saya tidak berpikir mendapatkan apa pun selain seperangkat ekspor adalah ide yang bagus. Saya menemukan bahwa mengeksekusi kode dengan sumber itu hanya membingungkan, dan membatasi penggunaan kembali, karena pengaturan variabel lingkungan dan lainnya membuat kode bersumber sangat tergantung pada kode sumber.

Anda lebih baik memecah aplikasi menjadi skrip mandiri yang lebih kecil, kemudian menjalankannya sebagai serangkaian perintah. Ini akan memudahkan debugging, karena Anda dapat menjalankan setiap skrip mandiri dalam shell interaktif, memeriksa file, log, dll di antara setiap permintaan perintah. Skrip aplikasi tunggal dan besar Anda berubah menjadi skrip pengendali yang lebih sederhana yang hanya menjalankan serangkaian perintah setelah Anda selesai debugging.

Sekelompok skrip yang lebih kecil dan mandiri berjalan ke masalah yang lebih sulit untuk diinstal.


1

Alternatif untuk sumber skrip hanya memanggil mereka dengan argumen. Jika Anda telah memecah sebagian besar fungsi Anda menjadi fungsi-fungsi shell, Anda mungkin sudah cukup dekat untuk dapat melakukan ini. Cuplikan Bash berikut memungkinkan setiap fungsi yang dideklarasikan dalam skrip untuk digunakan sebagai sub-perintah:

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

Alasannya tidak sourceuntuk menghindari polusi lingkungan dan opsi.


0

Berikut adalah contoh saya tentang bagaimana skrip bash besar dapat dipecah menjadi beberapa file dan kemudian dibangun menjadi satu skrip yang dihasilkan: https://github.com/zinovyev/bash-project

Saya menggunakan a Makefileuntuk tujuan ini:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.