Tại sao các shell tương tác trên shell đăng nhập OSX theo mặc định?


43

Trong Linux và, theo hiểu biết của tôi, tất cả các hệ thống Unix, trình giả lập thiết bị đầu cuối đều chạy các shell tương tác, không đăng nhập theo mặc định. Điều này có nghĩa là, đối với bash, shell bắt đầu sẽ:

Khi một vỏ tương tác không phải là vỏ đăng nhập được khởi động, bash sẽ đọc và thực thi các lệnh từ /etc/bash.bashrc~/.bashrc, nếu các tệp này tồn tại. Điều này có thể bị ức chế bằng cách sử dụng --norc tùy chọn.

Các --rcfile tùy chọn tập tin sẽ buộc bash để đọc và thực hiện các lệnh từ tập tin thay vì /etc/bash.bashrc~/.bashrc.

Và cho shell đăng nhập:

Khi bash được gọi dưới dạng shell đăng nhập tương tác hoặc dưới dạng shell không tương tác với --logintùy chọn, đầu tiên nó sẽ đọc và thực thi các lệnh từ tệp /etc/profile, nếu tệp đó tồn tại. Sau khi đọc tệp đó, nó tìm kiếm ~/.bash_profile, ~/.bash_login~/.profile, theo thứ tự đó, và đọc và thực thi các lệnh từ cái đầu tiên tồn tại và có thể đọc được.

Các --noprofiletùy chọn có thể được sử dụng khi vỏ được bắt đầu để ức chế hành vi này.

Tuy nhiên, trên OSX, shell mặc định (là bash) đã bắt đầu trong terminal mặc định (Terminal.app) thực sự là nguồn ~/.bash_profilehoặc ~.profilev.v. Nói cách khác, nó hoạt động như một vỏ đăng nhập.

Câu hỏi chính : Tại sao shell tương tác mặc định là shell đăng nhập trên OSX? Tại sao OSX chọn làm điều này? Điều này có nghĩa là tất cả các hướng dẫn / hướng dẫn cho những thứ dựa trên shell đề cập đến việc thay đổi mọi thứ trong ~/.bashrcsẽ thất bại trên OSX hoặc ngược lại ~/.profile. Tuy nhiên, trong khi nhiều lời buộc tội có thể được san bằng tại Apple, việc thuê các nhà phát triển bất tài hoặc ngu ngốc không phải là một trong số họ. Có lẽ, họ đã có một lý do tốt cho việc này, vậy tại sao?

Câu hỏi con: Terminal.app có thực sự chạy shell đăng nhập tương tác hay họ đã thay đổi hành vi của bash? Đây có phải là đặc trưng của Terminal.app hay nó độc lập với trình giả lập thiết bị đầu cuối?


2
Terminal.app chạy shell đăng nhập. Tôi không biết tại sao Apple chọn làm điều đó.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


33

Cách nó phải làm việc là, tại thời điểm khi bạn nhận được một vỏ nhanh chóng, cả hai .profile.bashrccó được chạy. Các chi tiết cụ thể về cách bạn đến điểm đó có liên quan thứ yếu, nhưng nếu một trong hai tệp không được chạy, bạn sẽ có một vỏ với các cài đặt không đầy đủ.

Lý do các trình giả lập thiết bị đầu cuối trên Linux (và các hệ thống dựa trên X khác) không cần phải.profile tự chạy là vì nó thường sẽ được chạy khi bạn đăng nhập vào X. Các cài đặt .profileđược cho là có thể là loại có thể được kế thừa bởi các quy trình con, miễn là nó được thực thi một lần khi bạn đăng nhập (ví dụ thông qua .Xsession), bất kỳ mạng con nào khác không cần phải chạy lại nó.

Như trang wiki Debian được liên kết bởi Alan Shutko giải thích:

