Sự khác biệt giữa việc thực thi một tập lệnh Bash so với tìm nguồn cung ứng là gì?


Câu trả lời:


345

Câu trả lời ngắn

Tìm kiếm một tập lệnh sẽ chạy các lệnh trong quy trình shell hiện tại .

Thực thi một tập lệnh sẽ chạy các lệnh trong một quy trình shell mới .

Sử dụng nguồn nếu bạn muốn tập lệnh thay đổi môi trường trong trình bao hiện đang chạy của bạn. sử dụng thực thi khác.

Nếu bạn vẫn còn bối rối, xin vui lòng đọc tiếp.

Thuật ngữ

Để làm rõ một số nhầm lẫn phổ biến về cú pháp thực thi và cú pháp nguồn:

./myscript

Điều này sẽ thực thi myscript với điều kiện là tệp có thể thực thi được và nằm trong thư mục hiện tại. Dấu chấm và dấu gạch chéo ( ./) hàng đầu biểu thị thư mục hiện tại. Điều này là cần thiết bởi vì thư mục hiện tại thường không (và thường không nên) trong $PATH.

myscript

Điều này sẽ thực thi myscript nếu tập tin được thực thi và nằm trong một số thư mục trong $PATH.

source myscript

Điều này sẽ nguồn myscript . Các tập tin không cần phải được thực thi nhưng nó phải là một tập lệnh shell hợp lệ. Các tập tin có thể trong thư mục hiện tại hoặc trong một thư mục trong $PATH.

. myscript

Điều này cũng sẽ nguồn myscript . "Chính tả" này là chính thức theo định nghĩa của POSIX . Bash định nghĩa sourcenhư một bí danh cho dấu chấm.

Trình diễn, thuyết trình

Xem xét myscript.shvới nội dung sau:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

Trước khi chúng tôi thực thi tập lệnh trước tiên, chúng tôi kiểm tra môi trường hiện tại:

$ env | grep FOO
$ echo $PWD
/home/lesmana

Biến FOOkhông được xác định và chúng tôi đang ở trong thư mục chính.

Bây giờ chúng tôi thực hiện các tập tin:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Kiểm tra lại môi trường:

$ env | grep FOO
$ echo $PWD
/home/lesmana

Biến FOOkhông được đặt và thư mục làm việc không thay đổi.

Đầu ra tập lệnh cho thấy rõ ràng rằng biến đã được đặt và thư mục đã được thay đổi. Việc kiểm tra sau đó cho thấy biến không được đặt và thư mục không thay đổi. Chuyện gì đã xảy ra? Những thay đổi đã được thực hiện trong một vỏ mới . Các hiện vỏ sinh ra một mới shell để chạy các kịch bản. Kịch bản đang chạy trong trình bao mới và tất cả các thay đổi đối với môi trường có hiệu lực trong trình bao mới. Sau khi kịch bản được thực hiện, shell mới bị phá hủy. Tất cả các thay đổi đối với môi trường trong lớp vỏ mới đều bị phá hủy bằng lớp vỏ mới. Chỉ văn bản đầu ra được in trong vỏ hiện tại.

Bây giờ chúng tôi nguồn tập tin:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Kiểm tra lại môi trường:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

Biến FOO được đặt và thư mục làm việc đã thay đổi.

Tìm nguồn cung cấp kịch bản không tạo ra một vỏ mới. Tất cả các lệnh được chạy trong shell hiện tại và các thay đổi đối với môi trường có hiệu lực trong shell hiện tại.

Lưu ý rằng trong ví dụ đơn giản này, đầu ra của việc thực thi giống như tìm nguồn cung cấp tập lệnh. Điều này không nhất thiết phải luôn luôn như vậy.

Một cuộc biểu tình khác

Xem xét kịch bản sau đây pid.sh:

#!/bin/sh
echo $$

(biến đặc biệt $$mở rộng tới PID của quy trình shell đang chạy hiện tại)

Đầu tiên in PID của shell hiện tại:

$ echo $$
25009

Nguồn kịch bản:

$ source pid.sh
25009

Thực thi tập lệnh, lưu ý PID:

$ ./pid.sh
25011

Nguồn lại:

$ source pid.sh
25009

Thực hiện lại:

$ ./pid.sh
25013

Bạn có thể thấy rằng việc tìm nguồn cung cấp tập lệnh chạy trong cùng một quy trình trong khi thực thi tập lệnh sẽ tạo ra một quy trình mới mọi lúc. Quá trình mới đó là trình bao mới được tạo để thực thi tập lệnh. Tìm nguồn cung cấp kịch bản không tạo ra một vỏ mới và do đó, PID vẫn giữ nguyên.

Tóm lược

Cả việc tìm nguồn cung ứng và thực thi tập lệnh sẽ chạy các lệnh trong dòng kịch bản theo từng dòng, như thể bạn đã gõ các lệnh đó theo từng dòng một.

Sự khác biệt là:

  • Khi bạn thực thi tập lệnh bạn đang mở một trình bao mới , hãy nhập các lệnh trong trình bao mới, sao chép đầu ra trở lại trình bao hiện tại của bạn, sau đó đóng trình bao mới. Mọi thay đổi đối với môi trường sẽ chỉ có hiệu lực trong lớp vỏ mới và sẽ bị mất khi lớp vỏ mới được đóng lại.
  • Khi bạn tìm nguồn kịch bản bạn đang gõ các lệnh trong của bạn hiện tại vỏ. Mọi thay đổi đối với môi trường sẽ có hiệu lực và nằm trong vỏ hiện tại của bạn.

