2017-01-25 11 views
5

Khi làm việc trên một dự án được viết bởi đồng nghiệp cũ của tôi, tôi nhận thấy rằng tất cả các tệp .sh không chứa gì ngoài các định nghĩa hàm bắt đầu bằng #!/bin/false. một cơ chế an toàn ngăn chặn việc thực thi các tệp chỉ bao gồm.Mục đích #!/Bin/false trong tập lệnh bash

Ví dụ:

my_foo.sh

#!/bin/false 
function foo(){ 
    echo foontastic 
} 

my_script.sh

#!/bin/bash 

./my_foo.sh # does nothing 
foo # error, no command named "foo" 

. ./my_foo.sh 
foo # prints "foontastic" 

Tuy nhiên khi tôi không sử dụng #!/bin/false, ảnh hưởng của cả hai sử dụng hợp lý và không đúng là chính xác giống nhau:

Ví dụ:

my_bar.sh

function bar(){ 
    echo barvelous 
} 

my_script.sh

#!/bin/bash 

./my_bar.sh # spawn a subshell, defines bar and exit, effectively doing nothing 
bar # error, no command named "bar" 

. ./my_bar.sh 
bar # prints "barvelous" 

Kể từ đúng cách sử dụng những kịch bản bằng cách bao gồm chúng với source trong cả hai trường hợp công trình như mong đợi, và thực hiện chúng trong cả hai trường hợp không có gì từ quan điểm của một shell cha và không tạo ra thông báo lỗi liên quan đến việc sử dụng không hợp lệ, mục đích chính xác của mục đích là #!/bash/false trong kịch bản đó là gì?

+2

Bạn đã tự nói: với nội dung «false', nội dung không được thực thi. Đó là một sự an toàn, trong trường hợp kịch bản là dễ bị lỗi khi được sử dụng trong bối cảnh sai hoặc ressource nặng. Rất có thể, đó là thói quen mà đồng nghiệp của bạn đã chọn, điều đó không ảnh hưởng đến mã trong hầu hết các trường hợp nhưng điều đó có thể hữu ích trong những trường hợp phức tạp hơn. – Aserre

+0

Cũng cần lưu ý rằng, dòng she-bang '#!/Bin/true' hoặc' #!/Bin/false' không ảnh hưởng đến kịch bản khi bạn gọi trình thông dịch shell trực tiếp dưới dạng 'bash my_script.sh ', cú pháp này chạy script với' bash' không có vấn đề gì và lặp lại đầu ra 'foontastic' – Inian

+2

'./my_bar.sh' không sinh ra một subshell: nó sinh ra một shell hoàn toàn mới. Đây không chỉ là một kỹ thuật: subshells nhận được một bản sao của tất cả các biến của shell chính (bao gồm cả các biến không được đánh dấu để export), trong khi một shell riêng chỉ nhận các biến được export. Subshells được khởi chạy theo các cách khác, ví dụ bằng cách đặt dấu ngoặc kép '()', bắt đầu các đường dẫn '|', quá trình/thay thế lệnh '$()' '<()' '>()'. – Fred

Trả lời

4

Nói chung, chúng ta hãy xem xét một tập tin testcode với mã bash trong đó

bạn có thể làm ba việc khác nhau với nó:

$ ./testcode 
You are executing ./testcode 

này hoạt động nếu testcode có đủ quyền hạn và đúng shebang. Với một shebang của #!/bin/false, kết quả này không có gì và trả về mã 1 (sai).

$ bash ./testcode 
You are executing ./testcode 

Điều này hoàn toàn bỏ qua shebang (thậm chí có thể bị thiếu) và chỉ yêu cầu quyền đọc, không được phép thực thi. Đây là cách để gọi các script bash từ một dòng lệnh CMD trong Windows (nếu bạn có bash.exe trong PATH của bạn ...), vì ở đó, machanism của shebang không hoạt động.

$ . ./testcode 
You are sourcing ./testcode 

