Kata Pengantar
Shell yang digunakan
Bash
satu Bash
satunya bahasa skrip shell yang dapat digunakan untuk file yang dapat dieksekusi.
Skrip harus dimulai dengan #!/bin/bash
dengan set minimal flag. Gunakan set
untuk mengatur opsi shell sehingga memanggil skrip Anda sebagai bash <script_name>
tidak melanggar fungsinya.
Membatasi semua skrip shell menjadi bash memberi kami bahasa shell yang konsisten yang diinstal pada semua mesin kami.
Satu-satunya pengecualian adalah jika Anda dibatasi oleh kondisi pemrograman Anda. Salah satu contohnya adalah paket Solaris SVR4, yang membutuhkan penggunaan shell Bourne biasa untuk skrip apa pun.
Kapan harus menggunakan Shell
Shell harus digunakan hanya untuk utilitas kecil atau pembungkus skrip sederhana.
Meskipun shell scripting bukan bahasa pengembangan, ini digunakan untuk menulis berbagai utilitas di seluruh Google. Panduan gaya ini lebih merupakan pengakuan atas penggunaannya, daripada proposal untuk menggunakannya dalam penggunaan luas.
Beberapa rekomendasi:
- Jika Anda paling sering memanggil utilitas lain dan melakukan sedikit manipulasi data, shell adalah pilihan yang dapat diterima untuk tugas tersebut.
- Jika masalah kinerja, gunakan sesuatu yang lain tetapi tidak shell.
- Jika Anda perlu menggunakan array lebih dari menugaskan
${PIPESTATUS}
, Anda harus menggunakan Python. - Jika Anda menulis skrip yang lebih panjang dari 100 baris, Anda mungkin harus menulisnya dengan Python. Ingatlah bahwa skrip berkembang. Tulis ulang skrip Anda dalam bahasa lain sebelumnya untuk menghindari penulisan ulang yang memakan waktu nanti.
File shell dan panggilan juru bahasa
Ekstensi file
File yang dapat dieksekusi tidak boleh memiliki ekstensi (sangat disukai) atau ekstensi .sh
. Perpustakaan harus memiliki ekstensi .sh
dan tidak boleh dieksekusi.
Tidak perlu tahu bahasa apa yang ditulis oleh program selama eksekusi, dan shell tidak memerlukan ekstensi, jadi kami lebih memilih untuk tidak menggunakannya untuk file yang dapat dieksekusi.
Namun, penting bagi perpustakaan untuk mengetahui bahasa apa itu ditulis, dan kadang-kadang perlu untuk memiliki perpustakaan serupa dalam bahasa yang berbeda. Ini memungkinkan Anda memiliki file perpustakaan yang dinamai secara identik dengan tujuan yang identik, tetapi ditulis dalam bahasa yang berbeda harus identik dalam namanya, kecuali untuk sufiks khusus bahasa.
SUID / SGID
SUID dan SGID dilarang pada skrip shell.
Ada terlalu banyak masalah keamanan, sehingga hampir tidak mungkin untuk menyediakan perlindungan SUID / SGID yang cukup. Meskipun bash mempersulit peluncuran SUID, masih dimungkinkan pada beberapa platform, jadi kami secara eksplisit melarang penggunaannya.
Gunakan sudo
untuk meningkatkan akses jika Anda membutuhkannya.
Lingkungan
STDOUT vs STDERR
Semua pesan kesalahan harus dikirim ke STDERR
.
Ini membantu memisahkan keadaan normal dari masalah aktual.
Fungsi untuk menampilkan pesan kesalahan direkomendasikan untuk digunakan bersama dengan informasi status lainnya.
err() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2 } if ! do_something; then err "Unable to do_something" exit "${E_DID_NOTHING}" fi
Komentar
Header file
Mulai setiap file dengan deskripsi kontennya.
Setiap file harus memiliki judul dari komentar, termasuk deskripsi singkat tentang isinya. Pemberitahuan hak cipta dan informasi penulis adalah opsional.
Contoh:
Komentar Fitur
Setiap fungsi yang tidak jelas dan singkat harus dikomentari. Setiap fungsi di perpustakaan harus dikomentari terlepas dari panjang atau kompleksitasnya.
Anda perlu memastikan bahwa orang lain memahami cara menggunakan program Anda atau cara menggunakan fungsi di perpustakaan Anda hanya dengan membaca komentar (dan kebutuhan untuk perbaikan diri) tanpa membaca kode.
Semua komentar fitur harus mencakup:
- Deskripsi Fungsi
- Variabel global yang digunakan dan dimodifikasi
- Argumen diterima
- Mengembalikan nilai yang berbeda dari kode keluar standar di perintah terakhir.
Contoh:
Komentar Implementasi
Komentari bagian kode Anda yang kompleks, tidak jelas, menarik, atau penting.
Ini diasumsikan sebagai praktik umum dari kode komentar di Google. Jangan mengomentari semuanya. Jika ada algoritma yang rumit atau Anda melakukan sesuatu yang tidak biasa, tambahkan komentar singkat.
Komentar TODO
Gunakan komentar TODO untuk kode yang bersifat sementara, jangka pendek, atau cukup bagus, tetapi tidak sempurna.
Ini konsisten dengan konvensi dalam manual C ++ .
Komentar TODO harus menyertakan kata TODO dalam huruf kapital, diikuti dengan nama Anda dalam tanda kurung. Tanda titik dua adalah opsional. Lebih disukai untuk menunjukkan nomor bug / tiket di sebelah elemen TODO.
Contoh:
Meskipun Anda harus mengikuti gaya yang sudah digunakan dalam file yang Anda edit, berikut ini diperlukan untuk kode baru apa pun.
Lekukan
Indentasi 2 spasi. Tidak ada tab.
Gunakan garis kosong di antara blok untuk meningkatkan keterbacaan. Lekukan adalah dua ruang. Apa pun yang Anda lakukan, jangan gunakan tab. Untuk file yang ada, tetap setia pada lekukan saat ini.
Panjang String dan Nilai Panjang
Panjang garis maksimum adalah 80 karakter.
Jika Anda perlu menulis baris yang lebih panjang dari 80 karakter, ini harus dilakukan menggunakan here document
atau, jika mungkin, newline
. Nilai literal yang bisa lebih dari 80 karakter dan tidak dapat dipisahkan diperbolehkan secara wajar, tetapi sangat disarankan agar Anda menemukan cara untuk membuatnya lebih pendek.
Jaringan pipa
Pipa harus dibagi masing-masing pada satu baris jika tidak cocok pada satu saluran.
Jika pipa cocok pada satu saluran, itu harus di satu saluran.
Jika tidak, itu harus dibagi sehingga setiap bagian berada pada baris baru dan di-indentasi oleh 2 spasi untuk bagian selanjutnya. Ini merujuk ke rantai perintah yang dikombinasikan menggunakan '|' serta koneksi logis menggunakan '||' dan '&&'.
Siklus
Tempat ; do
; do
dan ; then
; then
pada baris yang sama dengan while
, for
atau if
.
Siklus dalam shell sedikit berbeda, tetapi kami mengikuti prinsip yang sama seperti dengan kurung kurawal saat mendeklarasikan fungsi. Yaitu ; then
; then
dan ; do
; do
harus pada baris yang sama seperti if
/ for
/ while
. else
harus di jalur yang terpisah, dan pernyataan penutup harus di jalur mereka sendiri, selaras secara vertikal dengan pernyataan pembukaan.
Contoh:
for dir in ${dirs_to_cleanup}; do if [[ -d "${dir}/${ORACLE_SID}" ]]; then log_date "Cleaning up old files in ${dir}/${ORACLE_SID}" rm "${dir}/${ORACLE_SID}/"* if [[ "$?" -ne 0 ]]; then error_message fi else mkdir -p "${dir}/${ORACLE_SID}" if [[ "$?" -ne 0 ]]; then error_message fi fi done
Pernyataan kasus
- Pisahkan opsi dalam 2 spasi.
- Opsi baris tunggal memerlukan spasi setelah braket penutup template dan sebelum
;;
. - Opsi panjang atau multi-perintah harus dibagi menjadi beberapa baris dengan templat, tindakan, dan
;;
pada baris terpisah.
Ekspresi yang sesuai surut satu tingkat dari case
dan esac
. Tindakan multiline juga memiliki indentasi pada tingkat yang terpisah. Tidak perlu menempatkan ekspresi dalam tanda kutip. Pola ekspresi tidak boleh didahului oleh tanda kurung terbuka. Hindari menggunakan &;
dan ;;&
notasi.
case "${expression}" in a) variable="..." some_command "${variable}" "${other_expr}" ... ;; absolute) actions="relative" another_command "${actions}" "${other_expr}" ... ;; *) error "Unexpected expression '${expression}'" ;; esac
Perintah sederhana dapat ditempatkan pada satu baris dengan pola dan ;;
sementara ekspresi tetap dapat dibaca. Ini sering cocok untuk menangani opsi huruf tunggal. Ketika tindakan tidak sesuai pada satu baris, biarkan templat di baris Anda, tindakan selanjutnya, lalu ;;
juga sejalan. Ketika ini adalah baris yang sama dengan tindakan, gunakan spasi setelah kurung tutup template dan yang lain sebelum ;;
.
verbose='false' aflag='' bflag='' files='' while getopts 'abf:v' flag; do case "${flag}" in a) aflag='true' ;; b) bflag='true' ;; f) files="${OPTARG}" ;; v) verbose='true' ;; *) error "Unexpected option ${flag}" ;; esac done
Ekspansi variabel
Dalam urutan prioritas: amati apa yang sudah digunakan; lampirkan variabel dalam tanda kutip; lebih suka "${var}"
lebih dari "$var"
, tetapi dengan memperhatikan konteks penggunaan.
Ini lebih merupakan rekomendasi, karena topik ini cukup kontroversial untuk regulasi wajib. Mereka terdaftar dalam urutan prioritas.
- Gunakan gaya yang sama yang Anda temukan dalam kode yang ada.
- Masukkan variabel dalam tanda kutip, lihat bagian Kutipan di bawah ini.
Jangan letakkan karakter tunggal khusus untuk parameter shell / posisi di tanda kutip dan kawat gigi kecuali benar-benar diperlukan dan untuk menghindari kebingungan yang mendalam.
Pilih kurung kurawal untuk semua variabel lainnya.
Kutipan
- Selalu gunakan tanda kutip untuk nilai-nilai yang mengandung variabel, penggantian perintah, spasi atau karakter meta shell, sampai Anda perlu dengan aman mengekspos nilai-nilai tidak dalam tanda kutip.
- Lebih suka tanda kutip untuk nilai-nilai yang merupakan "kata-kata" (yang bertentangan dengan parameter perintah atau nama jalur)
- Jangan pernah mengutip bilangan bulat.
- Ketahui bagaimana tanda kutip bekerja untuk pola kecocokan di
[[
. - Gunakan
"$@"
jika Anda tidak memiliki alasan khusus untuk menggunakan $*
.
Fitur dan Kesalahan
Substitusi perintah
Gunakan $(command)
daripada backtick.
Backticks bersarang membutuhkan pelolosan internal dengan \
. Format $ (command)
tidak berubah tergantung pada sarangnya dan lebih mudah dibaca.
Contoh:
Cek, [
dan [[
[[ ... ]]
lebih disukai daripada [
, test
atau /usr/bin/[
.
[[ ... ]]
mengurangi kemungkinan kesalahan, karena tidak ada resolusi jalur atau pemisahan kata antara [[
dan ]]
, dan [[ ... ]]
memungkinkan Anda untuk menggunakan ekspresi reguler di mana [ ... ]
tidak.
Periksa Nilai
Gunakan tanda kutip daripada karakter tambahan jika memungkinkan.
Bash cukup pintar untuk bekerja dengan string kosong dalam ujian. Oleh karena itu, kode yang dihasilkan lebih mudah dibaca, gunakan cek untuk nilai kosong / tidak kosong atau nilai kosong, tanpa menggunakan karakter tambahan.
Untuk menghindari kebingungan tentang apa yang Anda periksa, gunakan secara eksplisit -z
atau -n
.
Ekspresi Substitusi untuk Nama File
Gunakan jalur eksplisit saat membuat ekspresi wildcard untuk nama file.
Karena nama file dapat dimulai dengan -
karakter, jauh lebih aman untuk ./*
ekspresi wildcard sebagai ./*
daripada *
.
Eval
eval
harus dihindari.
Eval memungkinkan Anda untuk memperluas variabel yang diteruskan dalam input, tetapi juga dapat mengatur variabel lain, tanpa kemungkinan memeriksanya.
Pipes in While
Gunakan substitusi perintah atau for
loop, daripada pipa while
. Variabel yang diubah di while
tidak merambat ke induk, karena perintah loop dijalankan di sub-shell.
Sub-shell implisit dalam pipa while
dapat membuat pelacakan kesalahan sulit.
last_line='NULL' your_command | while read line; do last_line="${line}" done
Gunakan for for loop jika Anda yakin bahwa input tidak akan mengandung spasi atau karakter khusus (biasanya ini tidak menyiratkan input pengguna).
total=0
Menggunakan substitusi perintah memungkinkan Anda untuk mengarahkan ulang output, tetapi mengeksekusi perintah dalam sub-shell eksplisit, tidak seperti sub-shell implisit, yang menciptakan bash untuk while
.
total=0 last_file= while read count filename; do total+="${count}" last_file="${filename}" done < <(your_command | uniq -c)
Gunakan while
loop di mana tidak perlu memberikan hasil yang kompleks ke shell induk - ini adalah tipikal ketika diperlukan "parsing" yang lebih kompleks. Ingatlah bahwa contoh sederhana kadang-kadang jauh lebih mudah untuk diselesaikan dengan menggunakan alat seperti awk. Ini juga dapat berguna ketika Anda secara khusus tidak ingin mengubah variabel lingkungan induk.
Konvensi penamaan
Nama Fungsi
Huruf kecil dengan garis bawah untuk kata-kata yang terpisah. Pisahkan perpustakaan dengan ::
. Kurung diperlukan setelah nama fungsi. Kata kunci fungsi adalah opsional, tetapi jika digunakan, konsisten di seluruh proyek.
Jika Anda menulis fungsi yang terpisah, gunakan huruf kecil dan kata yang terpisah dengan garis bawah. Jika Anda menulis paket, pisahkan nama paket dengan ::
. Tanda kurung harus pada baris yang sama dengan nama fungsi (seperti dalam bahasa lain di Google), dan tidak memiliki spasi antara nama fungsi dan braket.
Ketika "()" muncul setelah nama fungsi, maka kata kunci fungsi terlihat berlebihan, tetapi meningkatkan identifikasi fungsi dengan cepat.
Nama Variabel
Mengenai nama fungsi.
Nama variabel untuk loop harus sama dengan nama untuk variabel apa pun yang Anda ikuti.
for zone in ${zones}; do something_with "${zone}" done
Nama konstan variabel lingkungan
Semua dalam huruf kapital, dipisahkan oleh garis bawah, dideklarasikan di bagian atas file.
Konstanta dan segala sesuatu yang diekspor ke lingkungan harus dalam huruf besar.
Beberapa hal tetap konstan saat pertama kali diinstal (misalnya, melalui getopts
). Dengan demikian, sangat normal untuk menetapkan konstanta melalui getopts
atau berdasarkan kondisi, tetapi harus dilakukan hanya setelah itu. Perhatikan bahwa declare
tidak berfungsi dengan variabel global di dalam fungsi, jadi sebaiknya readonly
atau export
.
VERBOSE='false' while getopts 'v' flag; do case "${flag}" in v) VERBOSE='true' ;; esac done readonly VERBOSE
Sumber Nama File
Huruf kecil, dengan garis bawah untuk memisahkan kata, jika perlu.
Ini berlaku untuk mencocokkan gaya kode lainnya di Google: maketemplate
atau make_template
, tetapi tidak make-template
.
Variabel Hanya Baca
Gunakan hanya readonly
atau declare -r
untuk memastikan itu hanya-baca.
shell, . , , .
zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)" if [[ -z "${zip_version}" ]]; then error_message else readonly zip_version fi
, , local
. .
, , local
. , .
, ; local
exit code .
my_func2() { local name="$1"
. .
, . , set , .
. .
main
, main
, , .
, main
. , ( , ). main:
main "$@"
, , , main
— , .
.
$?
if
, .
:
if ! mv "${file_list}" "${dest_dir}/" ; then echo "Unable to move ${file_list} to ${dest_dir}" >&2 exit "${E_BAD_MOVE}" fi
, PIPESTATUS
, - , , PIPESTATUS
( , [
PIPESTATUS
).
tar -cf - ./* | ( cd "${DIR}" && tar -xf - ) return_codes=(${PIPESTATUS[*]}) if [[ "${return_codes[0]}" -ne 0 ]]; then do_something fi if [[ "${return_codes[1]}" -ne 0 ]]; then do_something_else fi
shell , .
, bash, ( , sed
).
:
Kesimpulan
.
Silakan luangkan beberapa menit untuk membaca bagian Kata Berpisah di bagian bawah manual C ++ .