Mengapa shell interaktif pada shell login OSX secara default?

43

Di Linux dan, setahu saya, semua sistem Unix, emulator terminal menjalankan shell interaktif, non-login secara default. Ini berarti bahwa, untuk bash, shell yang dimulai akan:

Ketika shell interaktif yang bukan shell login dimulai, bash membaca dan mengeksekusi perintah dari /etc/bash.bashrcdan ~/.bashrc, jika file-file ini ada. Ini dapat dihambat dengan menggunakan --norc opsi.

The --rcfile pilihan file akan memaksa bash untuk membaca dan menjalankan perintah dari file bukan /etc/bash.bashrcdan ~/.bashrc.

Dan untuk shell login:

Ketika bash dipanggil sebagai shell login interaktif, atau sebagai shell non-interaktif dengan --loginopsi, bash pertama kali membaca dan mengeksekusi perintah dari file /etc/profile, jika file itu ada. Setelah membaca file itu, tampaknya untuk ~/.bash_profile, ~/.bash_logindan ~/.profile, agar, dan membaca dan mengeksekusi perintah dari yang pertama yang ada dan dapat dibaca.

The --noprofilepilihan mungkin digunakan ketika shell dimulai untuk menghambat perilaku ini.

Pada OSX, bagaimanapun, shell default (yang bash) dimulai di terminal default (Terminal.app) sebenarnya sumber ~/.bash_profileatau lainnya ~.profile. Dengan kata lain, ini bertindak seperti shell login.

Pertanyaan utama : Mengapa shell interaktif interaktif merupakan shell login pada OSX? Mengapa OSX memilih untuk melakukan ini? Ini berarti bahwa semua instruksi / tutorial untuk hal-hal berbasis shell yang menyebutkan mengubah hal-hal di ~/.bashrcakan gagal pada OSX atau sebaliknya ~/.profile. Tetap saja, sementara banyak tuduhan dapat diajukan ke Apple, mempekerjakan devs yang tidak kompeten atau idiot bukanlah salah satunya. Agaknya, mereka punya alasan bagus untuk ini, jadi mengapa?

Subquestions: Apakah Terminal.app benar-benar menjalankan shell login interaktif atau apakah mereka mengubah perilaku bash? Apakah ini khusus untuk Terminal.app atau independen terhadap terminal emulator?

terdon
sumber
2
Terminal.app menjalankan shell login. Saya tidak tahu mengapa Apple memilih untuk melakukan itu.
Gilles 'SO- stop being evil'
By the way, pada macOS Catalina , shell default adalah zsh .
Basil Bourque

Jawaban:

33

Cara kerjanya seharusnya adalah, pada titik ketika Anda mendapatkan prompt shell, keduanya .profiledan .bashrctelah dijalankan. Detail spesifik tentang cara Anda sampai pada titik itu memiliki relevansi sekunder, tetapi jika salah satu file tidak dijalankan sama sekali, Anda akan memiliki shell dengan pengaturan yang tidak lengkap.

Alasan terminal emulator di Linux (dan sistem berbasis X lainnya) tidak perlu menjalankan .profilesendiri adalah bahwa hal itu biasanya sudah berjalan ketika Anda masuk ke X. Pengaturan di .profileseharusnya dari jenis yang dapat diwarisi oleh subproses, jadi selama itu dieksekusi sekali ketika Anda masuk (misalnya melalui .Xsession), subkulit lebih lanjut tidak perlu menjalankannya kembali.

Seperti yang dijelaskan laman wiki Debian oleh Alan Shutko:

"Mengapa ada .bashrcfile terpisah .bash_profile, kalau begitu? Ini dilakukan untuk sebagian besar alasan historis, ketika mesin sangat lambat dibandingkan dengan workstation hari ini. Memproses perintah dalam .profileatau .bash_profilebisa memakan waktu yang cukup lama, terutama pada mesin di mana banyak pekerjaan harus dilakukan dengan perintah eksternal (pra-bash) .Jadi perintah set-up awal yang sulit, yang menciptakan variabel lingkungan yang dapat diturunkan ke proses anak, dimasukkan .bash_profile. Pengaturan sementara dan alias yang tidak diwariskan dimasukkan di .bashrcsehingga mereka bisa kembali dibaca oleh setiap subkulit."

