Tại sao tất cả các tệp script đều bắt đầu bằng
#!/bin/sh
Hoặc với
#!/bin/csh
Có bắt buộc không? Mục đích của việc này là gì? Và sự khác biệt giữa hai là gì?
Tại sao tất cả các tệp script đều bắt đầu bằng
#!/bin/sh
Hoặc với
#!/bin/csh
Có bắt buộc không? Mục đích của việc này là gì? Và sự khác biệt giữa hai là gì?
Câu trả lời:
Điều này được gọi là Shebang
:
http://en.wikipedia.org/wiki/Shebang_(Unix)
#! thông dịch viên [tùy chọn-arg]
Một shebang chỉ có liên quan khi một tập lệnh có quyền thực thi (ví dụ: chmod u + x script.sh).
Khi một trình bao thực thi tập lệnh, nó sẽ sử dụng trình thông dịch được chỉ định.
Thí dụ:
#!/bin/bash
# file: foo.sh
echo 1
$ chmod u+x foo.sh
$ ./foo.sh
1
Các #!
dòng nói với hạt nhân (đặc biệt là việc thực hiện các execve
cuộc gọi hệ thống) rằng chương trình này được viết bằng một ngôn ngữ giải thích; tên đường dẫn tuyệt đối theo sau xác định trình thông dịch. Các chương trình được biên dịch sang mã máy bắt đầu bằng một chuỗi byte khác - trên hầu hết các Unix hiện đại, 7f 45 4c 46
( ^?ELF) xác định chúng như vậy.
Bạn có thể đặt một đường dẫn tuyệt đối đến bất kỳ chương trình nào bạn muốn sau đó #!
, miễn là chương trình đó không phải là #!
tập lệnh. Kernel viết lại một lời gọi
./script arg1 arg2 arg3 ...
nơi ./script
bắt đầu, giả sử #! /usr/bin/perl
, như thể dòng lệnh thực sự
/usr/bin/perl ./script arg1 arg2 arg3
Hoặc, như bạn đã thấy, bạn có thể sử dụng #! /bin/sh
để viết một kịch bản nhằm mục đích diễn giải sh
.
Các #!
dòng được chỉ xử lý nếu bạn trực tiếp gọi kịch bản ( ./script
trên dòng lệnh); tệp cũng phải là tệp thực thi ( chmod +x script
). Nếu bạn thực hiện sh ./script
, #!
dòng này là không cần thiết (và sẽ bị bỏ qua nếu có) và tệp không cần phải thực thi. Các điểm của tính năng này là để cho phép bạn trực tiếp gọi các chương trình giải thích ngôn ngữ mà không cần phải biết những gì ngôn ngữ mà họ được viết bằng. (Đỗ grep '^#!' /usr/bin/*
- bạn sẽ khám phá ra rằng một lớn nhiều chương trình cổ phiếu này trong thực tế sử dụng tính năng này.)
Dưới đây là một số quy tắc để sử dụng tính năng này:
#!
phải là hai đầu tiên byte trong file. Đặc biệt, tệp phải ở dạng mã hóa tương thích ASCII (ví dụ: UTF-8 sẽ hoạt động, nhưng UTF-16 thì không) và không được bắt đầu bằng "dấu thứ tự byte", nếu không hạt nhân sẽ không nhận ra nó là #!
kịch bản.#!
phải là đường dẫn tuyệt đối (bắt đầu bằng /
). Nó không được chứa các ký tự khoảng trắng, tab hoặc dòng mới.#!
và /
. Không đặt nhiều hơn một khoảng trống ở đó.#!
dòng, chúng sẽ không được mở rộng.#! /usr/bin/awk -f
), đôi khi nó chỉ hữu ích ( #! /usr/bin/perl -Tw
). Thật không may, bạn không thể đặt hai hoặc nhiều đối số sau đường dẫn tuyệt đối.#! /usr/bin/env interpreter
thay vì #! /absolute/path/to/interpreter
. Điều này hầu như luôn luôn là một sai lầm. Nó làm cho hành vi của chương trình của bạn phụ thuộc vào $PATH
biến của người dùng gọi script. Và không phải tất cả các hệ thống đều có env
ngay từ đầu.setuid
hoặc setgid
đặc quyền không thể sử dụng #!
; chúng phải được biên dịch thành mã máy. (Nếu bạn không biết setuid
là gì , đừng lo lắng về điều này.)Về vấn đề csh
, nó liên quan sh
gần giống như sản phẩm thay thế trà nâng cao Nutrimat đối với trà. Nó có (hoặc đúng hơn là có; các triển khai hiện đại của sh
đã bắt kịp) một số lợi thế hơn sh
cho việc sử dụng tương tác, nhưng việc sử dụng nó (hoặc hậu duệ của nó tcsh
) để viết kịch bản hầu như luôn là một sai lầm . Nếu bạn chưa quen với shell script nói chung, tôi thực sự khuyên bạn nên bỏ qua nó và tập trung vào sh
. Nếu bạn đang sử dụng csh
tương đối làm trình bao đăng nhập của mình, hãy chuyển sang bash
hoặc zsh
, để ngôn ngữ lệnh tương tác sẽ giống với ngôn ngữ kịch bản mà bạn đang học.
#!
; không có bình luận về việc đó là phong cách tốt. Xem câu hỏi này và câu trả lời của tôi để thảo luận về ưu và nhược điểm của bản #!/usr/bin/env
hack.
#!/usr/bin/env
là Điều Đúng, nhưng tôi vẫn cho rằng đó hầu như luôn là một ý kiến tồi.
Điều này xác định shell (trình thông dịch lệnh) bạn đang sử dụng để thông dịch / chạy tập lệnh của mình. Mỗi shell hơi khác nhau về cách nó tương tác với người dùng và thực thi các script (chương trình).
Khi bạn nhập một lệnh tại dấu nhắc Unix, bạn đang tương tác với trình bao.
Ví dụ: #!/bin/csh
đề cập đến C-shell, /bin/tcsh
t-shell, /bin/bash
bash shell, v.v.
Bạn có thể biết mình đang sử dụng trình bao tương tác nào
echo $SHELL
lệnh, hoặc cách khác
env | grep -i shell
Bạn có thể thay đổi trình bao lệnh của mình bằng chsh
lệnh.
Mỗi loại có một bộ lệnh hơi khác nhau và cách gán các biến cũng như bộ cấu trúc lập trình riêng của nó. Ví dụ: câu lệnh if-else với bash trông khác với câu lệnh trong C-shell.
Trang này có thể được quan tâm vì nó "dịch" giữa cú pháp / lệnh bash và tcsh.
Sử dụng chỉ thị trong tập lệnh shell cho phép bạn chạy các chương trình bằng cách sử dụng shell khác. Ví dụ: tôi sử dụng tcsh
shell một cách tương tác, nhưng thường chạy các tập lệnh bash bằng cách sử dụng / bin / bash trong tệp script.
Qua một bên:
Khái niệm này cũng mở rộng cho các tập lệnh khác. Ví dụ: nếu bạn lập trình bằng Python, bạn sẽ đặt
#!/usr/bin/python
ở đầu chương trình Python của bạn
#! $SHELL
nào? Điều này có đặt đúng vỏ vào Shebang không?
!#/bin/bash
chỉ thị ví dụ . Nó cho hệ thống biết shell cần sử dụng để thực thi shell script của bạn.
$SHELL
không nhất thiết cho bạn biết bạn đang chạy trình bao nào vào lúc này; nó thường cho bạn biết trình bao mặc định của bạn . tcsh bộ $version
và $tcsh
; bộ bash $BASH_VERSION
. Không phải tất cả các shell nhất thiết phải có cơ chế giống nhau.
#!
Dòng phải khớp với cú pháp của script, không phải là shell tương tác được sử dụng bởi bất kỳ ai đang chạy script.
#!/bin/csh -f
; lệnh-f
cho trình bao không lấy nguồn của người dùng.login
và.cshrc
, điều này làm cho tập lệnh chạy nhanh hơn và tránh phụ thuộc vào thiết lập của người dùng. (Hoặc tốt hơn, không viết script csh.) Không sử dụng-f
cho các script sh hoặc bash; nó không có cùng ý nghĩa.