header shell-script (#! / bin / sh vs #! / bin / csh)

92

Mengapa semua file skrip dimulai dengan

#!/bin/sh

atau dengan

#!/bin/csh

Apakah itu wajib? Apa tujuannya ini? Dan apa perbedaan diantara keduanya?

Satu dua tiga
sumber
1
Untuk skrip csh, Anda harus menggunakan #!/bin/csh -f; the -fmemberi tahu shell untuk tidak mencari pengguna .logindan .cshrc, yang membuat skrip berjalan lebih cepat dan menghindari ketergantungan pada penyiapan pengguna. (Atau lebih baik lagi, jangan menulis skrip csh.) Jangan gunakan -funtuk skrip sh atau bash; itu tidak memiliki arti yang sama.
Keith Thompson

Jawaban:

99

Ini dikenal sebagai Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! interpreter [opsional-arg]

Sebuah shebang hanya relevan jika skrip memiliki izin eksekusi (misalnya chmod u + x script.sh).

Ketika shell mengeksekusi skrip itu akan menggunakan interpreter yang ditentukan.

Contoh:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1
kwarrick
sumber
Anda tidak perlu @ @Kolob Canyon, tetapi dapat membantu beberapa editor dengan penyorotan sintaks (walaupun biasanya ada cara lain untuk mencapai hal yang sama): unix.stackexchange.com/a/88730/193985
Braham Snyder
42

The #!garis memberitahu kernel (khusus, pelaksanaan execvesystem call) bahwa program ini ditulis dalam bahasa ditafsirkan; nama jalur absolut yang mengikuti mengidentifikasi penerjemah. Program yang dikompilasi ke kode mesin dimulai dengan urutan byte yang berbeda - pada kebanyakan Unix modern, 7f 45 4c 46( ^?ELF) yang mengidentifikasinya seperti itu.

Anda dapat menempatkan jalur absolut ke program apa pun yang Anda inginkan setelahnya #!, selama program itu sendiri bukan #!skrip. Kernel menulis ulang pemanggilan

./script arg1 arg2 arg3 ...

di mana ./scriptdimulai dengan, katakanlah #! /usr/bin/perl, seolah-olah baris perintah itu benar-benar ada

/usr/bin/perl ./script arg1 arg2 arg3

Atau, seperti yang Anda lihat, Anda dapat menggunakan #! /bin/shuntuk menulis skrip yang dimaksudkan untuk ditafsirkan oleh sh.

The #!garis hanya diproses jika Anda langsung memanggil script ( ./scriptpada baris perintah); file tersebut juga harus dapat dieksekusi ( chmod +x script). Jika Anda melakukannya sh ./scriptdengan #!garis tidak perlu (dan akan diabaikan jika ada), dan file tidak harus dieksekusi. The titik fitur ini adalah untuk memungkinkan Anda untuk langsung menjalankan program ditafsirkan-bahasa tanpa harus mengetahui bahasa apa yang mereka ditulis dalam. (Do grep '^#!' /usr/bin/*- Anda akan menemukan bahwa banyak program saham besar sebenarnya menggunakan fitur ini.)

Berikut beberapa aturan untuk menggunakan fitur ini:

  • The #!harus dua pertama byte dalam file. Secara khusus, file harus dalam pengkodean yang kompatibel dengan ASCII (mis. UTF-8 akan berfungsi, tetapi UTF-16 tidak) dan tidak boleh dimulai dengan "tanda urutan byte", atau kernel tidak akan mengenalinya sebagai #!naskah.
  • Jalur setelahnya #!harus jalur absolut (dimulai dengan /). Tidak boleh berisi spasi, tab, atau karakter baris baru.
  • Ini adalah gaya yang bagus, tetapi tidak diharuskan, untuk memberi spasi antara #!dan /. Jangan meletakkan lebih dari satu tempat di sana.
  • Anda tidak dapat meletakkan variabel shell pada #!baris tersebut, mereka tidak akan diperluas.
  • Anda dapat meletakkan satu argumen baris perintah setelah jalur absolut, dipisahkan darinya dengan satu spasi. Seperti jalur absolut, argumen ini tidak boleh berisi spasi, tab, atau karakter baris baru. Terkadang hal ini diperlukan untuk membuat semuanya bekerja ( #! /usr/bin/awk -f), terkadang hanya berguna ( #! /usr/bin/perl -Tw). Sayangnya, Anda tidak dapat meletakkan dua atau lebih argumen setelah jalur absolut.
  • Beberapa orang akan memberitahu Anda untuk menggunakan #! /usr/bin/env interpreterbukan #! /absolute/path/to/interpreter. Ini hampir selalu merupakan kesalahan. Itu membuat perilaku program Anda bergantung pada $PATHvariabel pengguna yang memanggil skrip. Dan tidak semua sistem ada envdi tempat pertama.
  • Program yang membutuhkan setuidatau setgidhak istimewa tidak dapat digunakan #!; mereka harus dikompilasi ke kode mesin. (Jika Anda tidak tahu apa setuiditu, jangan khawatir tentang ini.)

Mengenai csh, ini shkira-kira berhubungan dengan apa yang dilakukan Nutrimat Advanced Tea Substitute terhadap teh. Ini memiliki (atau lebih tepatnya memiliki; implementasi modern shtelah menangkap) sejumlah keunggulan dibandingkan shuntuk penggunaan interaktif, tetapi menggunakannya (atau turunannya tcsh) untuk skrip hampir selalu merupakan kesalahan . Jika Anda baru mengenal skrip shell secara umum, saya sangat menyarankan Anda mengabaikannya dan fokuslah sh. Jika Anda menggunakan cshkerabat sebagai shell login Anda, alihkan ke bashatau zsh, sehingga bahasa perintah interaktif akan sama dengan bahasa skrip yang Anda pelajari.

zwol
sumber
Versi terbaru Linux memungkinkan interpreter yang ditentukan menjadi skrip. Merupakan praktik umum untuk menghilangkan spasi setelah #!; tidak ada komentar apakah itu gaya yang bagus. Lihat pertanyaan ini dan jawaban saya untuk diskusi tentang pro dan kontra #!/usr/bin/envperetasan.
Keith Thompson
@KeithThompson Saya mendapat kesan bahwa Linux adalah satu - satunya varian Unix umum yang memungkinkan interpreter menjadi skrip, jadi masih belum bisa diandalkan. Sejak saya menulis ini, saya sendiri mengalami situasi di mana #!/usr/bin/envHal yang Benar, tetapi menurut saya itu hampir selalu merupakan ide yang buruk.
zwol
4

Ini mendefinisikan shell (command interpreter) apa yang Anda gunakan untuk menafsirkan / menjalankan skrip Anda. Setiap shell sedikit berbeda dalam cara berinteraksi dengan pengguna dan menjalankan skrip (program).

Saat Anda mengetikkan perintah pada prompt Unix, Anda sedang berinteraksi dengan shell.

Misalnya, #!/bin/cshmengacu pada C-shell, /bin/tcsht-shell, /bin/bashbash shell, dll.

Anda dapat mengetahui shell interaktif mana yang Anda gunakan

 echo $SHELL

perintah, atau alternatif

 env | grep -i shell

Anda dapat mengubah shell perintah Anda dengan chshperintah.

Masing-masing memiliki set perintah yang sedikit berbeda dan cara menugaskan variabel dan rangkaian konstruksi pemrogramannya sendiri. Misalnya pernyataan if-else dengan bash terlihat berbeda dari yang ada di C-shell.

Halaman ini mungkin menarik karena "menerjemahkan" antara perintah / sintaks bash dan tcsh.

Menggunakan direktif dalam skrip shell memungkinkan Anda menjalankan program menggunakan shell yang berbeda. Misalnya saya menggunakan tcshshell secara interaktif, tetapi sering menjalankan skrip bash menggunakan / bin / bash di file skrip.

Ke samping:

Konsep ini meluas ke skrip lain juga. Misalnya jika Anda memprogram dengan Python, Anda akan memasukkan

 #!/usr/bin/python

di bagian atas program Python Anda

Levon
sumber
Jadi apakah itu wajib? Bagaimana saya tahu shell mana yang sebenarnya saya gunakan?
One Two Three
Jadi jika saya menulis skrip untuk digunakan seseorang di mesin mereka, dan saya tidak tahu shell apa yang mereka gunakan. (Sayangnya, orang ini tidak tahu apa-apa tentang hal ini, sehingga yang dapat dia lakukan hanyalah menjalankan skrip tanpa mengubah apa pun). Bisakah saya melakukan sesuatu seperti itu #! $SHELL? Apakah ini akan menempatkan cangkang yang benar di Sebang?
One Two Three
1
@OneTwoThree Kebanyakan sistem memiliki shell standar, jika Anda menulis skrip bash atau csh, Anda akan baik-baik saja. Shell apa yang mereka gunakan secara interaktif tidak masalah, itulah keindahan dari eg, !#/bin/bashdirective. Ini memberi tahu sistem shell apa yang akan digunakan untuk menjalankan skrip shell Anda.
Levon
Nilai dari $SHELLtidak selalu memberi tahu Anda shell mana yang Anda jalankan saat ini; itu biasanya memberi tahu Anda shell default Anda . tcsh set $versiondan $tcsh; set pesta $BASH_VERSION. Tidak semua cangkang memiliki mekanisme yang sama.
Keith Thompson
1
@OneTwoThree: #!Baris harus cocok dengan sintaks skrip, bukan shell interaktif yang digunakan oleh siapa pun yang menjalankan skrip.
Keith Thompson