Tại sao #! / Usr / bin / env bash vượt trội hơn #! / Bin / bash?


212

Tôi đã thấy ở một số nơi, bao gồm các đề xuất trên trang web này ( Bash shebang ưa thích là gì? ), Để sử dụng #!/usr/bin/env bashtheo sở thích #!/bin/bash. Tôi thậm chí đã thấy một đề xuất#!/bin/bash cá nhân táo bạo sử dụng sai và chức năng bash sẽ bị mất bằng cách làm như vậy.

Tất cả những gì đã nói, tôi sử dụng bash trong một môi trường kiểm tra được kiểm soát chặt chẽ trong đó mọi ổ đĩa đang lưu hành về cơ bản là một bản sao của một ổ đĩa chính. Tôi hiểu đối số tính di động, mặc dù nó không nhất thiết phải áp dụng trong trường hợp của tôi. Có bất kỳ lý do nào khác để thích #!/usr/bin/env bashhơn các lựa chọn thay thế và, giả sử tính di động là một mối quan tâm, có lý do nào để sử dụng nó có thể phá vỡ chức năng không?


7
Nó không nhất thiết phải tốt hơn. Xem câu hỏi nàycâu trả lời của tôi trên unix.stackexchange.com. (Tôi sẽ bỏ phiếu để đóng cái này dưới dạng trùng lặp, nhưng tôi không nghĩ bạn có thể làm điều đó trên các trang web.)
Keith Thompson

2
Ngoài câu trả lời của @ zigg, envcó thể không được đặt tại /usr/bin. Bình luận của Shebang hoàn toàn là một ý tưởng tồi IMHO. Nếu trình thông dịch tập lệnh mặc định của bạn không xử lý các bình luận shebang, thì đó chỉ là một bình luận. Tuy nhiên, nếu bạn biết trình thông dịch tập lệnh có thể xử lý các bình luận shebang và bạn biết đường dẫn đến bash, không có lý do gì để không gọi nó bằng đường dẫn tuyệt đối của nó trừ khi đường dẫn quá dài (không chắc), hoặc bạn có thể chuyển tập lệnh đến một hệ thống không có bash nằm trong / bin. Sau đó, một lần nữa, những cảnh báo mà tôi đã đề cập trước đây áp dụng trong trường hợp đó vì nó liên quan đến tính di động.

1
@KeithThndry, cảm ơn vì đường link. Có lẽ việc tìm kiếm câu trả lời của tôi trước khi đăng câu hỏi hơi hẹp. Tôi bỏ đi tất cả những điều này: (1) linux / unix / posix / etc ... có màu xám và (2) bất cứ ai tuyên bố hoàn toàn có câu trả lời đúng hoàn toàn có câu trả lời đúng cho kịch bản cụ thể của họ.
spugm1r3

3
Hành vi của nhiều thứ trong POSIX / Unix được xác định rõ. Các vị trí không phải lúc nào cũng rõ ràng cắt. Đôi khi phải tồn tại như /etchoặc /bin/sh. bashlà một tiện ích bổ sung cho hầu hết các hệ thống như Unix. Chỉ có Linux, nơi bashđược đảm bảo có mặt /binvà rất có thể cũng được liên kết như /bin/sh. Kể từ khi Linux trở thành Unix thực tế hiện đại cho nhiều người, thực tế là các hệ thống khác ngoài Linux có thể bị lãng quên. Trong câu trả lời của riêng tôi dưới đây, tôi giả sử Linux vì bạn nói bash. Rất nhiều hộp BSD mà tôi đã làm việc thậm chí không được cài đặt.
Sean Perry

2
@Keith - Trong trường hợp Bash (trái ngược với Python trong các câu hỏi khác) ... OpenBSD không có a /bin/bash. Bash không được cài đặt theo mặc định. Nếu bạn muốn nó, bạn phải pkg install bash. Sau khi cài đặt, nó được đặt tại /usr/local/bin/bash. Không có gì được cài đặt tại /bin/bashOpenBSD. Một shebang của #!/bin/bashý chí sẽ lỗi, và #!/usr/bin/env bashsẽ thành công.
jww

Câu trả lời:


229

#!/usr/bin/envtìm kiếm PATHcho bash, và bashkhông phải lúc nào cũng ở /bin, đặc biệt là trên các hệ thống phi Linux. Ví dụ: trên hệ thống OpenBSD của tôi, nó ở/usr/local/bin , nó đã được cài đặt dưới dạng gói tùy chọn.

Nếu bạn hoàn toàn chắc chắn bash là trong /binvà sẽ luôn luôn được, không có hại trong đặt nó trực tiếp trong công việc-nhưng tôi khuyên bạn nên chống lại nó bởi vì kịch bản và các chương trình đều có cuộc sống xa hơn những gì chúng ta ban đầu tin rằng họ sẽ có.