này cũng hoàn toàn không quan tâm đến các công việc, như ở trên, nhưng nó là một vấn đề hoàn toàn khác nhau, vì nguồn một kịch bản nghĩa có vỏ hiện thực nó, trong khi thực hiện một kịch bản nghĩa cách gọi một trình bao mới để thực thi nó. Ví dụ: nếu bạn đặt lệnh exit trong tập lệnh có nguồn gốc, bạn thoát khỏi trình bao hiện tại, điều này hiếm khi bạn muốn. Do đó, tìm nguồn cung ứng thường được sử dụng để tải các định nghĩa hàm hoặc hằng số, theo cách tương tự như câu lệnh import của các ngôn ngữ lập trình khác và các lập trình viên khác nhau phát triển các thói quen khác nhau giữa các tập lệnh được thực thi và bao gồm các tệp. Tôi thường không sử dụng bất kỳ tiện ích nào cho tiện ích mở rộng cũ (những người khác sử dụng .sh), nhưng tôi sử dụng một phần mở rộng là .shinc cho phần sau. Đồng nghiệp cũ của bạn đã sử dụng một shebang của #!/bin/false và người ta chỉ có thể hỏi họ tại sao họ lại ưa thích điều này với hàng triệu khả năng khác. Một lý do mà nói đến cái tâm của tôi là bạn có thể sử dụng file nói với những tập tin ngoài:

$ file testcode testcode2 
testcode: Bourne-Again shell script, ASCII text executable 
testcode2: a /bin/false script, ASCII text executable 

Tất nhiên, nếu bao gồm các file chỉ chứa các định nghĩa chức năng, đó là vô hại để thực hiện chúng, vì vậy tôi không nghĩ rằng đồng nghiệp của bạn đã làm nó để ngăn chặn thực hiện.

Một thói quen của tôi, lấy cảm hứng từ thế giới Python, là đặt một số xét nghiệm hồi quy ở phần cuối của .shinc tác phẩm của tôi (ít nhất là trong khi phát triển)

... function definitions here ... 

[ "$0" != "${BASH_SOURCE[0]}" ] && return 

... regression tests here ... 

Kể từ return tạo ra một lỗi trong kịch bản thực hiện nhưng OK trong các tập lệnh có nguồn gốc, một cách khó hiểu hơn để có được kết quả tương tự là

... function definitions here ... 

return 2>/dev/null || : 

... regression tests here ... 
1

Sự khác biệt trong việc sử dụng #!/bin/false hoặc không phải từ quan điểm của vỏ mẹ nằm trong mã trả về.

/bin/false luôn trả về mã trả lại không thành công (trong trường hợp của tôi 1, nhưng không chắc chắn nếu nó là tiêu chuẩn).

Hãy thử rằng:

./my_foo.sh //does nothing 
echo $? // shows "1", a.k.a failing 

./my_bar.sh //does nothing 
echo $? // shows "0", a.k.a. everything went right 

Vì vậy, sử dụng #!/bin/false không chỉ tài liệu thực tế là kịch bản không có ý định để được thực thi, mà còn tạo ra một mã trở lại báo lỗi khi làm như vậy.

+0

Ví dụ thứ hai của bạn không đúng, nếu my_bar.sh chứa "exit 1". Ngoài ra khi bao gồm các tệp đó thay vì thực thi (". ./my_foo", ". ./my_bar") giá trị trả về thực sự là một giá trị trả về của lệnh được thực thi cuối cùng, vì vậy để sử dụng các giá trị trả về như các biện pháp bảo vệ, tôi sẽ cần phải kết thúc tất cả tập lệnh chỉ bao gồm với 'true'. –

+0

Tập lệnh 'my_bar.sh' được cung cấp bởi OP không bao gồm lệnh' thoát'. Ngoài ra, mã trả lại chỉ là mã trả về của tập lệnh. Vấn đề là sử dụng '#!/Bin/false' sẽ tạo ra một mã trả về sai. –

+0

Theo hướng dẫn: 'sai - không làm gì cả, không thành công' – ash

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