Câu hỏi Sự khác biệt giữa việc thực hiện một kịch bản Bash so với tìm nguồn cung ứng nó là gì?


Sự khác nhau giữa việc thực hiện một kịch bản lệnh Bash như A và tìm kiếm một kịch bản Bash như B là gì?

A
> ./myscript

B
> source myscript

215
2017-12-11 15:24


gốc




Các câu trả lời:


Câu trả lời ngắn: tìm nguồn cung ứng sẽ chạy các lệnh trong quá trình shell hiện tại. thực thi sẽ chạy các lệnh trong một tiến trình shell mới. vẫn còn bối rối? thì hãy tiếp tục đọc câu trả lời dài.

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

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

myscript

Thi hành  myscript nếu tệp có thể thực thi được và nằm trong một số thư mục trong $PATH.

source myscript

Nguồn  myscript. tệp không cần phải thực thi được nhưng phải là tệp shell hợp lệ. Tệp có thể nằm trong thư mục hiện tại hoặc trong một thư mục trong $PATH.

. myscript

Nguồn  myscript. Cú pháp này là được xác định bởi POSIX. Bash được định nghĩa source làm bí danh cho lệnh dấu chấm.

Trình diễn:

Xem xét myscript.sh vớ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 ta thực thi kịch bản trước, chúng ta kiểm tra môi trường hiện tại:

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

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

Bây giờ chúng ta thi hành 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 FOO chưa được đặt và thư mục làm việc không thay đổi.

Đầu ra kịch bản cho thấy rõ ràng rằng biến đã được thiết lập và thư mục đã được thay đổi. Việc kiểm tra sau đó cho thấy rằng biến không được thiết lập 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 Mới vỏ. Các hiện hành vỏ sinh ra một Mới để chạy tập lệnh. Tập lệnh đang chạy trong trình bao mới và tất cả các thay đổi đối với môi trường đều có hiệu lực trong trình bao mới. Sau khi kịch bản được thực hiện vỏ mới bị phá hủy. Tất cả các thay đổi đối với môi trường trong shell mới đều bị hủy với shell mới. Chỉ văn bản đầu ra được in trong trình bao hiện tại.

Bây giờ chúng ta 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 thiết lập và thư mục làm việc đã thay đổi.

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

Lưu ý rằng trong ví dụ đơn giản này, đầu ra của việc thực hiện giống như tìm nguồn cung ứng kịch bản 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 tập lệnh sau pid.sh:

#!/bin/sh
echo $$

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

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

$ echo $$
25009

Nguồn tập lệnh:

$ source pid.sh
25009

Thực hiện kịch bản, 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 tìm nguồn cung ứng kịch bản chạy trong cùng một quá trình trong khi thực thi kịch bản tạo ra một quá trình mới mọi lúc. Quy trình mới đó là Mới shell được tạo để thực thi kịch bản. Tìm nguồn cung ứng 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ả hai tìm nguồn cung ứng và thực thi kịch bản sẽ chạy các lệnh trong dòng kịch bản theo dòng, như thể bạn đã gõ các lệnh đó theo từng dòng.

Sự khác biệt là:

  • Khi bạn thi hành kịch bản bạn đang mở Mới vỏ, gõ lệnh trong trình bao mới, sao chép đầu ra trở lại vỏ hiện tại của bạn, sau đó đóng vỏ mới. Mọi thay đổi đối với môi trường sẽ chỉ có hiệu lực trong shell mới và sẽ bị mất khi shell mới được đóng lại.
  • Khi bạn nguồn kịch bản bạn đang gõ các lệnh trong hiện hành vỏ. Mọi thay đổi đối với môi trường sẽ có hiệu lực và ở lại trong trình bao 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 vỏ đang chạy của bạn. sử dụng cách khác.


Xem thêm:


279
2017-08-16 21:58



Một sử dụng tìm nguồn cung ứng là tạo ra một hình thức thô sơ của tập tin cấu hình cho các kịch bản của bạn. Bạn bắt đầu bằng cách thiết lập các biến khác nhau thành các giá trị mặc định, và sau đó nguồn trong một cái gì đó như myscript.conf - và kịch bản có nguồn gốc đó có thể có các câu lệnh gán ghi đè lên bất cứ 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ên không nên thực thi nó trực tiếp. - LawrenceC
Vì vậy, nguồn là loại giống như chạy nó trong một phạm vi toàn cầu, và thực hiện tạo ra một phạm vi địa phương 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 hiện một chức năng (thông thường) hoặc "nguồn" nó? - aliteralmind
gọi hàm shell thường hoạt động giống như tìm nguồn cung ứng. gọi một hàm shell bên trong một subshell hoạt động giống như thực thi. - lesmana
Có sự khác biệt nào giữa việc sử dụng source myscript.sh và . myscript.sh? - Holloway
thực tế không có sự khác biệt nếu sử dụng bash. nguồn là bí danh để dấu chấm trong bash. - lesmana


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 của trình bao đượ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, được định nghĩa trong tập lệnh không thể được cập nhật trong shell mẹ (current).

Tìm kiếm một kịch bản có nghĩa là nó được phân tích cú pháp và được thực thi bởi chính shell hiện tại. Nó giống như bạn đã gõ nội dung của kịch bản. Vì lý do này, kịch bản có nguồn gốc không cần thực thi. Nhưng nó phải được thực thi nếu bạn đang thực hiện nó tất nhiê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.sh chứ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

Hy vọng rằng sẽ giúp.


21
2017-12-11 15:35



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


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

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


5
2017-12-11 15:27





Tìm nguồn cung ứng bạn nhận được tất cả các biến phụ đượ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 chức năng, bạn nên nguồn và không thực thi. Việc thi hành độc lập với môi trường của cha mẹ.


4
2017-12-11 15:25





Ngoài ra ở trên, thực thi kịch bản như ./myscript yêu cầu quyền thực thi cho tệp myscript trong khi tìm nguồn cung ứng không yêu cầu bất kỳ quyền thực thi nào. Đó là lý do tại sao chmod +x myscript không bắt buộc trước source myscript


4
2018-02-23 07:27



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


Nếu tôi nhớ chính xác, thực thi tập lệnh sẽ chạy tệp thực thi trong #! phù hợp với tệp kịch bản như một đối số (thường bắt đầu một trình bao mới và tìm nguồn gốc kịch bản một cách hiệu quả vào trình bao mới, như với #!/bin/sh);
trong khi, tìm nguồn cung ứng kịch bản thực thi mỗi dòng trong môi trường shell hiện tại của bạn, điều này 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 để định nghĩa các hàm shell và các biến môi trường xuất khẩu).


3
2017-12-11 15:27





source lệnh thực thi kịch bản được cung cấp (quyền thực thi là không bắt buộc) bên trong hiện hành môi trường vỏ, trong khi ./ thực hiện cung cấp thực thi kịch bản trong một Mới vỏ.

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


2
2018-03-27 14:04