29
những gì về envvị trí? POSIX không ép buộc nó.
Julio Guerra

1
@JulioGuerra Giống như có sẵn một tệp nhị phân /usr/lib/sendmail(hoặc, gần đây hơn /usr/sbin/sendmail) để xử lý thư, đó là lợi ích tốt nhất của hệ thống giống như Unix /usr/bin/envvì env shebang là cách làm phổ biến như vậy. Nó là một giao diện tiêu chuẩn thực tế.
zigg

8
@zigg Điều đó thật UN * X ... <-: Ý tôi là, việc họ có một vị trí tiêu chuẩn là điều tốt nhất env, nhưng bằng cách nào đó không có một vị trí tiêu chuẩn (có thể chỉ là một liên kết mềm) bash. Chưa kể, tại sao sau đó hashbang không chấp nhận #!bashvà sử dụng PATH, thay vì chúng ta làm giống hệt như vậy env. Không đủ khó hiểu cho các tân binh, tôi đoán.
ddekany

1
@JulioGuerra Theo wikipedia bạn đúng: Nó không "được bảo đảm". Thay vào đó, nó có vẻ "nhiều khả năng hơn". Wikipedia nói This mostly works because the path /usr/bin/env is commonly used for the env utilityở đây en.wikipedia.org/wiki/Shebang_(Unix) - Chúng ta phải tâm sự envrằng có "ở đó" trong tất cả các hệ thống.
Xavi Montero

2
@XaviMontero: Tôi đã sử dụng một hệ thống envở trong đó /bin, không phải trong /usr/bin(không chắc chắn là hệ thống nào, có khả năng là SunOS 4). Ngày nay, nó rất có thể /usr/bin/envsẽ có sẵn, chỉ vì sự phổ biến của vụ #!/usr/bin/envhack.
Keith Thompson

39

Vị trí chuẩn của bash là /binvà tôi nghi ngờ điều đó đúng trên tất cả các hệ thống. Tuy nhiên, nếu bạn không thích phiên bản bash đó thì sao? Ví dụ: tôi muốn sử dụng bash 4.2, nhưng bash trên máy Mac của tôi là 3.2.5.

Tôi có thể thử cài đặt lại bash trong /binnhưng đó có thể là một ý tưởng tồi. Nếu tôi cập nhật hệ điều hành của mình, nó sẽ bị ghi đè.

Tuy nhiên, tôi có thể cài đặt bash in /usr/local/bin/bashvà thiết lập PATH của mình thành:

PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"

Bây giờ, nếu tôi chỉ định bash, tôi sẽ không nhận được một chiếc cruddy cũ tại /bin/bash, nhưng cái mới hơn, sáng hơn tại/usr/local/bin . Đẹp!

Ngoại trừ các kịch bản shell của tôi có điều đó !# /bin/bash shebang . Vì vậy, khi tôi chạy các kịch bản shell của mình, tôi nhận được phiên bản bash cũ và tệ hại đó thậm chí không có mảng kết hợp.

Sử dụng /usr/bin/env bashsẽ sử dụng phiên bản bash được tìm thấy trong PATH của tôi. Nếu tôi thiết lập ĐƯỜNG của tôi, vì vậy mà/usr/local/bin/bash được thực thi, đó là bash mà tập lệnh của tôi sẽ sử dụng.

Thật hiếm khi thấy điều này với bash, nhưng nó phổ biến hơn nhiều với Perl và Python:

  • Một số phiên bản Unix / Linux tập trung vào sự ổn định đôi khi bị bỏ lại phía sau với việc phát hành hai ngôn ngữ script này. Cách đây không lâu, Perl của RHEL đã ở mức 5,8,8 - một phiên bản tám năm tuổi của Perl! Nếu ai đó muốn sử dụng các tính năng hiện đại hơn, bạn phải cài đặt phiên bản của riêng bạn.
  • Các chương trình như Perlbrew và Pythonbrew cho phép bạn cài đặt nhiều phiên bản của các ngôn ngữ này. Chúng phụ thuộc vào các tập lệnh thao túng PATH của bạn để có được phiên bản bạn muốn. Mã hóa cứng đường dẫn có nghĩa là tôi không thể chạy tập lệnh của mình theo brew .
  • Cách đây không lâu (được thôi, đã lâu rồi) rằng Perl và Python không phải là các gói tiêu chuẩn có trong hầu hết các hệ thống Unix. Điều đó có nghĩa là bạn không biết hai chương trình này đã được cài đặt ở đâu. Có phải dưới /binkhông? /usr/bin? /opt/bin? Ai biết? Sử dụng #! /usr/bin/env perlcó nghĩa là tôi không phải biết.

Và bây giờ tại sao bạn không nên sử dụng #! /usr/bin/env bash

