Mengapa menulis seluruh skrip bash dalam fungsi?

59

Di tempat kerja, saya sering menulis skrip bash. Atasan saya menyarankan agar seluruh skrip dipecah menjadi fungsi, mirip dengan contoh berikut:

#!/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

Apakah ada alasan untuk melakukan hal ini selain "keterbacaan", yang saya pikir dapat juga dilakukan dengan beberapa komentar dan spasi baris?

Apakah ini membuat script berjalan lebih efisien (saya benar-benar mengharapkan yang sebaliknya, jika ada), atau apakah itu membuatnya lebih mudah untuk memodifikasi kode di luar potensi keterbacaan yang disebutkan sebelumnya? Atau itu benar-benar hanya preferensi gaya?

Harap perhatikan bahwa meskipun skrip tidak menunjukkannya dengan baik, "menjalankan urutan" fungsi dalam skrip aktual kami cenderung sangat linier - walk_into_bartergantung pada hal-hal yang i_am_footelah dilakukan, dan do_baztindakan pada hal-hal yang diatur oleh walk_into_bar- jadi dapat secara sewenang-wenang menukar run order bukanlah sesuatu yang biasanya kita lakukan. Misalnya, Anda tidak akan tiba-tiba ingin declare_variablesmengejarnya walk_into_bar, itu akan menghancurkan banyak hal.

Contoh bagaimana saya akan menulis skrip di atas adalah:

#!/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
Doktor J
sumber
30
Saya suka bos Anda. Dalam skrip saya, saya juga meletakkan main()di bagian atas dan menambahkan main "$@"di bawah untuk menyebutnya. Itu memungkinkan Anda melihat logika skrip tingkat tinggi hal pertama ketika Anda membukanya.
John Kugelman mendukung Monica
22
Saya tidak setuju dengan gagasan bahwa keterbacaan dapat "sama-sama mapan dengan beberapa komentar lagi dan beberapa spasi baris." Kecuali mungkin untuk fiksi, saya tidak ingin berurusan dengan buku yang tidak memiliki daftar isi dan nama deskriptif untuk setiap bab dan bagian. Dalam bahasa pemrograman, itu adalah jenis keterbacaan yang dapat disediakan fungsi, dan komentar tidak bisa.
Rhymoid
6
Perhatikan bahwa variabel yang dideklarasikan dalam fungsi harus dideklarasikan local- ini menyediakan ruang lingkup variabel yang sangat penting dalam skrip non-sepele.
Boris the Spider
8
Saya tidak setuju dengan atasan Anda. Jika Anda harus memecah skrip Anda menjadi fungsi, Anda mungkin tidak boleh menulis skrip shell di tempat pertama. Tulis sebuah program sebagai gantinya.
el.pescado
6
Fungsinya untuk proses yang diulang, baik di dalam skrip atau di lebih dari satu skrip. Mereka juga memungkinkan metodologi yang seragam untuk ditempatkan. Misalnya menggunakan fungsi untuk menulis ke syslog. Selama semua orang menggunakan fungsi yang sama, entri syslog Anda lebih konsisten. Fungsi penggunaan tunggal seperti contoh Anda tidak perlu menyulitkan skrip. Dalam beberapa kasus, mereka menimbulkan masalah (pelingkupan variabel).
Xalorous

Jawaban:

40

Saya sudah mulai menggunakan gaya pemrograman bash yang sama ini setelah membaca posting blog Kfir Lavi "Defensive Bash Programming" . Dia memberikan beberapa alasan bagus, tetapi secara pribadi saya menemukan ini yang paling penting:

  • prosedur menjadi deskriptif: jauh lebih mudah untuk mengetahui bagian kode apa yang seharusnya dilakukan. Alih-alih dinding kode, Anda melihat "Oh, find_log_errorsfungsi membaca file log untuk kesalahan". Bandingkan dengan menemukan banyak baris awk / grep / sed yang menggunakan tuhan tahu apa jenis regex di tengah naskah panjang - Anda tidak tahu apa yang dilakukannya di sana kecuali ada komentar.

  • Anda dapat men-debug fungsi dengan menyertakan ke set -xdan set +x. Setelah Anda mengetahui bahwa sisa kode berfungsi dengan baik, Anda dapat menggunakan trik ini untuk fokus pada debugging hanya fungsi spesifik itu. Tentu, Anda dapat melampirkan bagian skrip, tetapi bagaimana jika itu bagian yang panjang? Lebih mudah melakukan hal seperti ini:

     set -x
     parse_process_list
     set +x
  • penggunaan pencetakan dengan cat <<- EOF . . . EOF. Saya telah menggunakannya beberapa kali untuk membuat kode saya jauh lebih profesional. Selain itu, parse_args()dengan getoptsfungsinya yang cukup nyaman. Sekali lagi, ini membantu keterbacaan, alih-alih memasukkan semuanya ke dalam skrip sebagai dinding teks raksasa. Juga nyaman untuk menggunakan kembali ini.

