なぜ人々は.profileで定義されている機能について文句を言うのですか?

なぜ人々は.profileで定義されている機能について文句を言うのですか?

私はBash 5.1.8を使用しています。実行すると、manマニュアルページが表示されますが、次のエラーが発生します。

man ps

sh: bat: line 10: syntax error near unexpected token `('
sh: bat: line 10: ` *.?(ba)sh)'
sh: error importing function definition for `bat'

私の考えでは、いくつかのシェル(sh)はBashismを迷惑にするようです。 Bash-ismsを以下から削除すると~/.bashrc:

    function bat {
        # lines snipped for brevity

        case "$f" in
            *.rs      ) opt_syntax="--syntax=rust";;
            *.?(ba)sh ) opt_syntax="--syntax=shellscript";;
            *.?(m)m   ) opt_syntax="--syntax=objc";;
        esac

        # lines snipped for brevity
    }
    export -f bat

.bashrcBashの起動時にエラーや警告が表示されないため、それ自体に問題はないと確信しています。追加のデバッグを通じて.profile購入したことがわかりました。.bashrc

# source Bash customizations
[ -n "${BASH_VERSION}" ] && [ -r "${HOME}/.bashrc" ] && . "${HOME}/.bashrc"

このように~/.bashrc始めました。

# If not running interactively, don't do anything
[[ "$-" != *i* ]] && return

質問:

  1. なぜ始める前にリソースを確保するman必要がありますか?.profile
  2. 二重チェックにもかかわらず、上記のコードがBashではなくシェルで解析されるのはなぜですか?
    1. Bashではない場合、.profileソースコードが得られないことを確認してください。.bashrc
    2. .bashrcさらに処理を中止するには、非対話式にチェックインしてください。

@muruのコメントを通して、Bashではなくシェルからインポートする危険があるので、エクスポートされた関数にBashismを含めてはいけないことに気づきました。残りの質問:なぜman電話するのですshか?

答え1

manあなたのものを読みませんが、いくつかのコマンドラインを解釈するために~/.profile実行されます(または少なくとも私のシステムではスクリプトラッパーを解釈します)。そしてあなたのシステムでは:shnroffshgroffshbash輸入bashexport -f(shellshockの後に名前付き変数から)BASH_FUNC_funcname%%によってエクスポートされた関数、sh

extglobここでは、このオプションによって構文が異なる関数をエクスポートしています。したがって、実行sh(モードbashで)してエクスポートされたすべての機能をインポートすると、デフォルトで有効なオプション(モードであるかどうか)ではないshため、問題を解決できません。extglobsh

IOW、関数のエクスポートは、その関数がすべての呼び出しで使用されることを意味しますbashshしたがって、shこれらの関数の構文が-as-in-default設定と互換性があることにbash注意する必要があります。それ以外の場合は、関数のエクスポートをすべて避ける必要があります。これらの関数が呼び出されなくても、これらの関数のコードも解析されます。bashshbash

望むより:

$ env 'BASH_FUNC_f%%=() { case x in ?(x)) echo x; esac; }' bash -O extglob -c f
x
$ env 'BASH_FUNC_f%%=() { case x in ?(x)) echo x; esac; }' bash -c f
bash: f: line 0: syntax error near unexpected token `('
bash: f: line 0: `f () { case x in ?(x)) echo x; esac; }'
bash: error importing function definition for `f'
bash: line 1: f: command not found

関数にこのような解析に影響を与えるデフォルト以外のオプションが必要な場合は、extglob次のように定義できます。

f() (
  shopt -s extglob
  eval '
    function body here
  '
)
export -f f

これは、オプションが関数の実行中にのみ設定されるようにサブシェルでコードを実行し(ローカル範囲を持たないbashオプションzshまたはオプション(最近のバージョンで設定されたオプションを除く)とは逆に)、関数が呼び出されるまで遅延解析を使用し、オプションが設定されますされました。kshsetevalextglob

ここでも次のことができます。

f() (
  shopt -s extglob
  pattern='*.?(ba)sh'
  case ... in
    ($pattern)...
  esac
)

ただし、次のようにすることもできます。

f() {
  case ... in
    (*.sh | *.bash) ...
  esac
}

これはsh必要ありませんextglob

答え2

関数、特に基本以外の bash 構成を必要とする関数をエクスポートしないでください。

エクスポートされた関数はbash機能なので、他のシェルには影響しません。しかし、これはbashへのすべての呼び出しに影響します。関数でextglobこのオプションを有効にする必要があります。それ以外の場合、関数の実行が失敗するだけでなく、分析する関数の定義に失敗しました。関数をエクスポートすると、bashは操作を開始する前に関数定義を解析します。

シェルはshUnixシステムのグルーコードです。インタラクティブに使用するだけでなく、後ろでも広く使用されています。プロシージャ呼び出しはshさまざまな目的で使用されます。man複数のコンパニオンプログラムを呼び出します。そのうちの1つはシェルを呼び出すことができます。たとえば、Linuxでのnroff一般的な実装(マンページのソースコードを端末のリッチテキストに変換する基本的なコマンド)はgroff伝統的です。 、ディストリビューションによっては、dash、bash(またはLinuxではまれですが、他の実装)かもしれません。nroffnroffsh

インタラクティブな使用の場合、bashはロードするので、.bashrc環境に関数を置くことは意味がありません。その定義を.bashrc、またはfromに入れます.bashrc。独自のスクリプトの場合は、関数定義を目的のファイルに入れます(.profileまたは.bashrcそれ自体が含まれているため)。すべてのスクリプトに対して実行してはいけません)、スクリプトにまたはコマンドを入れてくださいsource.関数定義をエクスポートする利点はほとんどありません。これを使用するスクリプトを制御するので、定義された場所を取得することができます。 Bashがデフォルト設定で関数を解析できない場合、関数が機能する方法はありません。

関連情報