私はGDMでUbuntu18.04を使用しています。 .profile
からいくつかのbash関数をエクスポートしようとしています。
この非常に優れたリソース で説明されているように、.bashrc
と.profile
の主な違いは、後者がログインシェルでのみ実行されることです。
私はすでに.profile
を使用して、.bashrc
では適切ではないいくつかの環境変数をエクスポートしています。したがって、グラフィカルログインシェルでも.profile
が正常に取得されていることがわかります。たとえば、私の$PATH
定義は次のようになります。
export PATH="something/bin:$PATH"
これを.bashrc
に入れると、サブシェルを実行するたびに"something/bin"
が再び挿入されます。
$ echo $PATH
something/bin:/usr/local/bin:/usr/bin:/bin
$ bash
$ echo $PATH
something/bin:something/bin:/usr/local/bin:/usr/bin:/bin
ただし、次のような関数のエクスポートは、グラフィカルログインでは機能しないようです。
hello () { echo "hello"; }
export -f hello
bash -l
を実行するときと、コンソールログインからの両方で正しく機能します。
したがって、問題は、どうやら.profile
がソースされた場合(env変数が正常にエクスポートされ、/etc/gdm3/Xsession
で明示的にソースされているように見える場合)、エクスポート関数が機能しないのはなぜですか?
これは、「 シェルサブプロセスでBASH_FUNC_foobar %%環境変数が設定されていないのはなぜですか? "」で説明されている問題の特定のインスタンスである可能性があります。
関数をbash
にエクスポートすると、特別な名前の環境変数が作成されます。
_$ foo () { echo hello; }
$ export -f foo
$ env
...
BASH_FUNC_foo%%=() { echo hello
}
...
_
シェル関数は本当にを関数としてエクスポートできないため、シェルはこれを行います。そのため、代わりに「特別な環境変数」に変換されます。環境変数は、単純なキーと値の文字列のペアにしかなり得ません。
bash
シェルがこれらの種類の環境変数を持つ環境を継承する場合、それらがbash
関数であることがわかり、適切な名前で関数をインスタンス化します。
POSIX標準 によると:
POSIX.1-2017のShelland Utilitiesボリュームのユーティリティで使用される環境変数名は、大文字、数字、および_
<underscore>
_(__
_)のみで構成されます。 ポータブル文字セットで定義された文字から、数字で始まらない。 他の文字は実装によって許可される場合があります。アプリケーションは、そのような名前の存在を許容するものとします。大文字と小文字は、固有のIDを保持し、一緒に折りたたまれてはなりません。小文字を含む環境変数名の名前空間は、アプリケーション用に予約されています。アプリケーションは、標準ユーティリティの動作を変更することなく、この名前空間の名前で環境変数を定義できます。
この一節によると、名前に_%
_を含む環境変数は許可されますが、他のシェル、たとえば一部のシステムでは_/bin/sh
_になりすますシェル(たとえば、Ubuntuではdash
、およびksh
(OpenBSDの場合))は、環境をサニタイズし、名前に明示的に許可されている文字以外の文字が含まれている環境変数をすべて削除します。
_/bin/sh
_シェルは、アプリケーションがsystem()
を呼び出して別のプロセスを開始するときに使用されます。
これはすべてあなたの_/bin/sh
_がdash
(Ubuntu上にある)であり、ターミナルで取得した最終的なインタラクティブなbash
シェルは、system()
の呼び出しを介して(親プロセスから子プロセスへの継承を介して)渡されたか、または他の方法で_/bin/sh
_途中で、あなたの関数は消えていただろう1。
回避策は、_~/.bashrc
_またはエイリアスを定義する場所で関数を定義することです。または、端末にbash
ログインシェルを生成させるため。
1残念ながら、私はGDMもUbuntuも実行していないため、現在、ログイン手順に関連するプロセスでstrace
を実行して、そこで実際に何が起こっているかを確認することはできません。
他のbash
シェルがbash
によって呼び出されたときに、1つのdash
シェルと別のシェルの間で関数が消えることを示す例:
_$ foo () { echo hello; }
$ export -f foo
$ dash -c 'bash -c foo'
bash: foo: command not found
_
代わりにyash
を使用する例。これは、関数を削除しません。
_$ yash -c 'bash -c foo'
hello
_
同様に、OpenBSDのサニタイズではksh
ですが、_ksh93
_とzsh
はそうではありません。
_$ ksh -c 'bash -c foo'
bash: foo: command not found
$ ksh93 -c 'bash -c foo'
hello
$ zsh -c 'bash -c foo'
hello
_
上記の出力がhello
であるすべての場合において、中間シェルは、特別に名前が付けられた環境変数が関数を構成していることをまったく認識していないことに注意してください。
_$ yash -c 'foo'
yash: no such command `foo'
$ ksh93 -c 'foo'
ksh93: foo: not found
$ zsh -c 'foo'
zsh:1: command not found: foo
_