Saya punya proyek yang terdiri dari sekitar 20 .sh
file kecil . Saya beri nama "kecil" ini karena umumnya, tidak ada file yang memiliki lebih dari 20 baris kode. Saya mengambil pendekatan modular karena dengan demikian saya setia pada filosofi Unix dan lebih mudah bagi saya untuk mempertahankan proyek.
Di awal setiap .sh
file, saya taruh #!/bin/bash
.
Sederhananya, saya mengerti deklarasi skrip memiliki dua tujuan:
- Mereka membantu pengguna mengingat shell apa yang diperlukan untuk menjalankan file (katakanlah, setelah beberapa tahun tanpa menggunakan file).
- Mereka memastikan bahwa skrip berjalan hanya dengan shell tertentu (Bash dalam kasus itu) untuk mencegah perilaku tak terduga jika shell lain digunakan.
Ketika sebuah proyek mulai tumbuh dari katakanlah 5 file menjadi 20 file atau dari 20 file menjadi 50 file (bukan kasus ini tetapi hanya untuk menunjukkan) kami memiliki 20 baris atau 50 baris deklarasi skrip. Saya akui, meskipun mungkin lucu bagi sebagian orang, rasanya agak berlebihan bagi saya untuk menggunakan 20 atau 50 sebagai gantinya mengatakan hanya 1 per proyek (mungkin dalam file utama proyek).
Apakah ada cara untuk menghindari dugaan redundansi 20 atau 50 atau lebih banyak baris deklarasi skrip dengan menggunakan beberapa deklarasi skrip "global", dalam beberapa file utama?
sumber
/bin/bash -x "$script"
Jawaban:
Meskipun proyek Anda sekarang mungkin hanya terdiri dari 50 skrip Bash, ia cepat atau lambat akan mulai mengumpulkan skrip yang ditulis dalam bahasa lain seperti Perl atau Python (untuk manfaat yang dimiliki bahasa skrip ini yang tidak dimiliki Bash).
Tanpa garis yang tepat
#!
di setiap skrip, akan sangat sulit untuk menggunakan berbagai skrip tanpa juga mengetahui penerjemah apa yang digunakan. Tidak masalah jika setiap skrip tunggal dieksekusi dari skrip lain , ini hanya memindahkan kesulitan dari pengguna akhir ke pengembang. Tak satu pun dari dua kelompok orang ini harus tahu bahasa apa yang digunakan untuk menulis naskah.Script shell dieksekusi tanpa garis
#!
dan tanpa juru bahasa eksplisit dieksekusi dengan cara yang berbeda tergantung pada shell apa yang memintanya (lihat misalnya pertanyaan. Shell interpreter mana yang menjalankan script tanpa shebang? Dan terutama jawaban Stéphane ), yang bukan yang Anda inginkan dalam lingkungan produksi (Anda ingin perilaku yang konsisten, dan mungkin bahkan portabilitas).Skrip yang dieksekusi dengan penerjemah eksplisit akan dijalankan oleh penerjemah itu terlepas dari apa yang
#!
dikatakan -line. Ini akan menyebabkan masalah lebih lanjut di telepon jika Anda memutuskan untuk menerapkan kembali, katakanlah, skrip Bash dengan Python atau bahasa lainnya.Anda harus menghabiskan penekanan tombol ekstra itu dan selalu menambahkan garis-
#!
untuk setiap naskah.Di beberapa lingkungan, ada teks hukum multi-paragraf boilerplate di setiap skrip di setiap proyek. Sangat senang bahwa itu hanya garis
#!
yang terasa "berlebihan" dalam proyek Anda.sumber
#!
baris segera setelah file memiliki izin exectuable dan tidak dimuat oleh penerjemah, tetapi oleh shell. Yaitu,/path/to/myprog.pl
jalankan program perl jika#!
garisnya ada (menunjuk ke penerjemah perl) dan file tersebut memiliki izin exec.Anda salah mengerti maksud dari
#!
. Sebenarnya a arahan ke sistem operasi untuk menjalankan program ini di bawah penerjemah yang ditentukan.Jadi skrip bisa dibuat
#!/usr/bin/perl
dan program yang dihasilkan dapat dijalankan sebagai./myprogram
dan penerjemah perl dapat digunakan. Serupa#!/usr/bin/python
akan menyebabkan program untuk berjalan di bawah python.Jadi intinya
#!/bin/bash
memberitahu OS untuk menjalankan program ini di bawah bash.Ini sebuah contoh:
Jadi, meskipun shell saya adalah ksh, program "x" berjalan di bawah bash karena
#!
baris tersebut, dan kita dapat melihatnya secara eksplisit dalam daftar proses.sumber
ps -aux
dapat memberikan peringatan,ps
memberikan peringatanWarning: bad syntax, perhaps a bogus '-'?
.ps
suooprts baik sintaks argumen BSD dan UXIX .-aux
salah UNIX Stephen mungkin berartiaux
BSD mana yang benarps
menunjukkan pemanggilanbash
) bukan sintaks eksplisit; (2)ps -aux
berfungsi dengan baik pada CentOS 7 dan Debian 9 tanpa peringatan; cut'n'paste itu persis output dari mesin saya; seluruh diskusi apakah-
diperlukan atau tidak berlaku untuk versi lama dari linux procps, bukan versi saat ini.Di
.sh
Apa yang buruk adalah
.sh
di akhir nama file.Bayangkan Anda menulis ulang salah satu skrip dengan python.
Nah sekarang Anda harus mengubah baris pertama agar
#!/usr/bin/python3
ini tidak terlalu buruk, karena Anda harus mengubah setiap baris kode lainnya dalam file juga. Namun Anda juga harus mengubah nama file dariprog.sh
menjadiprog.py
. Dan kemudian Anda harus menemukan di mana-mana di skrip lain, dan semua skrip pengguna Anda (skrip yang Anda bahkan tidak tahu ada), dan mengubahnya untuk menggunakan skrip baru.sed -e 's/.sh/.py/g'
dapat membantu orang-orang yang Anda kenal. Tapi sekarang alat kontrol revisi Anda menunjukkan perubahan dalam banyak file yang tidak terkait.Atau lakukan dengan cara Unix dan beri nama program
prog
tidakprog.sh
.Di
#!
Jika Anda memiliki yang benar
#!
, dan atur izin / mode untuk memasukkan eksekusi. Maka Anda tidak perlu tahu penerjemahnya. Komputer akan melakukannya untuk Anda.Untuk sistem non gnu baca manual untuk
chmod
(dan belajar oktal), mungkin membacanya pula.sumber
.image
untuk foto..audio
untuk sound dll. Dengan demikian memberi tahu Anda apa itu tetapi tidak tentang implementasi / encoding.launch-missiles
ataudelete-project-and-make-manager-pissed
saya tidak ingin "jalankan saja" ketika saya hanya ingin tahu tentang bahasa :)file
perintah. itu mengenali sebagian besar tipe file.Mungkin perlu untuk menunjukkan bahwa ini sangat salah. Baris hashbang tidak menghalangi Anda untuk mencoba memberi makan file ke shell / interpreter yang salah:
(atau serupa dengan
awk -f array.sh
dll.)Tetapi bagaimanapun juga, pendekatan lain terhadap modularitas adalah dengan mendefinisikan fungsi-fungsi shell dalam file, satu fungsi per file, jika Anda suka, dan kemudian
source
file-file dari program utama. Dengan begitu, Anda tidak perlu hashbangs: mereka akan diperlakukan sebagai komentar lain, dan semuanya akan berjalan menggunakan shell yang sama. Kelemahannya adalah Anda harussource
menggunakan file dengan fungsi (misalnyafor x in functions/*.src ; do source "$x" ; done
), dan mereka semua akan berjalan menggunakan shell yang sama, sehingga Anda tidak bisa langsung mengganti salah satu dari mereka dengan implementasi-Perl.sumber
Ada - itu disebut portabilitas atau kepatuhan POSIX. Berusaha keras untuk selalu menulis skrip dengan cara portabel, netral-shell, sumber mereka hanya dari skrip yang menggunakan
#!/bin/sh
atau ketika Anda menggunakan secara/bin/sh
interaktif (atau setidaknya shell yang sesuai dengan POSIX sepertiksh
).Namun, skrip portabel tidak menyelamatkan Anda dari:
/bin/sh
skrip dengancsh
.Jika saya dapat menyatakan pendapat saya, "menghindari redundansi" dengan menghilangkan
#!
adalah tujuan yang salah. Sasarannya haruslah kinerja yang konsisten dan benar-benar skrip yang berfungsi, dan mempertimbangkan kasus sudut, mengikuti aturan umum tertentu seperti tidak-parsing-ls atau selalu-mengutip-variabel-kecuali-perlu-kata-pemisahan .Mereka benar-benar bukan untuk pengguna - mereka untuk sistem operasi untuk menjalankan penerjemah yang tepat. "Tepat" dalam hal ini, berarti OS menemukan apa yang ada di shebang; jika kode di bawahnya untuk shell yang salah - itu kesalahan penulis. Mengenai memori pengguna, saya rasa "pengguna" program seperti Microsoft Word atau Google Chrome tidak perlu mengetahui program bahasa apa yang ditulis; penulis mungkin perlu.
Kemudian lagi, skrip yang ditulis dengan mudah dapat menghilangkan kebutuhan untuk bahkan mengingat cangkang mana yang Anda gunakan awalnya, karena skrip portabel harus bekerja di semua cangkang yang sesuai dengan POSIX.
Mereka tidak melakukannya. Apa yang sebenarnya mencegah perilaku tak terduga adalah menulis skrip portabel.
sumber
Alasan mengapa Anda harus meletakkan
#!/bin/bash
di bagian atas setiap skrip adalah karena Anda menjalankannya sebagai proses yang terpisah.Ketika Anda menjalankan skrip sebagai proses baru, OS melihat bahwa itu adalah file teks (sebagai lawan dari file biner yang dapat dieksekusi), dan perlu tahu penerjemah apa yang harus dieksekusi. Jika Anda tidak memberi tahu, OS hanya dapat menebak, menggunakan pengaturan default (yang dapat diubah oleh administrator). Jadi
#!
baris (ditambah menambahkan izin yang dapat dieksekusi, tentu saja) mengubah file teks sederhana menjadi executable yang dapat dijalankan secara langsung, dengan keyakinan bahwa OS tahu apa yang harus dilakukan dengannya.Jika Anda ingin menghapus
#!
garis, maka opsi Anda adalah:Jalankan skrip secara langsung (seperti yang Anda lakukan sekarang), dan berharap bahwa penerjemah default cocok dengan skrip - Anda mungkin aman di sebagian besar sistem Linux, tetapi tidak portabel untuk sistem lain (misalnya Solaris), dan dapat diubah menjadi apa saja (saya bahkan bisa mengaturnya agar berjalan
vim
di file!).Jalankan skrip menggunakan
bash myscript.sh
. Ini berfungsi dengan baik, tetapi Anda harus menentukan path ke skrip, dan itu berantakan.Sumber menggunakan skrip
. myscript.sh
, yang menjalankan skrip dalam proses juru bahasa saat ini (yaitu bukan sebagai sub-proses). Tapi ini hampir pasti membutuhkan modifikasi pada skrip Anda, dan membuatnya kurang modular / dapat digunakan kembali.Dalam kasus 2 dan 3, file tidak perlu (dan seharusnya tidak) menjalankan izin, dan memberikan
.sh
(atau.bash
) akhiran adalah ide yang bagus.Tetapi tidak satu pun dari opsi itu yang terlihat bagus untuk proyek Anda, seperti yang Anda katakan Anda ingin menjaga skrip Anda tetap modular (=> mandiri dan mandiri), jadi Anda harus menjaga
#!/bin/bash
garis Anda di bagian atas skrip.Dalam pertanyaan Anda, Anda juga mengatakan Anda mengikuti filosofi Unix. Jika itu benar, maka Anda harus mempelajari untuk apa
#!
garis itu sebenarnya, dan tetap menggunakannya di setiap skrip yang dapat dieksekusi!sumber
then you should learn what the #! line is really for, and keep using it in every executable script!
. Seseorang dapat mengikuti U. Filosofi hingga titik pengetahuan tertentu. Setelah semua jawaban ini saya mengerti mengapa itu bisa dimasukkan dalam istilah itu. Saya sarankan untuk mengedit jawaban, menggantinya dengan "Lihat shebang sebagai bagian internal dari Filsafat Unix yang Anda hormati dan adopsi".