Bất kỳ cách nào để thoát tập lệnh bash, nhưng không thoát khỏi thiết bị đầu cuối


183

Khi tôi sử dụng exitlệnh trong tập lệnh shell, tập lệnh sẽ chấm dứt thiết bị đầu cuối (lời nhắc). Có cách nào để chấm dứt một tập lệnh và sau đó ở lại trong thiết bị đầu cuối?

Kịch bản của tôi run.shdự kiến ​​sẽ được thực thi bằng cách trực tiếp có nguồn gốc, hoặc có nguồn gốc từ một kịch bản khác.

EDIT: Để cụ thể hơn, có hai kịch bản run2.shnhư

...
. run.sh
echo "place A"
...

run.shnhư

...
exit
...

Khi tôi chạy nó . run2.shvà nếu nó chạm vào exitdòng mã run.sh, tôi muốn nó dừng lại ở thiết bị đầu cuối và ở lại đó. Nhưng sử dụng exit, toàn bộ thiết bị đầu cuối bị đóng cửa.

PS: Tôi đã thử sử dụng return, nhưng echocodeline vẫn sẽ được thực thi ....


5
Tôi thực sự, thực sự, thực sự phải hỏi: tại sao bạn sử dụng lối ra trong một tập lệnh có nguồn gốc?
Ignacio Vazquez-Abrams

3
lệnh exit không nên chấm dứt phiên cuối / đăng nhập của bạn. nếu bạn sử dụng exit 0để chấm dứt tập lệnh sau khi thành công, khi bạn chạy tập lệnh cũ: ./test.shbạn sẽ thấy đầu ra nhưng bảng điều khiển của bạn sẽ vẫn mở.
Ben Ashton

Bạn có thể sử dụng shelllệnh, thực tế sẽ mở một thiết bị đầu cuối shell. Kinh nghiệm của riêng tôi tuy nhiên điều này không xảy ra với exit. Thoát thường trả lại quyền điều khiển cho tập lệnh cha.
Willem Van Onsem

Câu trả lời:


258

"Vấn đề" thực sự là bạn đang tìm nguồn cung ứng và không thực thi tập lệnh. Khi bạn lấy một tệp, nội dung của nó sẽ được thực thi trong trình bao hiện tại, thay vì sinh ra một lớp con. Vì vậy, tất cả mọi thứ, bao gồm cả lối ra, sẽ ảnh hưởng đến vỏ hiện tại.

Thay vì sử dụng exit, bạn sẽ muốn sử dụng return.


2
Đây là một lời giải thích khác mà tôi thấy hữu ích: Askubfox.com/a/53179/148337
3cheesewheel 26/07/13

Mặc dù đúng, đây không phải là một câu trả lời tuyệt vời. Nó bỏ qua rằng tập lệnh gọi có thể khai báo các biến hoặc hàm được gọi là tập lệnh cần truy cập. Tốt hơn để giải thích làm thế nào để thiết lập mã trả về và sau đó xử lý nó trong runs.sh@ruakh có câu trả lời tốt hơn cho câu hỏi này.
MikeSchinkel

5
Điều gì nếu chức năng là một cuộc gọi lồng nhau? tức là a gọi b, b gọi c, c muốn thoát ngay a và b.
Michael

Nguồn gần giống như sao chép dán. Tốt hơn là sử dụng sh <script>hoặc bash <script>nếu một người muốn chạy một kịch bản và chấm dứt tại một số điểm
peterchaula

42

Đúng; bạn có thể sử dụng returnthay vì exit. Mục đích chính của nó là trả về từ hàm shell, nhưng nếu bạn sử dụng nó trong sourcetập lệnh -d, nó sẽ trả về từ tập lệnh đó.

Như §4.1 "Bourne Shell Buildins" của Bash Reference Guide đặt nó:

     return [n]