Khi đường dẫn được mã hóa cứng trong shebang, tôi phải chạy với trình thông dịch đó. Vì vậy, #! /bin/bashbuộc tôi phải sử dụng phiên bản cài đặt mặc định của bash. Vì các tính năng bash rất ổn định (hãy thử chạy phiên bản 2.x của tập lệnh Python trong Python 3.x), rất có thể tập lệnh BASH cụ thể của tôi sẽ không hoạt động và vì tập lệnh bash của tôi có thể được sử dụng bởi hệ thống này và các hệ thống khác , sử dụng phiên bản bash không chuẩn có thể có tác dụng không mong muốn. Rất có khả năng tôi muốn đảm bảo rằng phiên bản bash tiêu chuẩn ổn định được sử dụng với tập lệnh shell của tôi. Vì vậy, tôi có thể muốn cứng mã đường dẫn trong shebang của tôi.


5
Điều này không đúng: "Vị trí chuẩn của bash là / bin" (trừ khi bạn có thể trích dẫn một tài liệu tiêu chuẩn) có lẽ chính xác hơn rằng đó là vị trí "thông thường" trên hầu hết các bản phân phối và macos của Linux, nhưng đó không phải là một tiêu chuẩn trên các hệ thống unix nói chung (và đáng chú ý không phải là vị trí trên hầu hết các * bsds).
tesch1 17/03/19

13

Để gọi bashnó là một chút quá mức cần thiết. Trừ khi bạn có nhiềubash tệp nhị phân như của riêng bạn trong ~ / bin nhưng điều đó cũng có nghĩa là mã của bạn phụ thuộc vào $ PATH có những thứ phù hợp trong đó.

Nó là tiện dụng cho những thứ như pythonmặc dù. Có các kịch bản lệnh bao bọc và môi trường dẫn đến thay thếpython tệp nhị phân đang được sử dụng.

Nhưng không có gì bị mất bằng cách sử dụng đường dẫn chính xác đến nhị phân miễn là bạn chắc chắn đó là nhị phân bạn thực sự muốn.


Tại chỗ cho python. Tôi đã mất số lượng địa điểm pythoncó thể được tìm thấy
zigg

2
Đồng ý /usr/bin/envlà hữu ích hơn cho Python, đặc biệt nếu bạn sử dụng virtualenv.
Dennis

10

Có rất nhiều hệ thống không có Bash in /bin, FreeBSD và OpenBSD chỉ để đặt tên cho một số hệ thống. Nếu tập lệnh của bạn có nghĩa là có thể di động tới nhiều Thông báo khác nhau, bạn có thể muốn sử dụng #!/usr/bin/env bashthay vì#!/bin/bash .

Lưu ý rằng điều này không đúng với sh; đối với các tập lệnh tuân thủ Bourne tôi chỉ sử dụng #!/bin/sh, vì tôi nghĩ rằng hầu như mọi Unix đều tồn shtại /bin.


Trong /binthư mục Ubuntu 18.04 , tôi thấy sh -> dash. Liên kết tượng trưng với dash, tiết lộ bản chất Debian của Ubuntu. Chạy ba chuỗi lệnh này để nhận ra tất cả sôi sục theo sở thích cá nhân: which bashsau which shđó which dash.
noobninja

0

Tôi muốn gói chương trình chính trong một kịch bản như dưới đây để kiểm tra tất cả bashcó sẵn trên hệ thống. Tốt hơn để có nhiều quyền kiểm soát trên phiên bản mà nó sử dụng.

#! /usr/bin/env bash

# This script just chooses the appropriate bash
# installed in system and executes testcode.main

readonly DESIRED_VERSION="5"

declare all_bash_installed_on_this_system
declare bash

if [ "${BASH_VERSINFO}" -ne "${DESIRED_VERSION}" ]
then
    found=0

    all_bash_installed_on_this_system="$(\
        awk -F'/' '$NF == "bash"{print}' "/etc/shells"\
        )"

    for bash in $all_bash_installed_on_this_system
    do
        versinfo="$( $bash -c 'echo ${BASH_VERSINFO}' )"
        [ "${versinfo}" -eq "${DESIRED_VERSION}" ] && { found=1 ; break;}
    done
    if [ "${found}" -ne 1 ]
    then
        echo "${DESIRED_VERSION} not available"
        exit 1
    fi
fi

$bash main_program "$@"

0
 #!/usr/bin/env bash

chắc chắn là tốt hơn bởi vì nó tìm thấy đường dẫn thực thi bash từ biến môi trường hệ thống của bạn.

Chuyển đến shell Linux của bạn và gõ

env

Nó sẽ in tất cả các biến môi trường của bạn.

Chuyển đến tập lệnh shell của bạn và gõ

echo $BASH

Nó sẽ in đường dẫn bash của bạn (theo danh sách biến môi trường) mà bạn nên sử dụng để xây dựng đường dẫn shebang chính xác trong tập lệnh của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.