"Tại sao lại là .bashrcmột tệp riêng biệt .bash_profile? Vì vậy, điều này được thực hiện vì hầu hết các lý do lịch sử, khi máy móc rất chậm so với các máy trạm ngày nay. Xử lý các lệnh trong .profilehoặc .bash_profilecó thể mất nhiều thời gian, đặc biệt là trên một máy có nhiều công việc phải được thực hiện bằng các lệnh bên ngoài (trước bash). Vì vậy, các lệnh thiết lập ban đầu khó khăn, tạo ra các biến môi trường có thể được truyền cho các tiến trình con, được đưa vào .bash_profile. Các cài đặt tạm thời và bí danh không được kế thừa được đặt trong .bashrcđể họ có thể được tái đọc bởi mỗi subshell."

Tất cả các quy tắc tương tự cũng có trên OSX, ngoại trừ một điều - GUI OSX không chạy .profilekhi bạn đăng nhập, rõ ràng vì nó có phương thức tải các cài đặt chung. Nhưng điều đó có nghĩa là trình giả lập thiết bị đầu cuối trên OSX không cần phải chạy .profile(bằng cách nói với trình bao, nó khởi chạy rằng đó là trình vỏ đăng nhập), nếu không, bạn sẽ kết thúc với trình bao bị tê liệt.


Bây giờ, một loại đặc biệt ngớ ngẩn của bash, không được chia sẻ bởi hầu hết các shell khác, là nó sẽ không tự động chạy .bashrcnếu nó bắt đầu như một vỏ đăng nhập. Cách giải quyết tiêu chuẩn cho điều đó là bao gồm một cái gì đó giống như các lệnh sau trong .bash_profile:

[[ -e ~/.profile ]] && source ~/.profile    # load generic profile settings
[[ -e ~/.bashrc  ]] && source ~/.bashrc     # load aliases etc.

Ngoài ra, có thể không có gì .bash_profilecả, và chỉ bao gồm một số mã cụ thể bash trong .profiletệp chung để chạy .bashrcnếu cần.

Nếu OSX mặc định .bash_profilehoặc .profile không làm điều này, thì đó có thể là một lỗi. Trong mọi trường hợp, cách giải quyết phù hợp là chỉ cần thêm các dòng đó vào .bash_profile.


Chỉnh sửa: Như ghi chú strugee , vỏ mặc định trên OSX từng là tcsh, mà hành vi của nhiều saner trong lĩnh vực này: khi chạy như một vỏ đăng nhập tương tác, tcsh tự động đọc cả hai .profile .tcshrc / .cshrc, và do đó không cần bất kỳ cách giải quyết như .bash_profilelừa hiển thị ở trên.

Dựa trên điều này, tôi chắc chắn 99% rằng việc OSX không cung cấp mặc định phù hợp .bash_profilelà do, khi họ chuyển từ tcsh sang bash, mọi người tại Apple chỉ đơn giản là không nhận thấy hành vi khởi động nhỏ này của bash. Với tcsh, không cần thủ thuật nào như vậy - bắt đầu tcsh như một vỏ đăng nhập từ trình giả lập thiết bị đầu cuối OSX Just Plain Works và thực hiện đúng mà không cần các kluges như vậy.


1
Cảm ơn, tôi sắp xếp biết tất cả. Câu hỏi của tôi là tại sao OSX chọn thiết lập theo cách để hiển thị .bashrckhông liên quan? Tại sao họ chọn làm tất cả các vỏ đăng nhập? Theo như tôi có thể nói, chỉ câu cuối cùng của bạn giải quyết điều đó và chỉ để nói rằng đó là một lỗi.
terdon

1
Không, vấn đề là họ bắt đầu đăng nhập shell trong trình giả lập thiết bị đầu cuối của họ. Các dotfiles là hành vi bash mặc định, các shell đăng nhập sẽ đọc hồ sơ, v.v., không phải bashrc, v.v. Câu hỏi đặt ra là tại sao shell đăng nhập được chạy thay vì không đăng nhập.
terdon