Semua aturan yang sama berlaku pada OSX, juga, kecuali untuk satu hal - GUI OSX tidak berjalan .profileketika Anda masuk, tampaknya karena ia memiliki metode sendiri memuat pengaturan global. Tapi itu berarti bahwa terminal emulator di OSX tidak perlu dijalankan .profile(dengan mengatakan shell itu meluncurkan bahwa itu adalah shell login), jika tidak, anda akan berakhir dengan shell berpotensi lumpuh.


Sekarang, semacam kekhasan bash, tidak dibagikan oleh kebanyakan shell lain, adalah bahwa itu tidak akan berjalan secara otomatis .bashrcjika dimulai sebagai shell login. Cara kerja standar untuk itu adalah memasukkan sesuatu seperti perintah berikut ini di .bash_profile:

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

Atau, mungkin tidak ada .bash_profilesama sekali, dan cukup sertakan beberapa kode spesifik-bash dalam .profilefile generik untuk dijalankan .bashrcjika diperlukan.

Jika OSX default .bash_profileatau .profile tidak melakukan ini, maka itu bisa dibilang bug. Bagaimanapun, penyelesaian yang tepat adalah dengan hanya menambahkan garis-garis itu .bash_profile.


Sunting: Seperti strugee note , shell default pada OSX dulu tcsh, yang perilakunya lebih waras dalam hal ini: ketika dijalankan sebagai shell login interaktif, tcsh secara otomatis membaca keduanya .profile dan .tcshrc / .cshrc, dan dengan demikian tidak memerlukan solusi seperti .bash_profiletrik. ditunjukkan di atas.

Berdasarkan hal ini, saya yakin 99% bahwa kegagalan OSX untuk memasok default yang sesuai .bash_profileadalah karena, ketika mereka beralih dari tcsh ke bash, orang-orang di Apple tidak memperhatikan kutil kecil ini dalam perilaku startup bash. Dengan tcsh, tidak ada trik seperti itu diperlukan - mulai tcsh sebagai shell login dari emulator terminal OSX Just Plain Works dan melakukan hal yang benar tanpa kluges seperti itu.

Ilmari Karonen
sumber
1
Terima kasih, saya agak tahu semua itu. Pertanyaan saya adalah mengapa OSX memilih untuk mengatur sedemikian rupa agar .bashrctidak relevan? Mengapa mereka memilih untuk membuat semua shell login shell? Sejauh yang saya tahu, hanya kalimat terakhir Anda yang membahasnya dan hanya mengatakan itu bug.
terdon
1
Tidak, masalahnya adalah mereka memulai shell login di emulator terminal mereka. Dotfile adalah perilaku default bash, memulai shell login akan membaca profil dll, bukan bashrc dll. Pertanyaannya adalah mengapa shell login dijalankan bukan yang non-login.
terdon
2
Ya, dan saya dan Alan telah menjelaskan bahwa itu karena, tidak seperti Linux, OSX tidak mengeksekusi .profileketika pengguna masuk ke GUI, jadi mereka harus mengeksekusinya nanti untuk mendapatkan variabel lingkungan seperti $PATH, yang biasanya diatur dalam .profile, dikonfigurasi dengan benar . Fakta bahwa, sebagai efek samping, ini menyebabkan .bashrctidak bersumber adalah bug; Anda bisa berdebat apakah bug di bash atau di OSX, tapi itu tidak mengubah fakta bahwa perilaku yang benar adalah untuk memastikan bahwa kedua variabel lingkungan dari .profiledan pengaturan konfigurasi bash dari .bashrcdimuat.
Ilmari Karonen
1
Memiliki .bashrcsumber .profileakan menjadi ide yang buruk, karena itu akan menyebabkan setiap subkulit dijalankan kembali .profile. Jika tidak ada yang lain, ini akan menyebabkan .profileidiom umum ingin export PATH = "$HOME/bin:$PATH"terus entri yang berlebihan $PATH. Memiliki .profilesumber .bashrcjauh lebih masuk akal, tetapi hanya setelah memeriksa bahwa shell itu berjalan di bawah, pada kenyataannya, bash. Memiliki .bash_profilesumber keduanya .profile dan .bashrc , seperti yang saya sarankan di atas, adalah, IMO, opsi yang paling masuk akal.
Ilmari Karonen
2
Dan saya mengatakan jawaban untuk "mengapa mereka menggunakan shell login?" adalah "karena mereka perlu memuat .profile", sedangkan jawaban untuk "mengapa mereka tidak mengambil .bashrcdari .profile, lalu?" adalah "karena itu bug!" Serius, itu tidak mungkin menjadi keputusan yang disengaja; itu hanya sesuatu yang mereka abaikan, mungkin karena, dalam ekosistem Mac, kerang adalah warga negara kelas dua yang seharusnya tidak ditangani oleh sebagian besar pengguna. (Mz. Lihat juga jawaban orang asing untuk penjelasan historis; hampir pasti ini adalah regresi dari pergantian dari tcsh ke bash.)
Ilmari Karonen
14