Sử dụng nguồn nếu bạn muốn tập lệnh thay đổi môi trường trong trình bao hiện đang chạy của bạn. sử dụng thực thi khác.


Xem thêm:


2
Một cách sử dụng nguồn là tạo ra một dạng tệp cấu hình thô sơ cho các tập lệnh của bạn. Bạn bắt đầu bằng cách đặt các biến khác nhau thành các giá trị mặc định, sau đó tìm nguồn trong một cái gì đó như myscript.conf - và tập lệnh có nguồn gốc đó có thể có các câu lệnh gán ghi đè lên bất kỳ giá trị nào bạn muốn. Vì tập lệnh có nguồn gốc không bắt đầu bằng # / bin / bash, nó không được khuyến khích thực hiện trực tiếp.
LawrenceC

Vì vậy, nguồn giống như chạy nó trong phạm vi toàn cầu và việc thực thi tạo ra một phạm vi cục bộ mới. Điều này có thể được mở rộng đến một chức năng trong một kịch bản? để thực thi một chức năng (thông thường) hoặc "nguồn" nó?
aliteralmind

2
Có sự khác biệt giữa việc sử dụng source myscript.sh. myscript.sh?
Holloway

2
Thực tế không có sự khác biệt nếu sử dụng bash. nguồn là một bí danh để chấm trong bash.
lesmana 17/03/2015

1
Tôi thích nó khi mọi người cung cấp các ví dụ phức tạp như vậy để ngay cả những người mới sử dụng Linux như tôi cũng có thể hiểu được. Cảm ơn!
Julius

21

Thực thi một tập lệnh chạy nó trong một tiến trình con riêng biệt, tức là, một thể hiện riêng biệt của shell được gọi để xử lý tập lệnh. Điều này có nghĩa là bất kỳ biến môi trường nào, v.v., được xác định trong tập lệnh không thể được cập nhật trong trình bao (hiện tại).

Tìm kiếm một tập lệnh có nghĩa là nó được phân tích cú pháp và được thực thi bởi chính trình bao hiện tại. Như thể bạn đã gõ nội dung của tập lệnh. Vì lý do này, kịch bản có nguồn gốc không cần phải được thực thi. Nhưng nó phải được thực thi nếu bạn đang thực hiện nó.

Nếu bạn có đối số vị trí trong trình bao hiện tại, chúng không thay đổi.

Vì vậy, nếu tôi có một tập tin a.shchứa:

echo a $*

và tôi làm:

$ set `date`
$ source ./a.sh

Tôi nhận được một cái gì đó như:

a Fri Dec 11 07:34:17 PST 2009

Trong khi:

$ set `date`
$ ./a.sh

đưa cho tôi:

a

Mong rằng sẽ giúp.


5
Mặc dù câu trả lời này là chính xác theo mọi cách tôi cảm thấy rất khó hiểu bởi vì nó được thể hiện bằng cách sử dụng một khái niệm khác (đặt tham số vị trí), theo tôi, thậm chí còn khó hiểu hơn sự khác biệt của việc tìm nguồn cung ứng và thực thi chính nó.
lesmana

9

tìm nguồn cung ứng về cơ bản giống như nhập từng dòng của tập lệnh tại dấu nhắc lệnh một lần ...

Thực thi bắt đầu một quy trình mới và sau đó chạy từng dòng của tập lệnh, chỉ sửa đổi môi trường hiện tại bằng những gì nó trả về.


6

Ngoài ra, việc thực thi tập lệnh theo ./myscriptyêu cầu quyền thực thi đối với tệp myscript trong khi tìm nguồn cung cấp không yêu cầu bất kỳ quyền thực thi nào. Đó là lý do tại sao chmod +x myscriptkhông bắt buộc trướcsource myscript


2
Đúng, nhưng nếu đó là một vấn đề, bạn luôn có thể chạy bash myscript.
Daniel Beck

5

Tìm nguồn cung ứng bạn nhận được tất cả các biến bổ sung được xác định trong tập lệnh.
Vì vậy, nếu bạn có cấu hình hoặc định nghĩa hàm, bạn nên nguồn và không thực thi. Thi hành độc lập với môi trường cha mẹ.


3

Nếu tôi nhớ lại chính xác, việc thực thi tập lệnh sẽ chạy tệp thực thi trong #!dòng với tệp tập lệnh dưới dạng đối số (thường bắt đầu một trình bao mới và tìm nguồn cung cấp tập lệnh vào trình bao mới một cách hiệu quả, như với #!/bin/sh);
trong khi đó, tìm nguồn cung cấp tập lệnh thực thi từng dòng trong môi trường shell hiện tại của bạn, rất hữu ích để thay đổi shell hiện tại của bạn (ví dụ: cung cấp một cách để xác định các hàm shell và xuất các biến môi trường).


2

sourcelệnh thực thi tập lệnh được cung cấp (quyền thực thi là không bắt buộc ) trong môi trường shell hiện tại , trong khi ./thực thi tập lệnh thực thi được cung cấp trong trình bao mới .

Ngoài ra, hãy kiểm tra câu trả lời này ví dụ: https://superuser.com/a/894748/432100

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.