2
Có, và cả tôi và Alan đều giải thích rằng, không giống như Linux, OSX không thực thi .profilekhi người dùng đăng nhập vào GUI, vì vậy họ phải thực thi nó sau để có được các biến môi trường như $PATHthường được đặt .profile, được định cấu hình chính xác . Thực tế là, như một tác dụng phụ, điều này gây ra .bashrckhông có nguồn gốc là một lỗi; bạn có thể tranh luận về việc đó là lỗi trong bash hay OSX, nhưng điều đó không thay đổi thực tế rằng hành vi đúng sẽ là để đảm bảo rằng cả hai biến môi trường từ .profilevà cài đặt cấu hình bash .bashrcđều được tải.
Ilmari Karonen

1
.bashrcnguồn .profilesẽ là một ý tưởng tồi, vì nó sẽ khiến mọi subshell chạy lại .profile. Nếu không có gì khác, điều này sẽ gây ra các .profilethành ngữ phổ biến như export PATH = "$HOME/bin:$PATH"tiếp tục trả trước các mục thừa $PATH. Có .profilenguồn .bashrccó ý nghĩa hơn rất nhiều, nhưng chỉ sau khi kiểm tra xem cái vỏ nó đang chạy trên thực tế là bash. Có .bash_profilenguồn cả hai .profile .bashrc , như tôi đã đề xuất ở trên, là IMO, tùy chọn hợp lý nhất.
Ilmari Karonen

2
Và tôi đang nói câu trả lời cho "tại sao họ sử dụng shell đăng nhập?" là "bởi vì họ cần tải .profile", trong khi câu trả lời là "tại sao họ không lấy nguồn .bashrctừ .profileđó?" là "bởi vì đó là một lỗi!" Nghiêm túc mà nói, đó không thể là một quyết định có chủ ý; đó chỉ là thứ họ bỏ qua, có lẽ bởi vì, trong hệ sinh thái Mac, vỏ là công dân hạng hai mà hầu hết người dùng không phải đối phó. (. Ps Xem thêm câu trả lời strugee của cho một lời giải thích lịch sử, nó gần như chắc chắn một hồi quy từ việc chuyển đổi từ tcsh để bash.)
Ilmari Karonen

14

Lý do chính khiến các ứng dụng đầu cuối X chạy shell không đăng nhập theo mặc định là vì trong thời gian đầu, .Xsession của bạn sẽ chạy .profile để thiết lập các mục đăng nhập ban đầu của bạn. Sau đó, vì tất cả đã được thiết lập, các ứng dụng đầu cuối không cần chạy nó, chúng có thể chạy .bashrc. Thảo luận về lý do tại sao điều này lại quan trọng tại https://wiki.debian.org/DotFiles :

Hãy lấy xdm làm ví dụ. pierre trở lại sau kỳ nghỉ một ngày và phát hiện ra rằng quản trị viên hệ thống của mình đã cài đặt xdm trên hệ thống Debian. Anh ta đăng nhập tốt, và xdm đọc tệp .xsession của anh ta và chạy fluxbox. Mọi thứ dường như đều ổn cho đến khi anh ta nhận được thông báo lỗi ở địa phương sai! Vì anh ta ghi đè biến LANG trong .bash_profile của mình và vì xdm không bao giờ đọc .bash_profile, nên biến LANG của anh ta được đặt thành en_US thay vì fr_CA.

Bây giờ, giải pháp ngây thơ cho vấn đề này là thay vì khởi chạy "xterm", anh ta có thể định cấu hình trình quản lý cửa sổ của mình để khởi chạy "xterm -ls". Cờ này cho xterm biết rằng thay vì khởi chạy shell thông thường, nó sẽ khởi chạy shell đăng nhập. Theo thiết lập này, xterm sinh ra / bin / bash nhưng nó đặt "- / bin / bash" (hoặc có thể là "-bash") trong vectơ đối số, vì vậy bash hoạt động như một vỏ đăng nhập. Điều này có nghĩa là mỗi khi anh ta mở một xterm mới, nó sẽ đọc / etc / profile và .bash_profile (hành vi bash tích hợp), sau đó .bashrc (vì .bash_profile nói để làm điều đó). Điều này ban đầu có vẻ hoạt động tốt - các tệp chấm của anh ta không nặng, vì vậy anh ta thậm chí không nhận thấy sự chậm trễ - nhưng có một vấn đề tinh tế hơn. Anh ta cũng khởi chạy một trình duyệt web trực tiếp từ menu fluxbox của mình, và trình duyệt web kế thừa biến LANG từ fluxbox, hiện được đặt thành ngôn ngữ sai. Vì vậy, trong khi các xterms của anh ta có thể ổn, và bất cứ điều gì được khởi chạy từ các xterms của anh ta đều ổn, trình duyệt web của anh ta vẫn đưa cho anh ta các trang ở địa phương sai.