Alasan utama bahwa aplikasi terminal X menjalankan shell non-login secara default adalah bahwa di awal waktu, .Xsession Anda akan menjalankan .profile untuk mengatur item login awal Anda. Kemudian, karena semua sudah diatur, aplikasi terminal tidak perlu menjalankannya, mereka dapat menjalankan .bashrc. Diskusi mengapa ini penting adalah di https://wiki.debian.org/DotFiles :

Mari kita ambil xdm sebagai contoh. pierre kembali dari liburan suatu hari dan menemukan bahwa administrator sistemnya telah menginstal xdm pada sistem Debian. Dia masuk dengan baik, dan xdm membaca file .xsession-nya dan menjalankan fluxbox. Segalanya tampak baik-baik saja sampai ia mendapatkan pesan kesalahan di tempat yang salah! Karena ia menimpa variabel LANG dalam .bash_profile-nya, dan karena xdm tidak pernah membaca .bash_profile, variabel LANG-nya sekarang disetel ke en_US, bukan fr_CA.

Sekarang, solusi naif untuk masalah ini adalah bahwa alih-alih meluncurkan "xterm", ia dapat mengkonfigurasi window manager-nya untuk meluncurkan "xterm -l". Bendera ini memberi tahu xterm bahwa alih-alih meluncurkan shell normal, itu harus meluncurkan shell login. Di bawah pengaturan ini, xterm memunculkan / bin / bash tetapi ia menempatkan "- / bin / bash" (atau mungkin "-bash") dalam vektor argumen, jadi bash bertindak seperti shell login. Ini berarti bahwa setiap kali dia membuka xterm baru, ia akan membaca / etc / profile dan .bash_profile (perilaku bash bawaan), dan kemudian .bashrc (karena .bash_profile mengatakan untuk melakukan itu). Ini mungkin kelihatannya bekerja dengan baik pada awalnya - file-file dot-nya tidak berat, jadi dia bahkan tidak melihat penundaan - tetapi ada masalah yang lebih halus. Dia juga meluncurkan browser web langsung dari menu fluxbox-nya, dan browser web mewarisi variabel LANG dari fluxbox, yang sekarang disetel ke lokal yang salah. Jadi sementara xtermsnya mungkin baik-baik saja, dan apa pun yang diluncurkan dari xtermsnya mungkin baik-baik saja, browser webnya masih memberinya halaman di tempat yang salah.

Pada OS X, lingkungan pengguna tidak dimulai oleh setumpuk skrip shell, dan launchd tidak sumber .profile kapan saja. (Itu agak memalukan, karena itu berarti jauh lebih menyebalkan untuk mengatur variabel lingkungan, tetapi begitulah hidup.) Karena tidak, kapan akan berjalan. Profil? Hanya jika Anda masuk? Sepertinya tidak ada gunanya, karena banyak kotak tidak akan pernah menjadi target ssh. Mungkin juga membuat terminal menjalankan shell login secara default, sehingga. Profil akan dijalankan kapan-kapan.

Bagaimana dengan .bashrc? Apakah itu tidak berguna? Tidak. Masih memiliki tujuan yang dimilikinya pada zaman VT100. Ini digunakan kapan saja Anda membuka shell selain membuka jendela Terminal. Jadi jika Anda keluar dari Emacs atau vi, atau jika Anda melakukan pengguna su.

