2012-05-14 30 views
47

Tại sao tất cả các file kịch bản bắt đầu vớivỏ kịch bản (#!/bin/sh vs #!/bin/csh)

#!/bin/sh 

hoặc với

#!/bin/csh 

Đó có phải là cần thiết? Mục đích của việc này là gì? Và sự khác nhau giữa hai người là gì?

+1

Đối với tập lệnh csh, bạn nên sử dụng '#!/Bin/csh -f'; '-f' yêu cầu trình bao không mã nguồn' .login' và '.cshrc' của người dùng, làm cho tập lệnh chạy nhanh hơn và tránh sự 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 kịch bản csh.) Không sử dụng '-f' cho sh hoặc bash script; nó không có cùng ý nghĩa. –

Trả lời

54

này được biết đến như một Shebang:

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

# phiên dịch [optional-arg]

Một shebang chỉ phù hợp khi tập lệnh có quyền thực thi (ví dụ: chmod u + x script.sh).

Khi trình bao thực hiện tập lệnh, nó sẽ sử dụng trình thông dịch được chỉ định.

Ví dụ:

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

$ chmod u+x foo.sh 
$ ./foo.sh 
    1 
+0

Liên kết ở trên cần sửa chữa. – Levon

+1

Bạn có cần thêm '#!/Bin/sh' vào' .profile' không? –

+0

@Kolob Canyon bạn không cần, nhưng nó có thể giúp một số biên tập viên làm nổi bật cú pháp (mặc dù thường có những cách khác để đạt được điều tương tự): https://unix.stackexchange.com/a/88730/193985 –

4