Dan jelas, ini jauh lebih mudah dibaca untuk seseorang yang tahu C atau Java, atau Vala, tetapi memiliki pengalaman bash yang terbatas. Sejauh efisiensi berjalan, tidak ada banyak yang dapat Anda lakukan - bash itu sendiri bukan bahasa yang paling efisien dan orang lebih suka perl dan python ketika datang ke kecepatan dan efisiensi. Namun, Anda dapat nicesuatu fungsi:

nice -10 resource_hungry_function

Dibandingkan dengan memanggil baik pada setiap baris kode, ini mengurangi banyak mengetik DAN dapat dengan mudah digunakan ketika Anda ingin hanya bagian dari skrip Anda berjalan dengan prioritas lebih rendah.

Menjalankan fungsi di latar belakang, menurut saya, juga membantu ketika Anda ingin memiliki banyak pernyataan untuk dijalankan di latar belakang.

Beberapa contoh di mana saya menggunakan gaya ini:

Sergiy Kolodyazhnyy
sumber
3
Saya tidak yakin Anda harus menerima saran dari artikel itu dengan sangat serius. Memang, ini memiliki beberapa ide bagus, tetapi jelas bukan seseorang yang terbiasa dengan shell scripting. Tidak ada variabel tunggal dalam salah satu contoh yang dikutip (!) Dan itu menyarankan menggunakan nama variabel KASUS UPPER yang sering merupakan ide yang sangat buruk karena mereka dapat bertentangan dengan vv env yang ada. Poin Anda dalam jawaban ini masuk akal, tetapi artikel yang ditautkan tampaknya telah ditulis oleh seseorang yang hanya terbiasa dengan bahasa lain dan mencoba untuk memaksa gaya mereka ke bash.
terdon
1
@terdon saya kembali ke artikel dan membacanya kembali. Satu-satunya tempat di mana penulis menyebutkan penamaan variabel huruf besar adalah "Immutable Global Variables". Jika Anda menganggap variabel global sebagai variabel yang harus berada dalam lingkungan fungsi, maka masuk akal untuk membuatnya menjadi modal. Di samping catatan, manual bash tidak menyatakan konvensi untuk case variabel. Bahkan jawaban yang diterima di sini mengatakan "biasanya" dan satu-satunya "standar" adalah oleh Google, yang tidak mewakili seluruh industri TI.
Sergiy Kolodyazhnyy
@terdon pada catatan lain, saya setuju 100% bahwa mengutip variabel seharusnya disebutkan dalam artikel, dan telah ditunjukkan dalam komentar di blog juga. Juga, saya tidak akan menilai seseorang menggunakan gaya pengkodean ini, terlepas dari apakah mereka terbiasa dengan bahasa lain atau tidak. Seluruh pertanyaan dan jawaban ini jelas menunjukkan ada kelebihannya, dan tingkat kemampuan seseorang dalam bahasa lain mungkin tidak relevan di sini.
Sergiy Kolodyazhnyy
1
@terdon yah, artikel itu diposting sebagai bagian dari materi "sumber". Saya bisa saja memposting semuanya sebagai pendapat saya sendiri, tetapi saya hanya harus memberi penghargaan bahwa beberapa hal yang saya pelajari dari artikel itu, dan bahwa semua ini berasal dari penelitian dari waktu ke waktu. Halaman tertaut penulis menunjukkan bahwa mereka memiliki pengalaman yang baik dengan Linux dan IT secara umum, jadi saya kira artikel itu tidak benar-benar menunjukkan itu, tapi saya percaya pada pengalaman Anda ketika datang ke Linux dan shell scripting, sehingga Anda mungkin benar .
Sergiy Kolodyazhnyy
1
Itu jawaban yang sangat baik tetapi saya juga ingin menambahkan bahwa ruang lingkup variabel di Bash adalah funky. Untuk alasan itu, saya lebih suka mendeklarasikan variabel saya di dalam fungsi menggunakan localdan memanggil semuanya melalui main()fungsi. Ini membuat banyak hal lebih mudah dikelola dan Anda dapat menghindari situasi yang berpotensi berantakan.
Housni
65

