web-dev-qa-db-ja.com

デフォルトでOSXログインシェルにインタラクティブシェルがあるのはなぜですか?

Linuxでは、私の知る限りでは、すべてのUnixシステムで、ターミナルエミュレータは対話型の非ログインシェルをデフォルトで実行します。つまり、bashの場合、起動したシェルは次のようになります。

ログインシェルではないインタラクティブシェルが起動すると、b [は、これらのファイルが存在する場合、/etc/bash.bashrcおよび~/.bashrcからコマンドを読み取り、実行します。これは、--norcオプションを使用することで禁止できます。

--rcfileファイルオプションは、/etc/bash.bashrcおよび~/.bashrcの代わりに、bashにファイルからのコマンドの読み取りと実行を強制します。

そしてログインシェルのために:

Bashが対話型ログインシェルとして、または--loginオプションを使用した非対話型シェルとして呼び出されると、ファイル/etc/profileが存在する場合、そのファイルからコマンドを読み取り、実行します。そのファイルを読み取った後、~/.bash_profile~/.bash_login、および~/.profileをこの順序で検索し、存在し、読み取り可能な最初のコマンドからコマンドを読み取って実行します。

シェルの起動時に--noprofileオプションを使用して、この動作を禁止できます。

ただし、OSXでは、デフォルトのターミナル(Terminal.app)で起動されたデフォルトのシェル(bash)は、実際には~/.bash_profileまたは~.profileなどをソースします。つまり、ログインシェルのように機能します。

主な質問:デフォルトのインタラクティブシェルがOSXのログインシェルである理由なぜOSXはこれを選択したのですか?つまり、~/.bashrcでの変更に関するシェルベースの説明やチュートリアルは、OSXでは失敗し、~/.profileではその逆になります。それでも、多くの非難はAppleで平準化できるが、無能なまたはばかげた開発者を雇うことはそれらの1つではない。おそらく、これには十分な理由があったので、なぜですか?

サブ質問:Terminal.appは実際にインタラクティブログインシェルを実行しますか、それともbashの動作を変更しましたか?これはTerminal.appに固有ですか、それともターミナルエミュレータから独立していますか?

44
terdon

想定の動作は、シェルプロンプトが表示された時点で、.profile.bashrcの両方が実行されているということです。その時点までの具体的な詳細は二次的な関連性がありますが、いずれかのファイルがまったく実行されなかった場合は、設定が不完全なシェルができます。

Linux(および他のXベースのシステム)のターミナルエミュレータが.profile自体を実行しないneedしない理由は、通常Xにログインしたときにすでに実行されているためです。.profileの設定はログイン時に(たとえば、.Xsessionを介して)1回実行される限り、サブプロセスが継承できる種類のものであることが想定されているため、それ以降のサブシェルで再実行する必要はありません。

Debian wiki page Alan Shutkoによってリンクされた説明:

「それでは、なぜ.bashrc.bash_profileとは別のファイルなのですか?これは、今日のワークステーションと比較してマシンが極端に遅い場合に、歴史的な理由で行われます。特に.profileまたは.bash_profileでコマンドを処理すると、特に多くの作業は外部コマンド(プリバッシュ)で行う必要がありました。そのため、子プロセスに渡すことができる環境変数を作成する難しい初期設定コマンドを.bash_profileに入れます。一時的な設定とエイリアス継承されないものは.bashrcに入れられるため、すべてのサブシェルで再読み取りできます。」

OSXにも同じ規則がすべて適用されますが、OSX GUIは、グローバル設定をロードする独自の方法があるため、ログイン時に.profileを実行しません。しかし、それはOSXのターミナルエミュレーターdoes.profileを実行する必要があることを意味します(シェルに起動シェルであることをシェルに通知することにより)。そうしないと、シェルが機能しなくなる可能性があります。


現在、他のほとんどのシェルでは共有されていない、bashのばかげた特徴の1つは、ログインシェルとして起動した場合、.bashrcが自動的に実行されないことです。そのための標準的な回避策は、次のようなコマンドを.bash_profileに含めることです。

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

あるいは、.bash_profileをまったく使用せず、bash固有のコードをジェネリック.profileファイルに含めて、必要に応じて.bashrcを実行することもできます。

OSXのデフォルトの.bash_profileまたは.profileしないの場合、これは間違いなくバグです。いずれの場合も、適切な回避策は、これらの行を単に.bash_profileに追加することです。


Edit:Strugee notes 、OSXのデフォルトのシェルは、以前はtcshでしたが、この点で動作は非常に健全です:対話型ログインシェルとして実行すると、tcshは自動的に.profileand.tcshrc/.cshrcの両方を読み取るため、上記の.bash_profileトリックのような回避策は必要ありません。

これに基づいて、OSXが適切なデフォルト.bash_profileを提供できないことが99%確信しているのは、tcshからbashに切り替えたときにAppleの人々が単に気づかなかったためですtcshを使用すると、そのようなトリックは必要ありません。OSX端末エミュレーターJust Just Worksからログインシェルとしてtcshを起動し、そのようなクルージなしで正しいことを行います。

35
Ilmari Karonen

Xターミナルアプリケーションがデフォルトで非ログインシェルを実行する主な理由は、当初、.Xsessionが.profileを実行して初期ログイン項目を設定していたためです。その後、すべてがすでにセットアップされているので、ターミナルアプリはそれを実行する必要がなく、.bashrcを実行できました。これがなぜ重要かについての議論は https://wiki.debian.org/DotFiles にあります:

例としてxdmを取り上げます。 pierreはある日休暇から戻ってきて、彼のシステム管理者がDebianシステムにxdmをインストールしたことを発見しました。彼は問題なくログインし、xdmは.xsessionファイルを読み取ってfluxboxを実行します。間違ったロケールでエラーメッセージが表示されるまで、問題はないようです。彼は.bash_profileのLANG変数をオーバーライドし、xdmは.bash_profileを読み取らないため、現在のLANG変数はfr_CAではなくen_USに設定されています。

現在、この問題の素朴な解決策は、「xterm」を起動する代わりに、「xterm -ls」を起動するようにウィンドウマネージャーを構成できることです。このフラグは、通常のシェルを起動する代わりに、ログインシェルを起動する必要があることをxtermに伝えます。この設定では、xtermは/ bin/bashを生成しますが、 "-/ bin/bash"(または "-bash")を引数ベクトルに入れるため、bashはログインシェルのように機能します。これは、彼が新しいxtermを開くたびに、/ etc/profileおよび.bash_profile(組み込みのbash動作)を読み取り、次に.bashrc(.bash_profileがそうするため)を読み取ることを意味します。これは最初はうまくいくように見えるかもしれません-彼のドットファイルは重くないので、彼は遅延に気づくことすらありません-しかし、より微妙な問題があります。彼はまた、fluxboxメニューから直接Webブラウザーを起動し、WebブラウザーはfluxboxからLANG変数を継承します。これは現在、間違ったロケールに設定されています。そのため、彼のxtermは問題なく、彼のxtermから起動されたものは何でも問題ないかもしれませんが、彼のWebブラウザーは依然として彼に間違ったロケールのページを提供しています。

OS Xでは、シェルスクリプトの山によってユーザー環境が開始されることはなく、launchdが.profileを取得することはありません。 (環境変数を設定するのはかなり面倒ですが、それは人生です。)そうではないので、いつ.profileを実行しますか? sshした場合のみ?多くのボックスがsshのターゲットになることは決してないので、それは一種の意味がないように見えます。端末がデフォルトでログインシェルを実行するようにして、.profileがいつか実行されるようにすることもできます。

では、.bashrcはどうでしょうか?役に立たないの?いいえ。VT100の時代の目的がまだ残っています。これは、ターミナルウィンドウを開く以外のときにシェルを開くときに使用されます。つまり、Emacsやviからシェル化した場合、またはsuユーザーを実行した場合です。

14
Alan Shutko

彼らがなぜそうしたのか、私にはわかりません。しかし、これは私の推測です。

まず第一に、GNU/Linuxシステムでは、もちろんvt1、vt2などに切り替えることができます。そこにログインシェルが表示されます。 OS Xシステムでは、これに相当するものはありません。 UNIXの基盤にアクセスする唯一の方法は、ターミナルエミュレーターまたはシングルユーザーモードを使用することです(免責事項:実際にシングルユーザーモードを使用したことはありません。コマンドライン方式のIIRCですが、間違っている可能性があります)。したがって、OS Xでは、エミュレータのデフォルトはすべてシステム全体のデフォルトです。

では、なぜデフォルトをログインシェルにするのでしょうか?これを行うために私が考えることができるいくつかの(読んだ:多くはない)理由があります。

  • ボックスにSSH接続すると、一貫したユーザーエクスペリエンスが提供されます。 (OS Xのサーバーエディションにとって特に重要です。おそらくOS Xサーバーを実行している場合は、初心者です。)
  • OS Xのデフォルトのシェルは、以前はtcshでした。これは、あなたが得ることができるのと同じくらいワイルドな推測ですが、tcshは通常、ログインシェルとして実行したときに何かを行い、履歴パターンがスタックしている可能性があります。 (私はそれを疑います-多分古い常連の1人が私たちに言うことができました。)
  • 「私たちはアップルです。私たちは地球上で最大のUNIXディストリビューションのベンダーです。私たちの理由がどれほど些細なことでもかまいません。私たちが決断した場合、ツールはそれに対処する必要があります。」

正直なところ、私はダーウィンを6年ほど使用しており、この質問に正しく答えることができません。それも私にはあまり意味がありません。

あなたのサブ質問に答えるために、bashにはパッチが適用されていません(少なくともこれについては)。デフォルトのターミナルエミュレータはデフォルトでログインシェルを実行し、おそらくiTermがそれをコピーします。

4
strugee

これは現在のステータスの更新です。新しいMacOSXバージョンがリリースされ、ログイン動作が変更されたため、回答は古くなっています。

この質問は2014年に行われ、回答されました。私は、さまざまなLinuxディストリビューションおよびBSD(ディストリビューションでない場合は何と呼ばれていても)で使用するための共通の.bashrc&.bash_profileセットを構築するために、この問題を調査しています。

最近、Sierraがインストールされた中古のMac Miniを購入したので、10.6、10.10、10.11、および10.12のシステムを使用しています。私は古いものを変更しましたが(手がかりを以前の状態に残しました)、10.12 Sierraのインストールは変更されていません。

結果:10.12 Sierraでは、デフォルトの.bashrc、.bash_profile、または.profileは作成されません。/etcには、bashrc、bashrc_Apple_Terminal、およびプロファイルがあります。/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

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

/ etc/bashrc_Apple_Terminalスクリプトは、Prompt_COMMAND変数を設定し、各端末のセッション状態を保持するメカニズムを設定します。端末アプリが終了した場合、アプリを再度起動すると、以前のセッションのステータスが復元されます。それ以外の場合、/ etc/bashrcにはほとんど何も(最小$ PS1)が設定されず、〜/ .bashrcおよび.bash_profile(または.profile)の$ PATH設定に他のカスタマイズ(実際の$ PS1、エイリアス、関数)が設定されます。 、.bash_profileから提供)。