Gây ra một hàm shell để thoát với giá trị trả về n . Nếu n không được cung cấp, giá trị trả về là trạng thái thoát của lệnh cuối cùng được thực thi trong hàm. Điều này cũng có thể được sử dụng để chấm dứt thực thi tập lệnh đang được thực thi với .(hoặc source) dựng sẵn, trả về n hoặc trạng thái thoát của lệnh cuối cùng được thực thi trong tập lệnh dưới dạng trạng thái thoát của tập lệnh. Bất kỳ lệnh nào liên quan đến RETURNbẫy đều được thực thi trước khi thực thi lại sau hàm hoặc tập lệnh. Trạng thái trả về là khác không nếu returnđược sử dụng bên ngoài hàm và không trong khi thực thi tập lệnh bằng .hoặc source.


3
returnCHỈ có thể được sử dụng từ một chức năng. Nếu bạn sử dụng returnvà thực thi nó như một tập lệnh shell (ví dụ sh run.sh), bash sẽ báo lỗi - return: can only return 'từ một hàm hoặc tập lệnh có nguồn gốc `
Tzunghsing David Wong

@TzungsingDavidWong: Bạn có nhận ra rằng phần lớn câu trả lời này là một trích dẫn từ tài liệu tham khảo chính thức? Và rằng thông báo lỗi bạn trích dẫn có đồng ý với câu trả lời này thay vì với yêu cầu của bạn không?
ruakh

Tôi không đồng ý với bạn. Tôi chỉ đơn giản muốn chỉ ra rằng returnsẽ không hoạt động nếu tập lệnh được chạy dưới dạng tập lệnh shell và không được thực thi bởi. (hoặc source). BTW, tôi có thể tìm tài liệu về source -dđâu?
Tzunghsing David Wong

9

Thay vì chạy tập lệnh bằng cách sử dụng . run2.sh, bạn có thể chạy tập lệnh bằng sh run2.shhoặcbash run2.sh

Một shell con mới sẽ được bắt đầu, để chạy script sau đó, nó sẽ được đóng ở cuối script để lại shell khác được mở.


Nếu vậy, tại sao tham số thứ hai sh "." run2.sh?
CHAN

@ H0WARD Bạn nói đúng Tôi quên xóa dấu chấm. Tôi đã chỉnh sửa câu trả lời ngay bây giờ.
Viorel Mirea 4/11/2015

1
OP tuyên bố rõ ràng nguồn là một yêu cầu.
Jonathan Neufeld

4

Bạn có thể thêm một lệnh thoát bổ sung sau câu lệnh return / lệnh để nó hoạt động cho cả hai, thực thi tập lệnh từ dòng lệnh và tìm nguồn từ thiết bị đầu cuối.

Mã thoát ví dụ trong tập lệnh:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

Dòng có exitlệnh sẽ không được gọi khi bạn lấy tập lệnh sau returnlệnh.

Khi bạn thực thi tập lệnh, returnlệnh sẽ báo lỗi. Vì vậy, chúng tôi ngăn chặn thông báo lỗi bằng cách chuyển tiếp nó đến /dev/null.


3

Trên thực tế, tôi nghĩ rằng bạn có thể bị nhầm lẫn bởi cách bạn thay đổi run a script.

Nếu bạn sử dụng shđể chạy tập lệnh, giả sử sh ./run2.sh, ngay cả khi tập lệnh được nhúng kết thúc exit, cửa sổ đầu cuối của bạn sẽ vẫn còn.

Tuy nhiên, nếu bạn sử dụng .hoặc source, cửa sổ đầu cuối của bạn cũng sẽ thoát / đóng khi đăng ký kết thúc.

để biết thêm chi tiết, vui lòng tham khảo Sự khác biệt giữa việc sử dụng shsource?


2

Điều này giống như bạn đặt một hàm chạy bên trong tập lệnh run2.sh. Bạn sử dụng mã thoát bên trong chạy trong khi nguồn tệp run2.sh của bạn trong bash tty. Nếu chức năng cung cấp cho chức năng chạy, nó có khả năng thoát khỏi tập lệnh của bạn và cung cấp cho run2.sh sức mạnh của nó để thoát khỏi bộ kết thúc. Sau đó, vì chức năng chạy có sức mạnh để thoát khỏi teminator của bạn.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

Dù sao, tôi đồng ý với Kaz đó là một vấn đề thiết kế.


Không rõ từ văn bản câu trả lời này cố gắng làm gì, nhưng chắc chắn nó không giải quyết được câu hỏi trong tầm tay.
Luís de Sousa

2

