web-dev-qa-db-ja.com

グラフィカルログイン中に.profileから関数をエクスポートする方法

私は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で明示的にソースされているように見える場合)、エクスポート関数が機能しないのはなぜですか?

2
tyrion

これは、「 シェルサブプロセスで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
_
3
Kusalananda