ログインセッションを開始するデフォルトの動作が表示され、編集できることを除いて、iTerm2がターミナルアプリと同じように動作することを確認しました。

X11(現在はXQuartz)XTermターミナルセッションを実行すると、Linuxシステムの場合と同じように、非ログインセッションが表示されます。 .bash_profile(または.profile)はスキップされ、.bashrcが取得されます。

そして、これが私の答えです:

ターミナルアプリはxterm(TERM = xterm-256color)であると主張していますが、X11がインストールされていない限り、$ DISPLAY変数を設定しません。 X環境のシミュレーションを見ていますが、完全に現実のものではありません。 -Xスイッチ(X11転送を有効にする)を使用して別のシステムにSSH接続すると、$ DISPLAY変数がないため失敗します。 X11をインストールしている場合、別のシステムにSSHで接続すると、X11転送が成功します。

最終結果(および短い答え):ターミナルアプリは、真のX11ターミナルではありません($ DISPLAYを設定していません)。ログインする必要があるという点で、XTermセッションよりもSSHログインのように動作します。/etc/profileおよび〜/ .bash_profileまたは〜/ .profileから値を設定するためのセッション

3
donls

上記の回答は、対話型シェルがデフォルトでmacOSのログインシェルである理由を説明しています:/etc/profile~/.profileの設定は、Xベースのシステムの非ログインシェルによって継承されますが、 macOSの場合。ここでは、path_helperが存在するため、macOSでは常にログインシェルを使用するが必要であることを思い出させたいと思います。

❯ 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

path_helperユーティリティは、ディレクトリ/etc/paths.dおよび/etc/manpaths.d内のファイルの内容を読み取り、それらの内容をPATHおよびMANPATH環境変数にそれぞれ追加します。 (MANPATH環境変数は、環境ですでに設定されていない限り、変更されません。)

非ログインシェルを使用している場合、一部のパスはインポートされません。

開発者は、ファイルを/etc/paths.dに入れてパス値をインポートすることを常にお勧めしますが、呼び出し可能なバイナリを/usr/bin/binなどの場所にシンボリックリンクしないでください。 (デフォルトのPATH/usr/bin:/bin:/usr/sbin:/sbinです。すべてのユーザーがHomebrewまたはMacPortsを使用してPATHにカスタム値を追加するわけではありません。したがって、呼び出し可能なコマンドのシンボリックリンクを配置する安全な場所が常にあるとは限りません。)

/etc/paths.dのファイルの例を次に示します。基本的には、1行に1つの値を入力します。

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

参照:

0
Simba