Tôi đã có cùng một vấn đề và từ các câu trả lời ở trên và từ những gì tôi hiểu những gì làm việc cho tôi cuối cùng là:

  1. Có một dòng shebang gọi kịch bản dự định, ví dụ,

    #!/bin/bashsử dụng bashđể thực thi tập lệnh

Tôi có kịch bản với cả hai loại shebang. Do đó, việc sử dụng shhoặc .không đáng tin cậy, vì nó dẫn đến việc thực thi sai (như khi tập lệnh bảo lãnh chạy không hoàn chỉnh)

Câu trả lời do đó, là

    • Hãy chắc chắn rằng tập lệnh có một shebang, để không có nghi ngờ gì về trình xử lý dự định của nó.
    • chmod tệp .sh để nó có thể được thực thi. (chmod +x file.sh)
    • Gọi nó trực tiếp mà không có bất kỳ shhoặc.

      (./myscript.sh)

Hy vọng điều này sẽ giúp ai đó với câu hỏi hoặc vấn đề tương tự.


1

Tôi nghĩ rằng điều này xảy ra bởi vì bạn đang chạy nó trên chế độ nguồn với dấu chấm

. myscript.sh

Bạn nên chạy nó trong một subshell:

/full/path/to/script/myscript.sh

'nguồn' http://ss64.com/bash/source.html


Bạn không cần đường dẫn đầy đủ đến kịch bản nếu . myscript.shhoạt động. Nhiều nhất, bạn có thể cần ./myscript.sh.
Álvaro González

1

Đó là chính xác rằng các tập lệnh có nguồn gốc so với thực thi sử dụng returnso với exitđể giữ cho cùng một phiên mở, như những người khác đã lưu ý.

Đây là một mẹo có liên quan, nếu bạn muốn một tập lệnh mở phiên, bất kể nó có nguồn gốc hay không.

Ví dụ sau có thể được chạy trực tiếp như foo.shhoặc có nguồn gốc như . foo.sh/ source foo.sh. Dù bằng cách nào, nó sẽ giữ cho phiên mở sau khi "thoát". Các $@chuỗi được truyền để các chức năng có quyền truy cập vào đối số kịch bản bên ngoài của.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Kết quả đầu cuối:

$ foo.sh
$ Bạn có muốn XYZ không? (Y / N): n
$. foo.sh
$ Bạn có muốn XYZ không? (Y / N): n
$ |
(cửa sổ đầu cuối vẫn mở và chấp nhận đầu vào bổ sung)

Điều này có thể hữu ích để nhanh chóng kiểm tra các thay đổi tập lệnh trong một thiết bị đầu cuối trong khi vẫn giữ một loạt mã phế liệu bên dưới chính exit/ returntrong khi bạn làm việc. Nó cũng có thể làm cho mã dễ di chuyển hơn theo nghĩa (nếu bạn có hàng tấn tập lệnh có thể được gọi hoặc không được gọi theo các cách khác nhau), mặc dù nó ít rắc rối hơn khi chỉ sử dụng returnexitkhi thích hợp.


0

nếu trình giả lập thiết bị đầu cuối của bạn không có, -holdbạn có thể vệ sinh tập lệnh có nguồn gốc và giữ thiết bị đầu cuối bằng:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

nếu không bạn có thể sử dụng $TERM -hold -e script


0

Cũng đảm bảo trả lại với giá trị trả lại dự kiến. Khác nếu bạn sử dụng exit khi bạn gặp phải một lối thoát thì nó sẽ thoát khỏi shell cơ sở của bạn vì nguồn không tạo ra một quy trình (ví dụ) khác.


0

Để viết một kịch bản đó là an toàn để được chạy như hoặc là một kịch bản shell hoặc được khai thác như một file rc, kịch bản có thể kiểm tra và so sánh $0$BASH_SOURCEvà xác định xem exitcó thể được sử dụng một cách an toàn.

Đây là một đoạn mã ngắn cho điều đó

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."

-1

1) thoát 0 sẽ ra khỏi tập lệnh nếu thành công.

2) thoát 1 sẽ ra khỏi tập lệnh nếu đó là một thất bại.

Bạn có thể thử hai điều trên dựa trên req của bạn.

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.