Keterbacaan adalah satu hal. Tetapi ada lebih banyak modularisasi daripada hanya ini. ( Semi-modularisasi mungkin lebih tepat untuk fungsi.)

Dalam fungsi Anda dapat menyimpan beberapa variabel lokal, yang meningkatkan keandalan , mengurangi kemungkinan hal-hal kacau.

Pro fungsi lainnya adalah kegunaan ulang . Setelah suatu fungsi dikodekan, itu dapat diterapkan beberapa kali dalam skrip. Anda juga dapat memindahkannya ke skrip lain.

Kode Anda sekarang mungkin linier, tetapi di masa depan Anda dapat memasukkan ranah multi-threading , atau multi-pemrosesan di dunia Bash. Setelah Anda belajar melakukan hal-hal dalam fungsi, Anda akan diperlengkapi dengan baik untuk melangkah ke paralel.

Satu hal lagi untuk ditambahkan. Sebagaimana Etsitpab Nioliv perhatikan dalam komentar di bawah, mudah untuk mengalihkan dari fungsi sebagai entitas yang koheren. Tetapi ada satu aspek lagi dari pengalihan dengan fungsi. Yaitu, pengalihan dapat diatur di sepanjang definisi fungsi. Misalnya.:

f () { echo something; } > log

Sekarang tidak diperlukan pengalihan secara eksplisit oleh pemanggilan fungsi.

$ f

Ini dapat menghemat banyak pengulangan, yang lagi-lagi meningkatkan keandalan dan membantu menjaga barang-barang tetap teratur.

Lihat juga

Tomasz
sumber
55
Jawaban yang sangat bagus meskipun akan jauh lebih baik jika dipecah menjadi fungsi.
Pierre Arlaud
1
Mungkin menambahkan bahwa fungsi memungkinkan Anda untuk mengimpor skrip itu ke skrip lain (dengan menggunakan sourceatau . scriptname.sh, dan menggunakan fungsi-fungsi itu seolah-olah mereka ada di skrip baru Anda.
SnakeDoc
Itu sudah tercakup dalam jawaban lain.
Tomasz
1
Saya menghargai itu. Tapi saya lebih suka membiarkan orang lain juga penting.
Tomasz
7
Saya menghadapi kasus hari ini di mana saya harus mengarahkan kembali beberapa output skrip ke file (untuk mengirimnya melalui email) alih-alih menggema. Saya hanya perlu melakukan myFunction >> myFile untuk mengarahkan ulang output dari fungsi yang diinginkan. Cukup nyaman. Mungkin relevan.
Etsitpab Nioliv
39

Dalam komentar saya, saya menyebutkan tiga keunggulan fungsi:

  1. Mereka lebih mudah untuk menguji dan memverifikasi kebenaran.

  2. Fungsi dapat dengan mudah digunakan kembali (bersumber) dalam skrip yang akan datang

  3. Bos Anda menyukai mereka.

Dan, jangan pernah meremehkan pentingnya angka 3.

Saya ingin membahas satu masalah lagi:

... jadi bisa secara sewenang-wenang menukar run order bukanlah sesuatu yang biasanya kita lakukan. Misalnya, Anda tidak akan tiba-tiba ingin declare_variablesmengejarnya walk_into_bar, itu akan menghancurkan banyak hal.

Untuk mendapatkan manfaat dari memecah kode menjadi fungsi, seseorang harus mencoba untuk membuat fungsi sebebas mungkin. Jika walk_into_barmemerlukan variabel yang tidak digunakan di tempat lain, maka variabel tersebut harus didefinisikan dan dibuat lokal untuk walk_into_bar. Proses memisahkan kode menjadi fungsi dan meminimalkan saling ketergantungan mereka harus membuat kode lebih jelas dan sederhana.

Idealnya, fungsi harus mudah diuji secara individual. Jika, karena interaksi, mereka tidak mudah diuji, maka itu adalah tanda bahwa mereka mungkin mendapat manfaat dari refactoring.

John1024
sumber
Saya berpendapat bahwa kadang-kadang masuk akal untuk memodelkan dan menegakkan dependensi-dependensi itu, vs refactoring untuk menghindarinya (karena jika ada cukup banyak dari mereka, dan mereka cukup berbulu, itu hanya dapat mengarah pada kasus di mana hal-hal tidak lagi termodulasi menjadi fungsi sama sekali). Kasus penggunaan yang sangat rumit sekali mengilhami kerangka kerja untuk melakukan hal itu .
Charles Duffy
4
Apa yang perlu dibagi menjadi beberapa fungsi seharusnya, tetapi contohnya terlalu jauh. Saya pikir satu-satunya yang benar-benar mengganggu saya adalah fungsi deklarasi variabel. Variabel global, terutama yang statis, harus didefinisikan secara global di bagian komentar yang didedikasikan untuk tujuan itu. Variabel dinamis harus lokal ke fungsi yang menggunakan dan memodifikasinya.
Xalorous
@Xalorous Saya telah melihat praktik di mana variabel global diinisialisasi dalam prosedur, sebagai langkah menengah dan cepat sebelum berkembangnya prosedur yang bertuliskan nilai mereka dari file eksternal ... Saya setuju itu harus bersih untuk definisi terpisah dan inisialisasi tetapi jarang Anda harus membungkuk untuk menjalani ke keunggulan nomor 3;-)
Hastur
14

