web-dev-qa-db-ja.com

現在のシェルを判別するためのcheckbashisms準拠の方法

私の_.profile_では、次のコードを使用して、ログインシェルが実際にBashである場合にのみBash関連のエイリアスと関数が供給されるようにします:

_# If the current (login) Shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi
_

現在、シェル構成ファイル、スクリプト、関数をバージョン管理下に置いています。私は最近、function funcname()funcname()に置き換えるなど、Bash固有の機能の恩恵を受けないシェルスクリプトからカジュアルなBashismを削除するプロセスも開始しました。

私のシェルファイルリポジトリでは、Debianの devscriptsからcheckbashismsユーティリティを実行するpre-commitフックを構成しましたパッケージ リポジトリ内の各shファイルに、誤ってBash固有の構文を導入しないようにします。ただし、これにより_.profile_のエラーが発生します。

_possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then
_

checkbashismsで警告をトリガーしないシェルが実行されていることを確認する方法があるかどうか疑問に思いました。

私は POSIXによってリストされたシェル関連の変数 のリストをチェックし、それらの1つが現在のシェルを表示するために使用できることを期待しました。インタラクティブなダッシュシェルに設定された変数も確認しましたが、やはり適切な候補を見つけることができませんでした。

現時点では、checkbashismsによる処理から_.profile_を除外しています。小さいファイルなので、手動で確認するのは難しくありません。ただし、問題を調査した後も、実行中のシェルを判断するためのPOSIX準拠の方法があるかどうか(または少なくともcheckbashismsが失敗しない方法)があるかどうかを知りたいです。


さらなる背景/説明

シェル構成ファイルをバージョン管理下に置く理由の1つは、現在定期的にログインしているすべてのシステム(Cygwin、Ubuntu、CentOS(5と7の両方、ユーザーにActive Directoryを使用)で環境を構成することです認証)。私はほとんどの場合、X Windows /デスクトップ環境とSSHを介してリモートホストにログオンします。ただし、これは将来の証拠であり、システムの依存関係や他のツールへの依存度をできるだけ低くしたいと思います。

私は、シェル関連ファイルの構文の単純な自動サニティチェックとしてcheckbashismsを使用しています。これは完璧なツールではありません。たとえば、スクリプトでの_command -v_の使用について問題がないように、すでにパッチを適用しています。調査中に、プログラムの実際の目的は、Debianのポリシーに確実に準拠することであり、私が理解しているように、2008年ではなくPOSIX 2004(またはその2013年の改訂)に基づいていることを知りました。

18

きみの

_# If the current (login) Shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi
_

コードは完全にPOSIXに準拠しており、現在bashを実行していることを確認する最良の方法です。もちろん、_$BASH_VERSION_変数はbash固有ですが、それが具体的に使用している理由です。 bashを実行していることを確認するには!

_$BASH_VERSION_は、bashbashまたはshのどちらとして呼び出されても設定されることに注意してください。 bashを実行していることをアサートしたら、シェルがshとして呼び出されたことを示すインジケーターとして_[ -o posix ]_を使用できます(そのオプションは、POSIXLY_CORRECTが環境内にあるか、bashが_-o posix_、または環境でSHELLOPTS = posixを使用します。ただし、これらすべてのケースで、bashshとして呼び出されたかのように動作します。


_$BASH_VERSION_の代わりに使用できる別の変数と、_-x_オプションが_$BASH_を渡されない限り、checkbashismは不満を感じないようです。これはbashにも固有なので、bashを実行しているかどうかを判別するためにも使用できるはずです。


また、実際にはcheckbashismsの適切な使用法ではないことも主張します。 checkbashismsは、移植可能なshスクリプト(Debianポリシーのsh仕様、POSIXのスーパーセットによる)を作成するのに役立つツールで、shbashへのシンボリックリンクであるシステムでスクリプトを作成する人によって導入された非標準構文を識別するのに役立ちます。

_.profile_はさまざまなシェルによって解釈され、その多くはPOSIXに準拠していません。通常、ログインシェルとしてshを使用しませんが、より高度なインタラクティブ機能を備えたzshfishbashなどのシェルを使用します。

bashおよびzshshとして呼び出されない場合、およびそれぞれのプロファイルセッションファイル(_.bash_profile_、_.zprofile_)がPOSIX準拠ではない(特にzsh)場合でも、_.profile_を読み取ります。

したがって、_.profile_に必要なPOSIX構文ではありませんが、POSIX(sh)、bash、およびzshと互換性のある構文です(これらのシェルを使用する場合は、Bourneでも_.profile_ですが、Linuxベースのシステムでは一般的には見つかりません)。

checkbashismsは間違いなくbashismsを見つけるのに役立ちますが、zshまたはbashと互換性のないPOSIX構文を指摘しない場合があります。

ここで、bash固有のコード(対話型ログインシェルで_~/.bashrc_を読み取らないbashバグの回避策など)を使用する場合、_~/.bash_profile_を実行することをお勧めします。それ(通常のセッション初期化を配置する_~/.profile_をソーシングする前または後)。

16

通常は$0 この目的のために。あなたがそれをリンクしたサイトには立っています:

0
   (Zero.) Expands to the name of the Shell or Shell script.
17
jimmij

通常、シェル環境変数はデフォルトのシェルを示します。 .bashrcファイルを手動でソースする必要はありません(trueは以下を参照)。bashは、$ HOMEディレクトリにあることを確認するだけで、これを自動的に行う必要があります。

他のオプションは次のようなことです:

 ps -o cmd= $$

これは、現在のプロセスのコマンド(引数なし、=なしの=は列ヘッダーを表示しません)を通知します。出力例:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

更新:

立て直しました! :)

.bashrcは、以下のコメントや https://stackoverflow.com/questions/415403/whats-the-difference-between-bashrc-bash-profile-and-environment で言及されているように、常に供給されているとは限りません=

したがって、.bashrcを.bash_profileに移動して、テストを行わなくても機能するかどうかを確認できます。そうでない場合は、上記のテストがあります。

5
Rob

質問は、ユーザーのloginシェルとcurrentシェルを要求しますcheckbashismsを緩和する方法で。それがユーザーがログインしたシェルである場合、/etc/passwdのシェルを使用します。たとえば、

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

もちろん、ユーザーはログイン後に新しいシェルを起動できます。もちろん、一方がbashでもう一方がbashでない場合、bashの環境変数のテストは役に立たない場合があります。

getentファイルだけではなくpasswdを使用したい場合もあります(ただし、これは問題の範囲には含まれません)。

LDAPに関するコメントと logname の提案に基づいて、この代替形式を使用できます。

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

テスト中、lognameはリダイレクトされる入力が好きではないことに気付きました(そのため、式を分割したままにしました)。クイックチェックは、getentが上記のプラットフォームで機能することを示しています(ただし、元の質問で提供されているはずです)。

4
Thomas Dickey