Câu trả lời:
Đây là kiểm tra xem vỏ có tương tác hay không. Trong trường hợp này, chỉ tìm nguồn cung cấp ~/.bash_profile
tệp nếu shell tương tác.
Xem "Đây có phải là Shell tương tác?" trong hướng dẫn bash, trong đó trích dẫn thành ngữ cụ thể đó. (Nó cũng khuyên bạn nên kiểm tra xem shell có tương tác hay không bằng cách kiểm tra xem $-
biến đặc biệt có chứa i
ký tự hay không, đây là cách tiếp cận tốt hơn cho vấn đề này.)
bash
hủy cài đặt PS1 khi không tương tác (lỗi chính tả trong nhận xét trước của bạn) là một lỗi IMO, PS1 không phải là một biến cụ thể của bash, nó không có doanh nghiệp nào làm phiền nó. Đây là lớp vỏ duy nhất thực hiện điều đó (mặc dù yash
cũng đặt PS1
thành giá trị mặc định ngay cả khi không tương tác).
[[ $- = *i* ]] && source ~/.bash_profile
).
[ -n "${PS1}" ]
, nhưng tôi vẫn cập nhật câu trả lời của mình để làm nổi bật rằng hướng dẫn bash cũng gợi ý / khuyên bạn nên kiểm tra $-
để xác định xem vỏ có tương tác hay không, tôi hy vọng bạn thấy điều đó giúp cải thiện câu trả lời. Chúc mừng!
Đây là một cách rộng rãi để kiểm tra xem vỏ có tương tác hay không. Coi chừng nó chỉ hoạt động trong bash, nó không hoạt động với các shell khác. Vì vậy, nó ổn (nếu ngớ ngẩn) cho .bashrc
, nhưng nó sẽ không hoạt động .profile
(được đọc bởi sh, và bash chỉ là một trong những triển khai có thể có của sh, và không phải là cách phổ biến nhất).
Một shell tương tác đặt biến shellPS1
thành chuỗi dấu nhắc mặc định. Vì vậy, nếu lớp vỏ tương tác, PS1
được đặt (trừ khi người dùng .bashrc
đã gỡ bỏ nó, điều này chưa thể xảy ra ở đầu .bashrc
và bạn có thể coi đó là một việc ngớ ngẩn dù sao đi nữa).
Điều ngược lại là đúng trong bash: các trường hợp không tương tác của bash unset PS1
khi chúng bắt đầu. Lưu ý rằng hành vi này là cụ thể đối với bash và được cho là một lỗi (tại sao nó bash -c '… do stuff with $var…'
không hoạt động khi var
có PS1
?). Nhưng tất cả các phiên bản bash lên đến và bao gồm 4.4 (phiên bản mới nhất khi tôi viết) làm điều này.
Nhiều hệ thống xuất khẩu PS1
ra môi trường. Đó là một ý tưởng tồi, bởi vì nhiều shell khác nhau sử dụng PS1
nhưng với một cú pháp khác nhau (ví dụ: thoát nhanh chóng của bash hoàn toàn khác với thoát nhanh chóng của zsh ). Nhưng nó đủ phổ biến đến mức trong thực tế, thấy rằng nó PS1
được đặt không phải là một chỉ số đáng tin cậy cho thấy vỏ có tính tương tác. Vỏ có thể được thừa hưởng PS1
từ môi trường.
.bashrc
là tập tin bash đọc khi khởi động khi nó tương tác. Một thực tế ít được biết đến là bash cũng đọc .bashrc
là một vỏ đăng nhập và các heuristic của bash kết luận rằng đây là một phiên từ xa (bash kiểm tra xem cha mẹ của nó là rshd
hay sshd
). Trong trường hợp thứ hai này, không chắc là nó PS1
sẽ được đặt trong môi trường, vì chưa có tệp chấm nào chạy được.
Tuy nhiên, cách mã sử dụng thông tin này là phản tác dụng.
.bash_profile
trong shell đó. Nhưng .bash_profile
là một kịch bản thời gian đăng nhập. Nó có thể chạy một số chương trình chỉ được chạy một lần mỗi phiên. Nó có thể ghi đè một số biến môi trường mà người dùng đã cố tình đặt thành một giá trị khác trước khi chạy shell đó. Chạy .bash_profile
trong một vỏ không đăng nhập là gây rối..bash_profile
. Nhưng đây là trường hợp tải .bash_profile
có thể hữu ích, vì vỏ đăng nhập không tương tác không tự động tải /etc/profile
và ~/.profile
.Tôi nghĩ lý do mọi người làm điều này là vì người dùng đăng nhập thông qua GUI (một trường hợp rất phổ biến) và những người đặt cài đặt biến môi trường của họ .bash_profile
thay vì .profile
. Hầu hết các cơ chế đăng nhập GUI đều gọi .profile
nhưng không .bash_profile
(đọc .bash_profile
sẽ yêu cầu chạy bash như một phần của phiên khởi động, thay vì sh). Với cấu hình này, khi người dùng mở một thiết bị đầu cuối, họ sẽ nhận được các biến môi trường. Tuy nhiên, người dùng sẽ không nhận được các biến môi trường của họ trong các ứng dụng GUI, đây là một nguồn gây nhầm lẫn rất phổ biến. Giải pháp ở đây là sử dụng .profile
thay vì .bash_profile
đặt các biến môi trường. Thêm một cầu nối giữa .bashrc
và .bash_profile
tạo ra nhiều vấn đề hơn nó giải quyết.
Có một cách đơn giản, di động để kiểm tra xem trình bao hiện tại có tương tác hay không: kiểm tra xem tùy chọn -i
có được bật hay không.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
Điều này rất hữu ích .bashrc
khi chỉ đọc .profile
nếu shell không tương tác - tức là ngược lại với những gì mã làm! Đọc .profile
nếu bash là vỏ đăng nhập (không tương tác) và không đọc nó nếu đó là vỏ tương tác.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
[[ -o interactive ]]
(ksh, bash, zsh) hoặc case $- in (*i*) ...; esac
(POSIX)
PS1
nếu không chạy tương tác. Thật dễ dàng để kiểm tra: PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
sẽ không in bất cứ thứ gì, trong khi PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
in giá trị của $PS1
tập hợp trong các tệp khởi động bash của bạn (nó sẽ không in chuỗi "cuckoo").
$-
có chứa i
vỏ tương tác.
[ -n "${PS1}" ]
sai là đi quá xa, sau tất cả, nó chỉ bị hỏng khi ai đó đang xuất khẩu PS1 (mà trong câu trả lời của bạn, bạn nói đó là một ý tưởng tồi và thậm chí đi vào lý do tại sao) và điều đó không ảnh hưởng bash anyways (vì nó hủy cài đặt PS1 và PS2 nếu shell không tương tác.) Có thể sử dụng một từ như "không khuyến khích" hoặc nói về "giới hạn" của phương pháp này sẽ tốt hơn. Tôi không nghĩ rằng nó "sai" hoàn toàn. Nếu có gì sai khi xuất PS1, đó là điều chắc chắn! Dù sao, cảm ơn vì đã đi vào chi tiết này.
Có vẻ như khái niệm kỳ lạ này là kết quả từ thực tế bash
không bắt đầu như một bản sao vỏ POSIX mà là một Bourne Shell
bản sao.
Do đó, hành vi tương tác POSIX ( $ENV
được gọi là shell tương tác) đã được thêm vào sau đó bash
và không được biết đến rộng rãi.
Có một vỏ cho phép hành vi tương tự. Đây là csh
và csh tài trợ $prompt
có giá trị cụ thể:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
Nhưng điều này không áp dụng cho vỏ Bourne cũng như vỏ POSIX.
Đối với hệ vỏ POSIX, phương thức được cấp duy nhất là đặt mã cho các vỏ tương tác vào tệp:
$ENV
có tên cụ thể vỏ. Nó là ví dụ
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Những người khác đã đề cập đến cờ shell -i
, nhưng điều này không thể sử dụng để lập trình đáng tin cậy. POSIX không yêu cầu set -i
hoạt động, cũng không $-
chứa i
vỏ tương tác. POSIX chỉ yêu cầu sh -i
thực thi shell vào chế độ tương tác.
Vì biến $PS1
có thể được nhập từ môi trường, nên nó có thể có giá trị ngay cả trong chế độ không tương tác. Thực tế là bash
unset
s PS1
trong bất kỳ shell không tương tác nào không được cấp bởi tiêu chuẩn và không được thực hiện bởi bất kỳ shell nào khác.
Vì vậy, lập trình sạch (thậm chí với bash
) là đặt các lệnh cho shell tương tác vào $HOME/.bashrc
.
Trước tiên tôi sẽ nói về Debian, và phần lớn thời gian Ubuntu cũng thiết lập cho bash. Và sau đó chạm vào các hệ thống khác.
Trong cài đặt shell start file có rất nhiều ý kiến.
Tôi cũng có ý kiến của mình nhưng tôi sẽ cố gắng hiển thị các ví dụ hiện có về cài đặt chính xác.
Tôi sẽ sử dụng debuan vì khá dễ tìm thấy các ví dụ về các tệp của nó.
Và debian được sử dụng rất nhiều, vì vậy các cài đặt đã được kiểm tra tốt,
Chỉ để tìm hiểu nếu vỏ là tương tác.
Các mặc định /etc/profile
trong debian và ubuntu (từ / usr / share / cơ sở-files / hồ sơ):
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
Nếu đọc: if tương tác (bộ mặc định PS1) và nó là bash shell (nhưng không hoạt động như một mặc định sh
), sau đó thay đổi PS1 thành một cái mới cụ thể (không phải mặc định).
Các mặc định /etc/bash.bashrc
trong debian cũng chứa:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Điều này khá rõ ràng trong những gì nó làm: Nếu tương tác không nguồn (phần còn lại).
Tuy nhiên, trong /etc/skel/.bashrc
là một ví dụ về cách chính xác để kiểm tra trình bao tương tác (sử dụng $-
):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Điều đó sẽ cho thấy rõ lý do tại sao của PS1 và một thay thế.
Nên tránh cài đặt bạn đang báo cáo.
Trình tự (từ thiết lập hệ thống để thiết lập người dùng cụ thể hơn (ví bash)) là /etc/profile
, /etc/bash.bashrc
, ~/.profile
và cuối cùng ~/.bashrc
. Điều đó đặt các hiệu ứng rộng nhất (và cho nhiều shell hơn) /etc/profile
(thuộc sở hữu của root) theo sau /etc/bash.bashrc
(cũng thuộc sở hữu của root) nhưng chỉ ảnh hưởng đến bash. Sau đó đến cài đặt cá nhân $HOME
, đầu tiên là ~/.profile
cho hầu hết các shell và ~/.bashrc
(gần như tương đương ~/.bash_profile
), chỉ dành riêng cho bash.
Do đó, sai lầm khi nguồn ~/.bashrc
trong ~/.profile
, nó được chuyển một người dùng cụ thể thiết lập cho bash đến một khái quát hơn đó là ảnh hưởng tới vỏ . Ngoại trừ nếu được thực hiện theo cách này :
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
Nó kiểm tra xem bash đang chạy và chỉ tải .bashrc
nếu đó là trường hợp.
Đây là một quyết định ngược dòng đến từ Debian. Lý do được giải thích ở đây .
Trên thực tế, điều ngược lại, tìm nguồn cung ứng ~/.profile
trong ~/.bash_profile
(hoặc ~/.bashrc
) chỉ áp dụng lại các quy tắc chung đã được tải cho một trường hợp sử dụng cụ thể và do đó "không tệ" (tôi không nói là "tốt"). Và tôi không nói tốt bởi vì nó có thể khiến việc tìm nguồn cung cấp các vòng lặp. Giống như khi một thư mục con tải một phụ huynh, đó là một vòng lặp thư mục.
Và trong nguồn cung cấp chéo này, việc kiểm tra vỏ tương tác có ý nghĩa. Chỉ khi một vỏ được tương tác được ~/.bashrc
tải, nhưng đến lượt nó có thể đang tải ~/.profile
(hoặc ngược lại) và trong trường hợp này, việc kiểm tra vỏ tương tác có thể được sử dụng.
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )
, chỉ đơn giản là in[]
. Có vẻ như zsh không làm như vậy, ít nhất là từ một thử nghiệm ... Trong mọi trường hợp, mục đích của việc[ -n "$PS1" ]
này là kiểm tra xem vỏ có tương tác hay không.