Anda memecah kode menjadi fungsi untuk alasan yang sama Anda akan melakukannya untuk C / C ++, python, perl, ruby ​​atau kode bahasa pemrograman apa pun. Alasan yang lebih dalam adalah abstraksi - Anda merangkum tugas-tugas tingkat bawah menjadi primitif tingkat tinggi (fungsi) sehingga Anda tidak perlu repot tentang bagaimana hal-hal dilakukan. Pada saat yang sama, kode menjadi lebih mudah dibaca (dan dipelihara), dan logika program menjadi lebih jelas.

Namun, melihat kode Anda, saya merasa sangat aneh memiliki fungsi untuk mendeklarasikan variabel; ini benar-benar membuat saya menaikkan alis mata.

countermode
sumber
IMHO jawaban yang diremehkan. Apakah Anda menyarankan untuk mendeklarasikan variabel dalam mainfungsi / metode, lalu?
David Tabernero M.
13

Sementara saya sepenuhnya setuju dengan usabilitas , keterbacaan , dan mencium bos dengan lembut tetapi ada satu keuntungan lain dari fungsi di : ruang lingkup variabel . Seperti yang ditunjukkan LDP :

#!/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.

Saya tidak sering melihat ini di skrip shell dunia nyata, tetapi sepertinya ide yang bagus untuk skrip yang lebih kompleks. Mengurangi kohesi membantu menghindari bug di mana Anda menghancurkan variabel yang diharapkan di bagian lain kode.

Dapat digunakan kembali sering kali berarti membuat perpustakaan umum fungsi dan sourcememasukkan perpustakaan itu ke semua skrip Anda. Ini tidak akan membantu mereka berlari lebih cepat, tetapi itu akan membantu Anda menulisnya lebih cepat.

anak ayam
sumber
1
Hanya sedikit orang yang secara eksplisit menggunakan local, tetapi saya pikir sebagian besar orang menulis skrip dipecah menjadi fungsi masih mengikuti prinsip desain. Usign localhanya mempersulit untuk memperkenalkan bug.
Voo
localmembuat variabel tersedia untuk fungsi dan anak-anaknya, jadi sangat menyenangkan memiliki variabel yang dapat diturunkan dari fungsi A, tetapi tidak tersedia untuk fungsi B, yang mungkin ingin memiliki variabel dengan nama yang sama tetapi tujuan yang berbeda. Jadi itu bagus untuk mendefinisikan ruang lingkup, dan seperti yang dikatakan Voo - lebih sedikit bug
Sergiy Kolodyazhnyy
10

Alasan yang sangat berbeda dari yang sudah diberikan dalam jawaban lain: satu alasan teknik ini kadang-kadang digunakan, di mana satu-satunya pernyataan non-fungsi-definisi di tingkat atas adalah panggilan untuk main, adalah untuk memastikan skrip tidak secara tidak sengaja melakukan sesuatu yang jahat jika skrip terpotong. Script dapat dipotong jika disalurkan dari proses A ke proses B (shell), dan proses A berakhir karena alasan apa pun sebelum selesai menulis keseluruhan skrip. Ini sangat mungkin terjadi jika proses A mengambil skrip dari sumber daya jarak jauh. Sementara untuk alasan keamanan itu bukan ide yang baik, itu adalah sesuatu yang dilakukan, dan beberapa skrip telah dimodifikasi untuk mengantisipasi masalah.