Alan Shutko
sumber
1
Halaman Debian yang Anda kutip menjelaskan mengapa .profilesumber Debian .bashrc, bukan mengapa OSX memutuskan untuk membuat semua shell login shell secara default. Sebenarnya, Anda menjawab pertanyaan saya yang lain , dan terima kasih! Namun, jawaban Anda tidak menjelaskan pilihan OSX dan kutipan Debian sama sekali tidak relevan di sini sejauh yang saya tahu (tolong beri tahu saya jika saya tidak mengerti intinya). Cara OSX membuat .bashrcdll tidak berguna dan tidak membuat .profilelebih berguna.
terdon
4

Saya tidak tahu mengapa mereka melakukan itu. Namun, ini tebakan saya.

Untuk mulai dengan, perlu dicatat bahwa pada sistem GNU / Linux, Anda tentu saja dapat beralih ke vt1, vt2, dll. Anda mendapatkan shell login di sana. Pada sistem OS X, tidak ada yang setara. Satu-satunya cara untuk mengakses dasar-dasar UNIX adalah melalui terminal emulator atau melalui mode pengguna tunggal (penafian: Saya tidak pernah benar-benar menggunakan mode pengguna tunggal; itu adalah IIRC yang digerakkan oleh perintah tapi saya mungkin salah). Oleh karena itu, di OS X apa pun defaultnya di emulator adalah default untuk seluruh sistem.

Sekarang, mengapa Anda membuat default shell login? Ada beberapa (baca: tidak banyak) alasan yang bisa saya pikirkan untuk melakukan ini.

  • Ini memberikan pengalaman pengguna yang konsisten jika Anda memasukkan SSH ke dalam kotak. (Terutama penting untuk edisi server OS X - mungkin jika Anda menjalankan server OS X, Anda seorang pemula.)
  • Shell default OS X dulu tcsh. Ini adalah tebakan liar yang bisa Anda peroleh, tetapi mungkin hal itu tcshbiasanya dilakukan ketika dijalankan sebagai shell login, dan pola historisnya macet. (Tapi saya ragu - mungkin salah satu pelanggan tetap bisa memberi tahu kami.)
  • "Kami adalah Apple. Kami adalah vendor distribusi UNIX terbesar di planet ini. Tidak masalah seberapa sepele alasan kami; jika kami mengambil keputusan, alat Anda harus menghadapinya."

Jujur, saya sudah menggunakan Darwin selama ~ 6 tahun dan saya tidak bisa menjawab pertanyaan ini dengan benar. Itu juga tidak masuk akal bagi saya.

Untuk menjawab pertanyaan Anda, bashjangan ditambal atau apa pun (setidaknya untuk ini). Emulator terminal default menjalankan shell login secara default, dan mungkin iTerm menyalinnya.

strugee
sumber
1
+1 untuk menyebutkan tcsh, karena perilakunya jauh lebih waras dalam hal ini daripada bash: ketika dimulai sebagai shell login interaktif, tcsh sumber keduanya .profile dan .tcshrc/ .cshrctanpa memerlukan klasp seperti yang saya berikan dalam jawaban saya. Mengingat itu, saya menduga perilaku ini adalah regresi tidak tetap yang disebabkan oleh peralihan dari tcsh ke bash.
Ilmari Karonen
@IlmariKaronen Maksud Anda (di sana -sini ) bahwa sumber tcsh .logindan .tcshrc/ .cshrc? Tidak masuk akal bagi tcsh untuk sumber .profile; biasanya berisi perintah dengan shsintaks yang tcshtidak akan menerima. Saya tidak punya macOS tapi saya membuat /bin/tcshshell login saya di Ubuntu 16.04. .profiletidak bersumber. tcsh (1) tidak menyebutkan file itu, juga tcsh ini (1) .
Eliah Kagan
3

Ini adalah pembaruan untuk status saat ini: jawaban menjadi basi karena versi MacOSX baru telah dirilis dan perilaku login telah berubah.

Pertanyaan ini ditanyakan dan dijawab pada tahun 2014. Saya telah meneliti subjek ini dalam upaya untuk membangun set .bashrc & .bash_profile yang umum digunakan di berbagai distro Linux dan BSD (apa pun namanya jika tidak distro).