Trên OS X, môi trường người dùng không được khởi động bởi một đống tập lệnh shell và launchd không có nguồn .profile bất cứ lúc nào. (Đó là một sự xấu hổ, vì điều đó có nghĩa là việc đặt các biến môi trường sẽ khó chịu hơn rất nhiều, nhưng đó là cuộc sống.) Vì nó không, khi nào nó sẽ chạy .profile? Chỉ khi bạn ssh'd trong? Điều đó có vẻ vô nghĩa, vì nhiều hộp sẽ không bao giờ là mục tiêu của ssh. Cũng có thể làm cho các thiết bị đầu cuối chạy shell đăng nhập theo mặc định, do đó .profile sẽ được chạy đôi khi.

Thế còn .bashrc thì sao? Có phải nó vô dụng? Không. Nó vẫn có mục đích mà nó có trong thời của VT100. Nó được sử dụng cho bất cứ khi nào bạn mở shell ngoài việc mở cửa sổ Terminal. Vì vậy, nếu bạn bỏ ra Emacs hoặc vi, hoặc nếu bạn làm một người dùng su.


1
Trang Debian bạn đang trích dẫn giải thích lý do tại sao .profilecác nguồn của Debian .bashrc, chứ không phải tại sao OSX quyết định tạo tất cả các shell đăng nhập theo mặc định. Thật ra, bạn đang trả lời một câu hỏi khác của tôi , và cảm ơn! Tuy nhiên, câu trả lời của bạn không giải thích được sự lựa chọn OSX và trích dẫn Debian hoàn toàn không liên quan ở đây theo như tôi có thể nói (xin vui lòng cho tôi biết nếu tôi chỉ thiếu điểm). Cách OSX làm cho .bashrcvv vô dụng và không làm cho .profilehữu ích hơn.
terdon

4

Tôi không biết tại sao họ lại làm vậy. Tuy nhiên, đây là dự đoán của tôi.

Để bắt đầu, đáng chú ý là trên hệ thống GNU / Linux, tất nhiên bạn có thể chuyển sang vt1, vt2, v.v. Bạn nhận được một vỏ đăng nhập ở đó. Trên hệ thống OS X, không có tương đương. Cách duy nhất để truy cập vào nền tảng UNIX là thông qua trình giả lập thiết bị đầu cuối hoặc thông qua chế độ người dùng duy nhất (từ chối trách nhiệm: Tôi chưa bao giờ thực sự sử dụng chế độ người dùng đơn lẻ; đó là IIRC điều khiển bằng dòng lệnh nhưng tôi có thể sai). Do đó, trong OS X, bất cứ thứ gì mặc định trong trình giả lập đều là mặc định cho toàn bộ hệ thống.

Bây giờ, tại sao bạn sẽ làm mặc định một vỏ đăng nhập? Có một vài lý do (đọc: không nhiều) tôi có thể nghĩ ra để làm điều này.

  • Nó cung cấp trải nghiệm người dùng nhất quán nếu bạn SSH vào hộp. (Đặc biệt quan trọng đối với phiên bản máy chủ của OS X - có lẽ nếu bạn đang chạy máy chủ OS X, bạn là người mới.)
  • Shell mặc định của OS X được sử dụng là tcsh. Đây là một phỏng đoán hoang dã như bạn có thể nhận được, nhưng có thể đó là điều tcshbình thường đã làm một cái gì đó khi chạy như một vỏ đăng nhập và mô hình lịch sử bị mắc kẹt. (Tuy nhiên, tôi nghi ngờ về điều đó - có lẽ một trong những quy định cũ hơn có thể cho chúng ta biết.)
  • "Chúng tôi là Apple. Chúng tôi là nhà cung cấp phân phối UNIX lớn nhất trên hành tinh. Không quan trọng lý do của chúng tôi tầm thường như thế nào; nếu chúng tôi đưa ra quyết định, công cụ của bạn phải đối phó với nó."