Điều này xác định trình bao (trình thông dịch lệnh) bạn đang sử dụng để diễn giải/chạy tập lệnh của mình. Mỗi shell là hơi khác nhau trong cách nó tương tác với người dùng và thực hiện các kịch bản (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-vỏ, /bin/tcsh t-vỏ, /bin/bash vỏ bash vv

Bạn có thể biết được tương tác vỏ bạn đang sử dụng lệnh

echo $SHELL 

, hoặc cách khác

env | grep -i shell 

Bạn có thể thay đổi trình bao lệnh bằng lệnh chsh.

Mỗi bộ có một bộ lệnh hơi khác và cách gán biến và tập hợp các 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.

This page có thể được quan tâm vì nó "dịch" giữa các lệnh/cú pháp bash và tcsh.

Sử dụng chỉ thị trong tập lệnh trình bao cho phép bạn chạy các chương trình bằng cách sử dụng trình bao khác. Ví dụ: tôi sử dụng vỏ tcsh tương tác, nhưng thường chạy tập lệnh bash bằng/bin/bash trong tệp tập lệnh.

Ngoài:

Khái niệm này cũng mở rộng sang các tập lệnh khác. Ví dụ nếu bạn lập trình bằng Python bạn muốn đặt

#!/usr/bin/python 

ở đầu chương trình Python của bạn

+0

Vì vậy, nó là cần thiết? Làm cách nào để biết tôi đang sử dụng trình bao nào? –

+0

Vì vậy, nếu tôi đang viết kịch bản cho một người nào đó để sử dụng trên máy tính của họ và tôi không biết họ đang sử dụng trình bao nào. (Người này, thật không may, là không biết gì về công cụ này, do đó tất cả những gì anh ta có thể làm là chạy kịch bản mà không thay đổi một thứ gì). Tôi có thể làm một cái gì đó như '#! $ SHELL'? Điều này sẽ đặt vỏ chính xác trong Shebang? –

+1

@OneTwoThree Hầu hết các hệ thống đều có vỏ chuẩn, nếu bạn viết một tập lệnh bash hoặc csh, bạn sẽ ổn. Vỏ nào họ đang sử dụng tương tác ** không ** quan trọng, đó là vẻ đẹp của ví dụ, '! #/Bin/bash'directive. Nó cho hệ thống biết shell sử dụng để thực thi kịch bản lệnh shell của bạn. – Levon

36

Dòng #! nói với hạt nhân (đặc biệt là việc thực hiện execve hệ thống gọi) 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 sau xác định trình thông dịch. Các chương trình được biên dịch thành 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 đườ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 với, nói, #! /usr/bin/perl, như thể dòng lệnh đã thực sự được

/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 tập lệnh được diễn giải bởi sh.

Dòng #! chỉ được xử lý nếu bạn trực tiếp gọi tập lệnh (./script trên dòng lệnh); tập tin cũng phải được thực thi (chmod +x script). Nếu bạn làm sh ./script dòng #! là không cần thiết (và sẽ bị bỏ qua nếu có) và tệp không 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 ngôn ngữ diễn giải mà không cần phải biết ngôn ngữ được viết. (Do grep '^#!' /usr/bin/* - bạn sẽ khám phá ra rằng rất nhiều chương trình chứng khoán đang 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:

  • các #! phải là đầu tiên hai byte trong file. Cụ thể, tệp phải phải được mã hóa tương thích ASCII (ví dụ: UTF-8 sẽ hoạt động, nhưng UTF-16 sẽ không) và không được bắt đầu bằng "dấu thứ tự byte" hoặc hạt nhân sẽ không nhận ra nó dưới dạng tập lệnh #!.
  • Đường dẫn sau #! phải là đường dẫn tuyệt đối (bắt đầu bằng /). Nó không thể chứa dấu cách, tab hoặc ký tự dòng mới.
  • Đó là phong cách tốt, nhưng không bắt buộc, để đặt khoảng cách giữa #!/. Không đặt nhiều hơn một không gian ở đó.
  • Bạn không thể đặt biến shell trên dòng #!, chúng sẽ không được mở rộng.
  • Bạn có thể đặt một đối số dòng lệnh sau đường dẫn tuyệt đối, được tách biệt với nó bằng một dấu cách. Giống như đường dẫn tuyệt đối, đối số này không thể chứa dấu cách, tab hoặc ký tự dòng mới. Đôi khi điều này là cần thiết để có được những thứ để làm việc (#! /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.
  • Một số người sẽ cho bạn biết sử dụng #! /usr/bin/env interpreter thay vì #! /absolute/path/to/interpreter. Điều này hầu như luôn là một sai lầm. Điều này làm cho hành vi của chương trình phụ thuộc vào biến số $PATH của người dùng gọi tập lệnh. Và không phải tất cả các hệ thống đều có số env ở vị trí đầu tiên.
  • Các chương trình cần 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ề việc này.)

Về csh, nó liên quan đến sh khoảng như Nutrimat Advanced Tea Substitute không uống trà. Nó có (hoặc đúng hơn là, việc triển khai hiện đại sh đã bắt kịp) một số lợi thế hơn sh để sử dụng tương tác, nhưng sử dụng nó (hoặc hậu duệ của nó tcsh) để tạo tập lệnh là almost always a mistake. Nếu bạn mới sử dụng shell script nói chung, tôi 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 vỏ đăng nhập, hãy chuyển sang bash hoặc zsh, để ngôn ngữ lệnh tương tác sẽ giống như ngôn ngữ kịch bản bạn đang học.

+1

xuất sắc lời khuyên –

+0

Các phiên bản gần đây của Linux cho phép trình thông dịch được chỉ định làm tập lệnh. Thực hành phổ biến là bỏ qua khoảng trống sau '#!'; không có bình luận về việc đó là phong cách tốt. Xem [câu hỏi này] (http://unix.stackexchange.com/q/29608/10454) và [câu trả lời của tôi] (http://unix.stackexchange.com/a/29620/10454) để thảo luận về các chuyên gia và chống lại hack '#!/usr/bin/env'. –

+0

@KeithThompson Tôi theo ấn tượng Linux là phiên bản Unix duy nhất * duy nhất cho phép người phiên dịch trở thành một tập lệnh, vì vậy nó vẫn không phải là thứ để dựa vào. Vì tôi đã viết điều này, bản thân tôi đã gặp phải một tình huống mà '#!/Usr/bin/env' là Điều Đúng, nhưng nó vẫn là ý kiến ​​của tôi rằng nó gần như luôn luôn là một ý tưởng tồi. – zwol

Các vấn đề liên quan