Làm cách nào để kiểm tra xem shell có đăng nhập / tương tác / đợt không


145

Tôi nghĩ rằng tôi hiểu sự khác biệt giữa một tương tác, đăng nhập và vỏ hàng loạt. Xem các liên kết sau để được trợ giúp thêm:

Câu hỏi của tôi là, làm thế nào tôi có thể kiểm tra bằng lệnh / điều kiện nếu tôi đang ở trên một tương tác, đăng nhập hoặc vỏ hàng loạt?

Tôi đang tìm kiếm một lệnh hoặc điều kiện (trả về truehoặc false) và tôi cũng có thể đặt một câu lệnh if. Ví dụ:

if [[ condition ]]
   echo "This is a login shell"
fi

3
Vẫn còn một câu hỏi nữa: STDIN và / hoặc STDOUT có được kết nối với tty (thiết bị đầu cuối) hoặc đường ống (tệp hoặc quy trình) không? Đây là một thử nghiệm liên quan nhưng khác biệt như được mô tả trong một số ý kiến ​​dưới đây.
Mark Hudson

Câu trả lời:


162

Tôi đang giả sử một bashshell, hoặc tương tự, vì không có shell được liệt kê trong các thẻ.

Để kiểm tra xem bạn có ở trong vỏ tương tác không:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

Để kiểm tra xem bạn có ở trong vỏ đăng nhập không:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

Theo "đợt", tôi giả sử bạn có nghĩa là "không tương tác", do đó, việc kiểm tra vỏ tương tác sẽ đủ.


12
Đối với zshngười dùng, việc kiểm tra vỏ đăng nhập có thể được thực hiện với:if [[ -o login ]] ...
chb

1
Nếu bạn muốn biết liệu một "người dùng" có chạy chương trình của bạn so với "cron" hay không. [[TERM == "câm"]] && echo "Chạy trong cron.
Erik Aronesty

10
@ErikAronesty Không phải tất cả các thiết bị đầu cuối câm là phiên cron.
Chris Xuống

2
Tôi đang giả sử một vỏ bash, hoặc tương tự, vì không có vỏ được liệt kê trong các thẻ. Mạnh - Logic của tuyên bố này là thực sự đẹp! :)
Michael Le Barbier Grünewald

2
@antonio Đó là vì trích dẫn của bạn sai, $-đang được mở rộng trong trình bao hiện tại. Nếu bạn sử dụng các trích dẫn đơn xung quanh biểu thức đầy đủ, bạn sẽ nhận được kết quả chính xác:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down

33

Trong bất kỳ trình bao kiểu Bourne nào, itùy chọn cho biết liệu trình bao có tương tác hay không:

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

Không có cách di động và hoàn toàn đáng tin cậy để kiểm tra vỏ đăng nhập. Ksh và zsh thêm lvào $-. Bash đặt login_shelltùy chọn mà bạn có thể truy vấn shopt -q login_shell. Có thể kiểm tra xem có $0bắt đầu bằng a -: shell thường biết rằng chúng là shell đăng nhập hay không bởi vì người gọi đã thêm -tiền tố vào đối số 0 (thông thường là tên hoặc đường dẫn của tệp thực thi). Điều này không phát hiện ra các cách cụ thể của shell để gọi shell đăng nhập (ví dụ ash -l).


(...) Bởi vì người gọi - Tôi nghĩ rằng có một cái gì đó bị thiếu trong đoạn này.
Piotr Dobrogost

Sẽ thật lý tưởng nếu $0luôn luôn bắt đầu với -bất kể nó được bắt đầu như thế nào. Nhưng có ít nhất một ngoại lệ: Điều này không phải lúc nào cũng đúng với bash ngay cả khi nó được coi là một vỏ đăng nhập. Hãy thử nó trong hộp của bạn: gọi bash --login, sau đó $0vẫn đọc bash.
Wi Girls Purwanto

@WiINAPurwanto Tôi không chắc là tôi hiểu bình luận của bạn. Đó không phải là những gì tôi đã viết trong câu cuối cùng của tôi?
Gilles

@Gilles: Bạn đúng rồi. Xin lỗi tôi đã bỏ lỡ câu cuối cùng của bạn.
Wi Girls Purwanto

24

vỏ cá

Đây là câu trả lời fishtrong trường hợp bất kỳ người dùng nào khác vấp phải trang này.

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Tài liệu về cá: khởi tạo


1
-1 cho việc biên tập không cần thiết.
Nick Bastin

6
Nếu bất cứ ai thắc mắc về nhận xét của @ NickBastin, anh ta đã có một điểm công bằng nên tôi đã chỉnh sửa. Số lượng ban đầu của sự ngu ngốc đã được cắt giảm một nửa.
ohspite

18

csh / tcsh

Cho cshtcshtôi có những điều sau đây trong .cshrctập tin của tôi :

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

Cụ thể cho tcsh, biến loginshđược đặt cho shell đăng nhập:

if($?loginsh) then              # A login shell..
    ...
endif

( tcshcũng có một biến shlvlđược đặt thành số vỏ được lồng, trong đó vỏ đăng nhập có giá trị là 1.)


2
PS1không hoạt động để kiểm tra vỏ tương tác. Nó hầu như luôn được đặt trong một tương tác, nhưng bạn có thể bỏ đặt nó. Nó rất thường xuyên đặt trong một vỏ noninteractive, bởi vì tàu nhiều hệ thống với export PStrong /etc/profile.
Gilles