Saya baru-baru ini membeli Mac Mini bekas dengan Sierra diinstal, jadi saya sekarang memiliki sistem dengan 10.6, 10.10, 10.11, dan 10.12. Meskipun saya telah membuat yang lebih tua (meninggalkan petunjuk ke status sebelumnya), instalasi 10.12 Sierra tidak tersentuh.

Hasil: Di 10.12 Sierra, tidak ada .bashrc, .bash_profile, atau .profile default yang dibuat. Di / etc, ada bashrc, bashrc_Apple_Terminal, dan profil. Isi dari / 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

Isi dari / 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"

Skrip / etc / bashrc_Apple_Terminal menetapkan variabel PROMPT_COMMAND dan membuat mekanisme untuk mempertahankan status sesi untuk setiap terminal; jika aplikasi terminal berhenti, status sesi sebelumnya dipulihkan ketika aplikasi dimulai lagi. Kalau tidak, hampir tidak ada (minimal $ PS1) yang diatur di / etc / bashrc, meninggalkan kustomisasi lain (real $ PS1, alias, fungsi) yang akan diset dalam ~ / .bashrc dan $ PATH pengaturan di .bash_profile (atau dalam .profile , bersumber dari .bash_profile).

Saya telah mengkonfirmasi bahwa iTerm2 berperilaku sama dengan aplikasi Terminal, kecuali bahwa perilaku default memulai sesi login terlihat dan dapat diedit.

Jika Anda menjalankan sesi terminal XTerm X11 (sekarang XQuartz), Anda akan melihat sesi non-login, sama seperti pada sistem Linux; .bash_profile (atau .profile) dilewati, dan Anda hanya mendapatkan .bashrc.

Dan inilah jawaban saya:

Meskipun aplikasi Terminal mengklaim sebagai xterm (TERM = xterm-256color), itu tidak menetapkan variabel $ DISPLAY kecuali X11 diinstal. Kami melihat simulasi lingkungan X, tetapi tidak sepenuhnya nyata. Jika Anda SSH ke sistem lain dengan -X switch (aktifkan penerusan X11), itu akan gagal karena tidak ada variabel $ DISPLAY. Jika Anda telah menginstal X11, maka SSH ke sistem lain, penerusan X11 akan berhasil.

Intinya (dan jawaban singkat): Aplikasi Terminal bukan terminal X11 sejati (tidak menyetel $ DISPLAY); itu berperilaku lebih seperti login SSH daripada sesi XTerm, dalam hal itu harus menjadi sesi login untuk menetapkan nilai dari / etc / profile dan ~ / .bash_profile atau ~ / .profile

donl
sumber
0

Jawaban di atas menjelaskan alasan mengapa shell interaktif adalah shell login pada macOS secara default: setting in /etc/profile, ~/.profilediwarisi oleh shell non-login pada sistem berbasis X, tetapi tidak pada macOS . Di sini saya ingin mengingatkan Anda bahwa Anda harus selalu menggunakan shell login di macOS karena keberadaan 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

The path_helperutilitas membaca isi dari file dalam direktori /etc/paths.ddan /etc/manpaths.d dan menambahkan isinya ke PATHdan MANPATHlingkungan variabel masing-masing. ( MANPATHVariabel lingkungan tidak akan dimodifikasi kecuali sudah ditetapkan di lingkungan.)

Jika Anda menggunakan shell non-login, beberapa jalur tidak akan diimpor.

Saya pikir itu selalu merupakan ide yang baik bagi pengembang untuk memasukkan file ke dalam /etc/paths.duntuk mengimpor nilai path mereka, tetapi tidak untuk symlink biner yang dapat dipanggil ke lokasi seperti /usr/binatau /bin. (Defaultnya PATHadalah /usr/bin:/bin:/usr/sbin:/sbin. Tidak semua orang menggunakan Homebrew atau MacPorts untuk menambahkan nilai khusus PATH. Jadi tidak selalu ada tempat yang aman untuk menaruh symlink dari perintah yang bisa dipanggil.)

Berikut adalah contoh file di /etc/paths.d. Pada dasarnya Anda menempatkan satu nilai setiap baris.

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

Referensi:

Simba
sumber