Sự khác biệt giữa nguồn của x x, hung. x và và.


11

Tôi có một nguồn bash run.shnhư sau,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

Khi tôi thực hiện nó theo hai cách, có những hành vi khác nhau. Cách đầu tiên là,

source run.sh

Nó sẽ đóng thiết bị đầu cuối sau khi thực hiện. Cách thứ hai là,

./run.sh

điều này chỉ đơn giản là kết thúc việc chạy tập lệnh và ở trên thiết bị đầu cuối. Tôi đang hỏi nếu có một lệnh để thoát khỏi tập lệnh bash cho cả hai source run.sh./run.shthực thi. Tôi cũng đã thử return, nó không hoạt động tốt khi ./run.shthực hiện.

Tổng quát hơn, tôi quan tâm đến lý do tại sao điều này xảy ra và sự khác biệt giữa việc sử dụng "nguồn" và "." để thực thi kịch bản?

Câu trả lời:


16

Trước khi trả lời, tôi nghĩ rằng một số làm rõ là cần thiết. Hãy phân tích ba dòng sau:

source run.sh
. run.sh
./run.sh

Hai dòng đầu tiên giống hệt nhau: .thực tế là một bí danh cho source. Điều gì sourceđang thực hiện kịch bản shell trong bối cảnh hiện tại, do đó một lệnh gọi exitsẽ thoát khỏi shell.

Dòng thứ ba (là dòng khiến bạn bối rối) tuy nhiên không liên quan gì đến các dòng khác. ./run.shchỉ là một đường dẫn và giống như (ví dụ) /home/user/run.shhoặc /usr/bin/something. Luôn nhớ rằng các lệnh trong shell được phân tách bằng khoảng trắng. Vì vậy, trong trường hợp này, lệnh không phải ., nhưng là ./run.sh: điều này có nghĩa là một lớp vỏ phụ sẽ được thực thi và nó exitsẽ có hiệu lực chỉ với lớp vỏ phụ.


5

Ba cách:

Bạn có thể đặt tập lệnh trong một hàm và chỉ sử dụng return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Bạn có thể kiểm tra xem tập lệnh có được cung cấp bởi trình bao tương tác hay không.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Bạn có thể cố gắng quay lại và nếu thất bại, hãy thoát.

return 1 2>/dev/null || exit 1

Bất kỳ gợi ý như làm thế nào các câu thần chú $- = *i* hoạt động?
deadbeef404

@ deadbeef404 Tham số đặc biệt -giữ các cờ tùy chọn hiện đang hoạt động. Kiểm tra kiểm tra nếu -icờ đang hoạt động. Xem gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha

1

Hãy nghĩ về lệnh 'nguồn' như trong câu lệnh 'bao gồm'. Nó lấy nội dung của đối số và chạy nó như thể nó được chạy trực tiếp. Trong trường hợp này, lệnh của bạn là 'nguồn' với đối số 'run.sh' và run.sh được thực thi chính xác như thể bạn đã nhập nội dung của run.sh vào dòng lệnh của mình.

Khi bạn chạy './run.sh', './run.sh' là lệnh của bạn và nó không có đối số. Vì tệp này là văn bản thuần túy và không phải là nhị phân, trình bao của bạn tìm kiếm một trình thông dịch tại shebang ('#!' Trên dòng đầu tiên) và tìm thấy '/ bin / bash'. Vì vậy, shell của bạn sau đó bắt đầu một phiên bản bash mới và nội dung của run.sh được chạy bên trong thể hiện mới này.

Trong trường hợp đầu tiên, khi bash đạt đến lệnh 'exit', nó được thực thi chính xác như thể bạn đã gõ nó vào dòng lệnh. Trong các trường hợp thứ hai, nó được thực thi trong quá trình bash shell của bạn bắt đầu, do đó chỉ có trường hợp bash này nhận được lệnh 'exit'.

Khi bạn nhập một dòng vào bash, bất cứ điều gì trước dấu cách đầu tiên được coi là một lệnh và bất cứ điều gì tiếp theo đều được coi là đối số. Lệnh '.' là một bí danh của 'nguồn'. Khi bạn chạy '. chạy.sh 'cái'. ' là một lệnh riêng của nó vì nó được phân tách khỏi các đối số của nó bằng một khoảng trắng. Khi bạn chạy './run.sh', lệnh của bạn là './run.sh' và '.' là một phần của đường dẫn tương đối đến run.sh với '.' đại diện cho thư mục hiện tại của bạn.


Nếu bạn là một lập trình viên C / C ++ muốn cải thiện kịch bản shell / bash thì đây là câu trả lời hoàn hảo.
Justin
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.