hvd
sumber
5
Menarik! Tetapi saya merasa bermasalah bahwa seseorang harus mengurus hal-hal itu di setiap program. Di sisi lain, main()pola ini persis biasa di Python di mana orang menggunakan if __name__ == '__main__': main()di akhir file.
Martin Ueding
1
Ungkapan python memiliki kelebihan yaitu membiarkan skrip lain menjalankan skrip importsaat ini tanpa berjalan main. Saya kira penjaga yang sama bisa dimasukkan ke dalam skrip bash.
Jake Cobb
@ Jake Cobb Ya. Saya sekarang melakukannya di semua skrip bash baru. Saya memiliki skrip yang berisi infrastruktur inti fungsi yang digunakan oleh semua skrip baru. Skrip itu bisa bersumber atau dijalankan. Jika bersumber, fungsi utamanya tidak dijalankan. Deteksi sumber vs eksekusi adalah melalui fakta bahwa BASH_SOURCE berisi nama skrip pelaksana. Jika sama dengan skrip inti, skrip sedang dieksekusi. Kalau tidak, itu bersumber.
DocSalvager
7

Suatu proses membutuhkan urutan. Sebagian besar tugas berurutan. Tidak masuk akal untuk mengacaukan pesanan.

Tetapi hal super besar tentang pemrograman - yang termasuk scripting - adalah pengujian. Pengujian, pengujian, pengujian. Skrip tes apa yang saat ini Anda miliki untuk memvalidasi kebenaran skrip Anda?

Bos Anda mencoba memandu Anda dari menjadi script kiddy menjadi programmer. Ini adalah arah yang baik untuk masuk. Orang-orang yang datang setelah Anda akan menyukai Anda.

TAPI. Ingatlah selalu akar proses Anda. Jika masuk akal untuk memiliki fungsi yang dipesan dalam urutan di mana mereka biasanya dieksekusi, maka lakukan itu, setidaknya sebagai pass pertama.

Kemudian, Anda akan melihat bahwa beberapa fungsi Anda menangani input, yang lain output, yang lain memproses, yang lain memodelkan data, dan yang lain memanipulasi data, sehingga mungkin pintar untuk mengelompokkan metode yang serupa, mungkin bahkan memindahkannya ke file yang terpisah. .

Kemudian, Anda mungkin menyadari bahwa sekarang Anda telah menulis perpustakaan fungsi pembantu kecil yang Anda gunakan di banyak skrip Anda.

Dewi Morgan
sumber
7

Komentar dan spasi tidak dapat mendekati keterbacaan yang berfungsi, seperti yang akan saya tunjukkan. Tanpa fungsi, Anda tidak dapat melihat hutan untuk pepohonan - masalah besar bersembunyi di antara banyak garis detail. Dengan kata lain, orang tidak bisa secara bersamaan fokus pada detail halus dan gambaran besar. Itu mungkin tidak jelas dalam naskah pendek; selama masih pendek mungkin cukup mudah dibaca. Namun, perangkat lunak menjadi lebih besar, tidak lebih kecil, dan tentu saja itu bagian dari keseluruhan sistem perangkat lunak perusahaan Anda, yang tentunya jauh lebih besar, mungkin jutaan baris.

Pertimbangkan jika saya memberi Anda petunjuk seperti ini:

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)

Pada saat Anda setengah jalan, atau bahkan 5% melalui, Anda akan lupa apa beberapa langkah pertama itu. Anda tidak mungkin menemukan sebagian besar masalah, karena Anda tidak dapat melihat hutan untuk pepohonan. Bandingkan dengan fungsi:

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

Itu tentu jauh lebih dimengerti, tidak peduli berapa banyak komentar yang Anda masukkan ke dalam versi berurutan baris demi baris. Ini juga membuatnya jauh lebih mungkin Anda akan melihat bahwa Anda lupa membuat kopi, dan mungkin lupa sit_down () di akhir. Ketika pikiran Anda memikirkan perincian grep dan awk regexes, Anda tidak dapat memikirkan gambaran besar - "bagaimana jika tidak ada kopi yang dibuat"?