Thành thật mà nói, tôi đã sử dụng Darwin được 6 năm và tôi không thể trả lời đúng câu hỏi này. Nó cũng không thực sự có ý nghĩa với tôi.

Để trả lời câu hỏi phụ của bạn, bashkhông được vá hoặc bất cứ điều gì (ít nhất là cho điều này). Trình giả lập thiết bị đầu cuối mặc định chạy shell đăng nhập theo mặc định và có lẽ là bản sao iTerm đó.


1
+1 khi đề cập đến tcsh, vì hành vi của nó rõ ràng hơn nhiều so với bash: khi bắt đầu như một vỏ đăng nhập tương tác, tcsh cung cấp cả hai .profile.tcshrc/ .cshrckhông yêu cầu bất kỳ klug nào như câu trả lời của tôi. Cho rằng, tôi nghi ngờ hành vi này là một hồi quy không trộn lẫn gây ra bởi việc chuyển đổi từ tcsh sang bash.
Ilmari Karonen

@IlmariKaronen Ý bạn là (ở đây và ở đó ) rằng các nguồn tcsh .login.tcshrc/ .cshrc? Nó sẽ không có ý nghĩa cho tcsh nguồn .profile; nó thường chứa các lệnh với shcú pháp tcshkhông chấp nhận. Tôi không có macOS nhưng tôi đã tạo /bin/tcshvỏ đăng nhập trên Ubuntu 16.04. .profilekhông có nguồn gốc. tcsh (1) không đề cập đến tập tin đó, cũng không phải tcsh này (1) .
Eliah Kagan

3

Đây là một bản cập nhật cho trạng thái hiện tại: các câu trả lời đã trở nên cũ kỹ khi các phiên bản MacOSX mới được phát hành và hành vi đăng nhập đã thay đổi.

Câu hỏi này đã được hỏi và trả lời vào năm 2014. Tôi đã nghiên cứu chủ đề này trong nỗ lực xây dựng một bộ .bashrc & .bash_profile chung để sử dụng trên các bản phân phối Linux và BSD khác nhau (bất cứ điều gì họ gọi chúng nếu chúng không phải là bản phân phối).

Gần đây tôi đã mua một chiếc Mac Mini đã qua sử dụng có cài đặt Sierra, vì vậy bây giờ tôi có các hệ thống với 10.6, 10.10, 10.11 và 10.12. Mặc dù tôi đã mung những cái cũ hơn (để lại manh mối cho tình trạng trước đó của chúng), bản cài đặt Sierra 10.12 không được sử dụng.

Kết quả: Trong 10.12 Sierra, KHÔNG có .bashrc, .bash_profile hoặc .profile mặc định được tạo. Trong / etc, có bashrc, bashrc_Apple_Terminal và hồ sơ. Nội dung của / etc / profile:

# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

Nội dung của / etc / bashrc:

# System-wide .bashrc file for interactive bash(1) shells.
if [ -z "$PS1" ]; then
   return
fi

PS1='\h:\W \u\$ '
# Make bash check its window size after a process completes
shopt -s checkwinsize

[ -r "/etc/bashrc_$TERM_PROGRAM" ] && . "/etc/bashrc_$TERM_PROGRAM"