@Gilles Cảm ơn bạn đã chỉnh sửa và chỉnh sửa
Andrew Stein

17

Một cách khác là kiểm tra kết quả của tty

if [ "`tty`" != "not a tty" ]; then

10
... Hoặc sử dụng [ -t 0 ]để kiểm tra xem STDIN có phải là tty không. Bạn cũng có thể sử dụng 1 (STDOUT) hoặc 2 (STDERR) tùy theo nhu cầu của bạn.
derobert

@derobert - cảm ơn vì đã cho tôi xem một cái gì đó mới
Adrian Cornish

10
Đây là một thử nghiệm khác nhau. Có thể có một lớp vỏ không tương tác với đầu vào là một thiết bị đầu cuối (bất cứ khi nào bạn chạy một tập lệnh trong một thiết bị đầu cuối!), Và có thể (mặc dù rất hiếm) để có một vỏ tương tác lấy đầu vào không phải từ một thiết bị đầu cuối.
Gilles

@Gilles nếu lớp vỏ tương tác và đóng lại để lại một đứa trẻ disownvà còn sống, ttyhoạt động tốt nhất để biết nó không tương tác nữa, trong khi $-không thay đổi; Tôi vẫn còn hoang mang về cách tiếp cận tốt nhất là gì.
Sức mạnh Bảo Bình

5
@AquariusPower Sau đó, những gì bạn muốn kiểm tra không dành cho hệ vỏ tương tác, mà là liệu đầu vào tiêu chuẩn có phải là thiết bị đầu cuối hay không. Sử dụng [ -t 0 ]. PS Trong nhận xét trước đây của tôi, tôi đã viết rằng, đó là một mối tương quan mạnh mẽ - Tôi đã quên đi biệt với trường hợp cực kỳ phổ biến của một kịch bản được bắt đầu bằng #!/bin/shhoặc giống như, không tương tác nhưng có thể được kết nối với một thiết bị đầu cuối.
Gilles

8

UNIX / Linux có một lệnh để kiểm tra nếu bạn đang ở trên một thiết bị đầu cuối.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
Điều này cũng hoạt động trong dash.
Ken Sharp

7

Bạn có thể kiểm tra xem stdin có phải là thiết bị đầu cuối không:

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi

3

Để kiểm tra xem tập lệnh có chạy trong trình bao tương tác hay không tương tác hay không, tôi kiểm tra tập lệnh của mình xem có dấu nhắc được lưu trong $PS1biến không:

if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ]   # On Bash 4.2+ ...
then
  # non-interactive
  ...
else
  # interactive
  ...
fi

Điều này tôi học được ở đây: https://www.tldp.org/LDP/abs/html/intandnonint.html


1

ikhông phải là lựa chọn chính xác để tìm kiếm. -ilà buộc một vỏ không tương tác khác trở thành tương tác. Tùy chọn tự động kích hoạt chính xác là -s, nhưng không may Bash không xử lý chính xác điều này.

Bạn cần kiểm tra xem $-có chứa s(cái này được cấp để tự động kích hoạt hay không) hay nó chứa i(cái này không được cấp để tự động kích hoạt mà chỉ chính thức được ghép với -itùy chọn dòng lệnh của shell).


1
ssẽ là nếu shell đọc các lệnh từ stdin, không phải là nó có tương tác hay không. Một shell tương tác không nhất thiết phải đọc các lệnh từ stdin (thử zsh -i < /dev/null, mặc dù zsh dường như là ngoại lệ ở đây). Và một shell có thể đang đọc các lệnh từ stdin và không tương tác (như sh < filehoặc echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas

2
Điều tôi muốn chỉ ra là Bourne Shell ban đầu không có 'i' bằng $ -, ngay cả khi nó được dự định tương tác.
hỏi

OK, nhưng trên U & L, "shell" có xu hướng đề cập đến các shell hiện đại . Vỏ Bourne thường được coi là một bản sao và biến thể của riêng bạn không đủ chính thống để mong mọi người biết bạn đang nói về điều gì trừ khi bạn nói rõ. Câu hỏi đề cập đến [[...]]ngụ ý ksh / bash / zsh. Bạn đã có một điểm như một lịch sử lưu ý rằng kiểm tra cho itại $-sẽ không làm việc trong vỏ Bourne. Nhưng sau đó kiểm tra ssẽ không làm việc ở đó một cách đáng tin cậy. Bạn cũng muốn kiểm tra [ -t 0 ]hoặc i; thậm chí sau đó sẽ bị lừa trong các trường hợp góc nhưecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas

Solaris cho đến Solaris 10 đi kèm với Bourne Shell ban đầu và thậm chí cả bệ bao gồm cả aprox. 10 lỗi được biết là nằm trong shell kể từ SVr4. Vì vậy, việc thêm một gợi ý về Bourne Shell không phải là chiếc mũ lệch lạc như bạn có thể tin. Mặt khác, zsh không đủ tương thích, ví dụ như không thành công khi bạn cố chạy "configure" với zsh, vì vậy hãy cẩn thận khi thiết lập / bin / sh để trỏ đến zsh. BTW: Bourne Shell của tôi đặt -i theo mặc định trong trường hợp nó quyết định tương tác.
schily

3
Tôi nhận thấy POSIX dường như không yêu cầu $ - chứa i (mà dường như yêu cầu s), tôi sẽ đặt câu hỏi trên ML nhóm austin.
Stéphane Chazelas
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.