Fungsi utamanya memungkinkan Anda melihat gambaran besar, dan memerhatikan bahwa Anda lupa membuat kopi (atau seseorang mungkin lebih suka teh). Di lain waktu, dalam kerangka berpikir yang berbeda, Anda khawatir tentang implementasi terperinci.

Ada juga manfaat lain yang dibahas dalam jawaban lain, tentu saja. Manfaat lain yang tidak secara jelas dinyatakan dalam jawaban lain adalah bahwa fungsi memberikan jaminan yang penting dalam mencegah dan memperbaiki bug. Jika Anda menemukan bahwa beberapa variabel $ foo dalam fungsi walk_to () yang salah salah, Anda tahu bahwa Anda hanya perlu melihat 6 baris lainnya dari fungsi itu untuk menemukan segala sesuatu yang dapat dipengaruhi oleh masalah itu, dan segala sesuatu yang bisa telah menyebabkannya salah. Tanpa fungsi (tepat), apa pun dan segala sesuatu di seluruh sistem mungkin menjadi penyebab $ foo salah, dan apa pun dan segala sesuatu mungkin dipengaruhi oleh $ foo. Karenanya Anda tidak dapat memperbaiki $ foo dengan aman tanpa memeriksa ulang setiap baris program. Jika $ foo bersifat lokal untuk suatu fungsi,

Ray Morris
sumber
1
Ini bukan bashsintaksis. Sayang sekali; Saya tidak berpikir ada cara untuk memasukkan input ke fungsi seperti itu. (yaitu pour();< coffee). Itu lebih mirip c++atau php(saya pikir).
Suara
2
@ tjt263 tanpa tanda kurung, ini sintaks bash: tuangkan kopi. Dengan parens, hampir semua bahasa lainnya. :)
Ray Morris
6

Beberapa kebenaran yang relevan tentang pemrograman:

  • Program Anda akan berubah, bahkan jika bos Anda bersikeras ini bukan masalahnya.
  • Hanya kode dan input yang memengaruhi perilaku program.
  • Penamaan itu sulit.

Komentar dimulai sebagai penghenti karena tidak dapat mengekspresikan ide Anda dengan jelas dalam kode *, dan menjadi lebih buruk (atau hanya salah) dengan perubahan. Karena itu, jika memungkinkan, ungkapkan konsep, struktur, alasan, semantik, aliran, penanganan kesalahan, dan hal lain yang berkaitan dengan pemahaman kode sebagai kode.

Yang mengatakan, fungsi Bash memiliki beberapa masalah yang tidak ditemukan di sebagian besar bahasa:

  • Namespacing mengerikan di Bash. Misalnya, lupa menggunakan localhasil kata kunci dalam mencemari namespace global.
  • Menggunakan local foo="$(bar)"hasil dalam kehilangan kode keluar daribar .
  • Tidak ada parameter bernama, jadi Anda harus ingat apa "$@"artinya dalam konteks yang berbeda.

* Maaf jika ini menyinggung, tetapi setelah menggunakan komentar selama beberapa tahun dan berkembang tanpa mereka ** selama bertahun-tahun cukup jelas mana yang lebih unggul.

** Menggunakan komentar untuk lisensi, dokumentasi API dan sejenisnya masih diperlukan.

l0b0
sumber
Aku mengatur hampir semua variabel lokal dengan menyatakan mereka untuk null di awal fungsi ... local foo=""Kemudian pengaturan mereka menggunakan perintah eksekusi untuk bertindak atas hasilnya ... foo="$(bar)" || { echo "bar() failed"; return 1; }. Ini membuat kita keluar dari fungsi dengan cepat ketika nilai yang diperlukan tidak dapat ditetapkan. Kurung kurawal diperlukan untuk memastikan bahwa return 1hanya dijalankan pada kegagalan.
DocSalvager
6

Waktu adalah uang

Ada jawaban bagus lainnya yang menyebarkan alasan teknis untuk menulis skrip modular , berpotensi panjang, dikembangkan di lingkungan kerja, dikembangkan untuk digunakan oleh sekelompok orang dan tidak hanya untuk penggunaan Anda sendiri.

Saya ingin fokus pada satu harapan: dalam lingkungan kerja "waktu adalah uang" . Jadi tidak adanya bug dan kinerja kode Anda dievaluasi bersama dengan readibility , testability, rawatan, refactorability, reusability ...