Tập lệnh / etc / bashrc_Apple_Terminal thiết lập biến PROMPT_COMMAND và thiết lập một cơ chế để duy trì trạng thái phiên cho mỗi thiết bị đầu cuối; nếu ứng dụng đầu cuối bị thoát, trạng thái của phiên trước đó sẽ được khôi phục khi ứng dụng được khởi động lại. Mặt khác, hầu như không có gì (tối thiểu $ PS1) được đặt trong / etc / bashrc, để lại bất kỳ tùy chỉnh nào khác ($ PS1 thực, bí danh, hàm) được đặt trong cài đặt ~ / .bashrc và $ PATH trong .bash_profile (hoặc .profile , có nguồn gốc bởi .bash_profile).

Tôi đã xác nhận rằng iTerm2 hoạt động giống như ứng dụng Terminal, ngoại trừ hành vi mặc định bắt đầu phiên đăng nhập là hiển thị và có thể được chỉnh sửa.

Nếu bạn chạy phiên cuối X11 (bây giờ là XQuartz), bạn sẽ thấy phiên không đăng nhập, giống như trên hệ thống Linux; .bash_profile (hoặc .profile) bị bỏ qua và bạn chỉ cần lấy .bashrc.

Và đây là câu trả lời của tôi:

Mặc dù ứng dụng Terminal tuyên bố là xterm (TERM = xterm-256color), nhưng nó không đặt biến $ HIỂN THỊ trừ khi X11 được cài đặt. Chúng ta đang thấy một mô phỏng của một môi trường X, nhưng không phải là một môi trường hoàn toàn có thật. Nếu bạn SSH vào một hệ thống khác có công tắc -X (bật chuyển tiếp X11), nó sẽ thất bại vì không có biến $ HIỂN THỊ. Nếu bạn đã cài đặt X11, sau đó SSH vào hệ thống khác, chuyển tiếp X11 sẽ thành công.

Dòng dưới cùng (và câu trả lời ngắn): Ứng dụng Terminal không phải là thiết bị đầu cuối X11 thực sự (không đặt $ HIỂN THỊ); nó hoạt động giống như một lần đăng nhập SSH hơn là một phiên XTerm, trong đó nó phải là một phiên đăng nhập để đặt các giá trị từ / etc / profile và ~ / .bash_profile hoặc ~ / .profile


0

Các câu trả lời ở trên đã giải thích lý do tại sao shell tương tác là shell đăng nhập trên macOS theo mặc định: cài đặt trong /etc/profile, ~/.profileđược kế thừa bởi shell không đăng nhập trên các hệ thống dựa trên X, nhưng không phải trên macOS . Ở đây tôi muốn nhắc bạn rằng bạn nên luôn sử dụng shell đăng nhập trên macOS vì sự tồn tại của path_helper:

 cat /etc/profile # or cat /etc/zprofile
# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

Các path_helpertiện ích đọc nội dung của các tập tin trong các thư mục /etc/paths.d/etc/manpaths.d và gắn thêm nội dung của họ đến PATHMANPATHmôi trường biến tương ứng. (Biến MANPATHmôi trường sẽ không được sửa đổi trừ khi nó đã được đặt trong môi trường.)

Nếu bạn đang sử dụng shell không đăng nhập, một số đường dẫn sẽ không được nhập.

Tôi nghĩ rằng luôn luôn là một ý tưởng tốt cho nhà phát triển để đưa tệp vào /etc/paths.dđể nhập giá trị đường dẫn của họ, nhưng không liên kết các nhị phân có thể gọi được vào các vị trí như /usr/binhoặc /bin. (Mặc định PATH/usr/bin:/bin:/usr/sbin:/sbin. Không phải ai cũng sử dụng Homebrew hoặc MacPorts thêm các giá trị tùy chỉnh vào PATH. Vì vậy, không phải lúc nào cũng là nơi an toàn để đặt liên kết tượng trưng của các lệnh có thể gọi được.)

Dưới đây là một ví dụ về các tập tin trong /etc/paths.d. Về cơ bản, bạn đang đặt một giá trị mỗi dòng.

 cat /etc/paths.d/Wireshark
/Applications/Wireshark.app/Contents/MacOS

Tài liệu tham khảo:

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.