Menulis dalam "modul" kode akan mengurangi waktu membaca yang dibutuhkan tidak hanya oleh koder itu sendiri, tetapi bahkan waktu yang digunakan oleh penguji atau oleh bos. Selain itu perhatikan bahwa waktu seorang bos biasanya dibayar lebih dari waktu seorang pembuat kode dan bahwa bos Anda akan mengevaluasi kualitas pekerjaan Anda.

Selanjutnya menulis dalam "modul" kode independen (bahkan skrip bash) akan memungkinkan Anda untuk bekerja secara "paralel" dengan komponen lain dari tim Anda yang memperpendek waktu produksi keseluruhan dan menggunakan keahlian terbaik single, untuk meninjau atau menulis ulang bagian dengan tidak ada efek samping pada yang lain, untuk mendaur ulang kode yang baru saja Anda tulis "apa adanya"untuk program / skrip lain, untuk membuat pustaka (atau pustaka snippet), untuk mengurangi ukuran keseluruhan dan kemungkinan kesalahan yang terkait, untuk men-debug dan menguji secara menyeluruh setiap bagian tunggal ... dan tentu saja akan diatur dalam bagian logis program Anda / skrip dan tingkatkan keterbacaannya. Semua hal yang akan menghemat waktu dan uang. Kekurangannya adalah Anda harus tetap berpegang pada standar dan mengomentari fungsi Anda (yang harus Anda lakukan di lingkungan kerja).

Mematuhi standar akan memperlambat pekerjaan Anda di awal tetapi akan mempercepat pekerjaan semua yang lain (dan Anda juga) sesudahnya. Memang ketika kolaborasi tumbuh dalam jumlah orang yang terlibat ini menjadi kebutuhan yang tidak dapat dihindari. Jadi, misalnya, bahkan jika saya percaya bahwa variabel global harus didefinisikan secara global dan tidak dalam suatu fungsi, saya dapat memahami suatu standar yang mem-inisialisasi mereka dalam suatu fungsi yang dinamakan declare_variables()selalu di baris pertama main()...

Last but not least, jangan meremehkan kemungkinan dalam editor kode sumber modern untuk menunjukkan atau menyembunyikan rutinitas terpisah secara selektif ( Lipat kode ). Ini akan menjaga kode kompak dan memfokuskan pengguna menghemat waktu lagi.

masukkan deskripsi gambar di sini

Di sini di atas Anda dapat melihat bagaimana itu hanya membukawalk_into_bar() fungsi. Bahkan yang lainnya masing-masing terdiri dari 1000 baris, Anda masih dapat mengontrol semua kode dalam satu halaman. Catatan itu dilipat bahkan bagian mana Anda pergi untuk mendeklarasikan / menginisialisasi variabel.

Cepat
sumber
2

Selain alasan yang diberikan dalam jawaban lain:

  1. Psikologi: Seorang programmer yang produktivitasnya sedang diukur dalam baris kode akan memiliki insentif untuk menulis kode verbose yang tidak perlu. Semakin banyak manajemen berfokus pada garis kode, semakin banyak insentif yang harus diprogram programmer untuk memperluas kodenya dengan kompleksitas yang tidak dibutuhkan. Ini tidak diinginkan karena peningkatan kompleksitas dapat menyebabkan peningkatan biaya pemeliharaan dan peningkatan upaya yang diperlukan untuk memperbaiki bug.
agc
sumber
1
Ini bukan jawaban yang buruk, seperti kata downvotes. Catatan: AGC mengatakan, juga ini adalah kemungkinan, dan ya, itu. Dia tidak mengatakan itu akan menjadi satu-satunya kemungkinan, dan tidak menuduh siapa pun, hanya menyatakan fakta. Meskipun saya pikir hari ini hampir tidak pernah terdengar "kode baris" langsung - pekerjaan kontrak gaya "$$", secara tidak langsung berarti sangat umum, bahwa ya, massa kode yang dihasilkan diperhitungkan oleh para pemimpin / bos.
user259412
2

Alasan lain yang sering diabaikan adalah sintaks bash:

set -eu

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

Script ini jelas mengandung kesalahan sintaks dan bash seharusnya tidak menjalankannya sama sekali, kan? Salah.

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

Jika kami membungkus kode dalam suatu fungsi, ini tidak akan terjadi:

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
Hubert Grzeskowiak
sumber