現在作業中のシェルを特定する方法


634

現在作業中のシェルをどのように判断できますか?

psコマンドの出力だけで十分でしょうか?

Unixの異なるフレーバーでこれをどのように行うことができますか?


9
特定の機能のテスト(たとえば、!置換を行うかどうか)は、シェルの名前を見つけるよりもおそらく移植性があります。ローカルカスタムは、あなたが名前の何か実行している場合があります/bin/sh実際など灰、ダッシュ、bashの、可能性
MSW

1
@msw:「どうやって?」と思ってしまう以外は、良いコメントのようです。
nobar

この質問に対する単純な答えはないようです。シェルにクエリを実行できない場合は、常にシェルを指定することをお勧めします。これが常に可能であるかどうかはわかりませんが、一般的に想定されているよりも簡単に達成できるかもしれません。
nobar

このかもしれないのヘルプ- > opensourceforgeeks.blogspot.in/2013/05/...
Aniketタクール

@Aniket、あなたが思っているほどのヘルプはありません-それはインタラクティブなシェルプロセスにのみ興味があります。
Toby Speight

回答:


794
  • 現在のシェルの実行可能ファイルの名前を見つけるには、3つの方法があります。

    シェルの実行可能ファイルがである場合、3つのアプローチすべてがだまされる可能性がありますが/bin/sh、実際にはbash、たとえば名前が変更されています(これは頻繁に発生します)。

    したがって、ps出力が行うかどうかについての2番目の質問は、「常にではない」で答えられます。

    1. echo $0 -プログラム名を出力します...シェルの場合は実際のシェルです。

    2. ps -ef | grep $$ | grep -v grep-実行中のプロセスのリストから現在のプロセスIDを探します。現在のプロセスはシェルなので、含まれます。

      これは100%信頼できるものではありません。他のプロセスにpsシェルのプロセスIDと同じ番号が含まれている可能性があるため、特にそのIDが小さい場合(たとえば、シェルのPIDが「5」の場合)、プロセスが呼び出されることがあります。同じgrep出力で「java5」または「perl5」!)。これは、シェル名に依存できないことに加えて、「ps」アプローチの2番目の問題です。

    3. echo $SHELL-現在のシェルへのパスは、SHELL任意のシェルの変数として保存されます。この警告は、シェルをサブプロセスとして明示的に起動した場合(たとえば、ログインシェルではない場合)、代わりにログインシェルの値を取得することです。それが可能である場合は、psまたは$0アプローチを使用してください。


  • ただし、実行可能ファイルが実際のシェルと一致しない場合(たとえば/bin/sh、実際にはbashまたはksh)、ヒューリスティックが必要です。以下は、さまざまなシェルに固有の環境変数です。

    • $version tcshに設定されている

    • $BASH バッシュに設定されています

    • $shell (小文字)は、cshまたはtcshで実際のシェル名に設定されます

    • $ZSH_NAME zshに設定されています

    • kshには$PS3$PS4set がありますが、通常のBourneシェル(sh)には$PS1$PS2set しかありません。これは、一般的に区別するために最も困難なように思える- のみの間で、環境変数のセット全体で違いをshしてksh、我々は、Solarisのツゲにインストールされているで$ERRNO$FCEDIT$LINENO$PPID$PS3$PS4$RANDOM$SECONDS、と$TMOUT


$ {。sh.version}がksh93に設定されています
fpmurphy 2010

14
ps -p $$マシュースラッタリーは指摘します。の場合kshecho $KSH_VERSIONまたはecho ${.sh.version}
追って通知があるまで一時停止。

@デンマーク語-私のkshには現在KSH_VERSIONが設定されていません。echo ${.sh.version}「Bad Substitution」を返します。上記の私のソリューションを参照してください
DVK 2010

3
ps -ef | grep ……これは…のように100%信頼できるわけではありません。」 を介して単純な正規表現を使用するegrepか、またはgrep -eすべての目的と目的で100%の信頼性を簡単に実現できますps -ef | egrep "^\s*\d+\s+$$\s+"^作るには、必ず私たちは、行の先頭から開始している\d+、UID食べるの$$PIDと一致し、\s*かつ\s+、アカウントの他の部分との間に空白を確保&ため。
Slipp D. Thompson 2016

2
@ SlippD.ThompsonはGNU / Linuxでは機能しませんでした。しかし、これはps -ef | awk '$2==pid' pid=$$
うまくいく

98

ps -p $$

が関与しps -efgrep実行するソリューションが動作する場所(のPOSIXオプションpsをサポートする任意のUnixバリアント)で機能し、他の場所に出現する可能性がある一連の数字のgreppingによって導入される誤検知の影響を受けません。


12
一部のシェルには独自の組み込みバージョンがpsあり、理解できない-p場合があるため、を使用する必要があります/bin/ps -p $$
追って通知があるまで一時停止。

13
あなたが使用しなければならないものを$$除いてfish、私がよく知っているすべてのシェルは理解していますps -p %self
追って通知があるまで一時停止。

3
実際、などのハードパスに依存するべきではありません/bin/pspsに簡単に(実際には今日では非常に正常です)をにインストールできます/usr/bin$(which ps) -p $$より良い方法です。もちろん、これは魚では機能せず、おそらく他のいくつかの貝では機能しません。(which ps) -p %self魚だと思います。
Aron Cederholm 2014年

1
debian-slim Dockerコンテナーなどの一部の最小システムでは、psが存在しない場合があります。その場合、このアプローチは引き続き機能しますreadlink /proc/$$/exe
。– mxmlnkn

shでエミュレートされている場合bash、ps -pを/usr/bin/bash実行すると、次のように実行できます。sh
Ding-Yi Chen

45

試す

ps -p $$ -oargs=

または

ps -p $$ -ocomm=

4
これはいい短いものです。自分で使っていましたps -o fname --no-headers $$
アンヴァンロッサム2014年

ありがとう。これは、bash固有のコマンドを保護するスクリプトで使用するのに最適なオプションtest `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bashです。(私のスクリプトの次の行はcshと同等です。)
craq

1
サブシェル内からこれを行うと、親のPIDと実際のシェルプロセスを照合することにより、余分な行が誤って作成される可能性があることがわかりました。このために、私は使用-qの代わりに、-pSHELL=$(ps -ocomm= -q $$)
スティーブ・

35

ユーザーがBashでスクリプトを呼び出していることを確認するだけの場合:

if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi

1
これは上部に近いものでなければなりません。どうもありがとう。
Alex Skrypnyk 2014

4
それは質問に全く答えないので、それは上に近づくべきではありません。「スクリプトがbashで実行されているかどうかを確認する方法」という質問の場合は、投票します。
David FerenczyRogožan2014年

2
@DawidFerenczy-この質問は、そのフレーズを検索した場合の最高の結果です。長い目で見れば、答えは元の質問の答えではなく、人々が探しているものに答えることの方がはるかに重要だと思います。
ArtOfWarfare 2017年

3
さらに、tcshがbashから呼び出される場合、変数$ BASH tcsh 定義されます
18446744073709551615

これはとても便利です、ありがとう。これを少し変更して、これを次の2行目に置き#!/bin/bashますif [ ! -n "$BASH" ] ;then exec bash $0; fi。この行では、kshまたはshを使用して開始した場合でも、スクリプトはbashを使用して実行されます。私のユースケースではコマンドライン引数は必要ありませんが$0、必要に応じて後で追加できます。
joanis

20

あなたが試すことができます:

ps | grep `echo $$` | awk '{ print $4 }'

または:

echo $SHELL

6
grepの後にawkが続くポイントは何/pattern/ { action }ですか?
イェンス

#zshellエイリアスshell = 'echo $ {SHELL:t}'
SergioAraujo

4
$SHELL環境変数には、現在のユーザーのデフォルトとして設定されているシェルが含まれています。現在実行中のシェルを反映していません。またps -p $$、誤検知のため、$$をgrepping するよりも使用することをお勧めします。
David FerenczyRogožan2014年

$ SHELL環境。変数は、POSIX仕様で指定されている「親」シェルを指します 。SHELLこの変数は、ユーザーの優先コマンド言語インタープリターのパス名を表します。したがって、$ SHELLの値は現在のシェルではない可能性があります。
Theo

すべての内awkps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null

16

$SHELL常に現在のシェルを表示する必要はありません。呼び出されるデフォルトのシェルのみを反映しています。

上記をテストするにbashは、デフォルトのシェルであると言って、を試してecho $SHELLから、同じターミナルで他のシェル(KornShell(ksh)など)にアクセスしてを試してください$SHELL。どちらの場合も、結果はbashとして表示されます。

現在のシェルの名前を取得するには、を使用しcat /proc/$$/cmdlineます。そして、シェル実行可能ファイルへのパスreadlink /proc/$$/exe


8
...あなたが持っている限り/proc
tripleee 2013

10

psは最も信頼できる方法です。SHELL環境変数が設定されているとは限りません。設定されている場合でも、簡単に偽装される可能性があります。


12
+1 $ SHELLは、1つを生成する必要があるプログラムのデフォルトのシェルです。現在実行中のシェルを必ずしも反映しているわけではありません。
ジム・ルイス

8

現在のシェルを見つける簡単な方法があります。ランダムな文字列を入力するだけです(これはコマンドではありません)。失敗して「見つかりません」というエラーが返されますが、行の先頭ではどのシェルであるかが表示されます。

ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found

3
台本はダメです。echo 'aaaa' > script; chmod +x script; ./scriptギブ./script.sh: 1: aaaa: not found
スリムな

6

以下は常に実際に使用されるシェルを提供します-シェル名ではなく実際の実行可能ファイルの名前を取得します(つまり、のksh93代わりにksh)。の場合/bin/sh、実際に使用されているシェル、つまりが表示されdashます。

ls -l /proc/$$/exe | sed 's%.*/%%'

私は言う多くのことを知っています ls出力を処理してはならないとますが、特殊文字で名前が付けられている、または特殊文字で名前が付けられたディレクトリに配置されているシェルを使用する可能性はどのくらいありますか?これが依然として当てはまる場合は、別の方法で行う他の例がたくさんあります。

Toby Speightが指摘したように、これは同じことを実現するためのより適切でよりクリーンな方法です。

basename $(readlink /proc/$$/exe)

3
これは、提供していないすべてのUnicesでエラーが発生するだけ/procです。世界中のすべてがLinuxボックスであるわけではありません。
Jens

5
あなたがいる場合とされている Linux上で、我々は好むbasename $(readlink /proc/$$/exe)ls+ sed+ echo
Toby Speight 2016年

1
これにより、実際のシェルではなく、実際の実行可能ファイルの名前が表示されます。実際のシェルがbusyboxアプレット(たとえばash -> /bin/busybox)としてリンクされている場合、これは/ bin / busyboxを提供します。
stepe

6

私は多くの異なるアプローチを試しましたが、私にとって最良のものは:

ps -p $$

また、Cygwinで動作し、PID greppingとして誤検知を生成することはできません。いくつかのクリーニングを行うと、実行可能ファイル名のみが出力されます(パス付きのCygwinの下)。

ps -p $$ | tail -1 | awk '{print $NF}'

関数を作成して、覚える必要がないようにすることができます。

# Print currently active shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}

...そして単に実行しshellます。

DebianとCygwinでテストされました。


私のセットアップ(Cygwin | Windows 7)の時点では、あなたの答えが最高です。そして、 ps -p $$ | 尾-1 | gawk '{print $ NF}' は、$ bashなしでcmdからでも機能します。awkはbashからのみ機能するため、awkではなくgawkに注意してください。
WebComer 2018年

@WebComer申し訳ありませんが、「$ bashなしのcmdからでも機能する」という意味がわかりません。あなたはのWindowsのポートを持っているでしょうとしてもpstailそしてgawk、cmdが定義されていません$$、それはPIDだとして、それは間違いなく、プレーンCMDの下で働くことができないようにします。
David FerenczyRogožan19年

なぜ単純ではないのですps -p$$ -o comm=か?POSIXは、すべてのヘッダーを空に指定するとヘッダーが完全に抑制されると述べています。ps直接実行されるスクリプト(例:)をソースとする場合でも、(すべての回答と同様に)失敗しています#!/bin/sh
Toby Speight

5

親プロセスの印刷に関する私の変種:

ps -p $$ | awk '$1 == PP {print $4}' PP=$$

AWKが実行できるときに不要なアプリケーションを実行しないでください。


2
なぜ不要を実行awkするとき、ps -p "$$" -o 'comm='あなたのためにそれを行うことができますか?
Toby Speight

5

シェルとそれに対応するバージョンを見つける方法はたくさんあります。ここに私のために働いたいくつかがあります。

単純明快

  1. $> echo $ 0(プログラム名を指定します。私の場合、出力は-bashでした。。)
  2. $> $ SHELL(シェルに移動し、プロンプトでシェル名とバージョンを取得します。私の場合はbash3.2 $です。)
  3. $> echo $ SHELL(これにより、実行可能パスが得られます。私の場合は/ bin / bashです。)
  4. $> $ SHELL --version(これにより、ライセンスタイプを含むシェルソフトウェアに関する完全な情報が得られます)

ハックなアプローチ

$> *******(ランダムな文字のセットを入力すると、出力にシ​​ェル名が表示されます。私の場合、-bash:chapter2-a-sample-isomorphic-app:コマンドが見つかりません


3

あなたのことを提供する/bin/shサポートは、POSIX標準およびシステムで使用されているlsofコマンドがインストール-可能な代替がするlsof。この場合には可能性がpid2path-あなたはまた、使用(または適応)することができ、完全なパスを出力し、次のスクリプトは:

#!/bin/sh
# cat /usr/local/bin/cursh
set -eu
pid="$$"

set -- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login

unset echo env sed ps lsof awk getconf

# getconf _POSIX_VERSION  # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"
[ $? -ne 0 ] && { echo "'getconf PATH' failed"; exit 1; }
export PATH

cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }

awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"

ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"
[ "${ppid}"X = ""X ] && { echo "no ppid found"; exit 1; }

lsofstr="`lsof -p $ppid`" || 
   { printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }

printf "%s\n" "${lsofstr}" | 
   LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'

1
これは魚で機能します!しかし、私にとっては、-i(-> ignore environment)オプションが利用可能envかどうかを確認する行にあるため、bashで失敗しlsofます。それは失敗します:env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui

2

(特定のバージョンの)Bashを実行していることを確認したいだけの場合、そのための最良の方法は、 $BASH_VERSINFO配列変数です。(読み取り専用)配列変数としては、環境では設定できないため、現在のシェルから(もしあれば)確実に取得されます。

ただし、Bashはとして呼び出された場合の動作が異なるshため、$BASH環境変数の末尾がであるかどうかを確認する必要もあります/bash

-(アンダースコアではなく)で関数名を使用し、連想配列(Bash 4で追加)に依存する私が書いたスクリプトでは、次の健全性チェックを行っています(役立つユーザーエラーメッセージを含む)。

case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
    */bash@[456789])
        # Claims bash version 4+, check for func-names and associative arrays
        if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
            echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
            exit 1
        fi
        ;;
    */bash@[123])
        echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
        exit 1
        ;;
    *)
        echo >&2 "This script requires BASH (version 4+) - not regular sh"
        echo >&2 "Re-run as \"bash $CMD\" for proper operation"
        exit 1
        ;;
esac

最初のケースでは、機能に対する多少偏執的な機能チェックを省略し、将来のBashバージョンに互換性があると想定するだけで済みます。


2

fishシェルで動作する回答はありません(変数$$またははありません$0)。

(上のテスト私のためにこの作品をshbashfishkshcshtruetcsh、およびzsh、openSUSEの13.2):

ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'

このコマンドは、のような文字列を出力しますbash。ここでは、、、および(GNU拡張機能なしpstail、それをチェックするsedために追加--posixしてみます)のみを使用しています。これらはすべて標準のPOSIXコマンドです。私は確実tailに取り除くことができますが、私のsedfuはこれを行うのに十分な強さではありません。

このソリューションはOS Xでは機能しないため、移植性があまり高くないようです。


sed: invalid option -- 'E'はbash 3.2.51とtcsh 6.15.00に乗ります
craq

2

私の解決策:

ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1

これは、異なるプラットフォームおよびシェル間で移植可能でなければなりません。これは、使用するps他のソリューションと同様に、それは依存しませんsedawkとフィルター配管からジャンクから出て、ps自身がそうシェルは常に最後のエントリでなければならないこと。これにより、移植性のないPID変数に依存したり、正しい行や列を選択したりする必要がなくなります。

私は、Bash、Zシェルzsh)、およびfish(異なるPID変数を使用するため、fish専用の式を変更せずにこれらのソリューションのほとんどで機能しない)で、DebianおよびmacOSでテストしました。


1
echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.

どのようにあなたの現在のシェルが何であるかを知っているのですか?


3
これは親プロセスではなく、現在のプロセスです。
追って通知があるまで一時停止。

7
使用grep $$は信頼できません。ps -ef | awk -v pid=$$ '$2==pid { print $8 }'より良いですが、なぜ単に使用しないのps -p $$ですか?
musiphil 2013年

1

Mac OS X(およびFreeBSD)の場合:

ps -p $$ -axco command | sed -n '$p' 

2
使用中にこれを試してみzshました-bash
user137369

私のシステム(現在)では、bashとdashでテストされ、この戻り値mutt...:
F. Hauri

1

/ procディレクトリ構造から任意のPIDのそれぞれのコマンドラインを読み取ることができるため、「ps」の出力からPIDを取得する必要はありません。

echo $(cat /proc/$$/cmdline)

ただし、それは単に次のことよりも優れているわけではありません。

echo $0

名前が示すものと実際に異なるシェルを実行することについての1つのアイデアは、以前に取得した名前を使用してシェルからバージョンを要求することです。

<some_shell> --version

sh 終了コード2で失敗するようですが、他のユーザーは何か有用なものを提供します(ただし、私はそれらがないため、すべてを確認することはできません)。

$ sh --version
sh: 0: Illegal option --
echo $?
2

1

これは非常にクリーンなソリューションではありませんが、あなたが望むことを行います。

# MUST BE SOURCED..
getshell() {
    local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"

    shells_array=(
    # It is important that the shells are listed in descending order of their name length.
        pdksh
        bash dash mksh
        zsh ksh
        sh
    )

    local suited=false
    for i in ${shells_array[*]}; do
        if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
            shell=$i
            suited=true
        fi
    done

    echo $shell
}
getshell

今、あなたは使うことができます $(getshell) --version

ただし、これはKornShellのようなシェル(ksh)でのみ機能します。


1
「ただし、これはkshのようなシェルでのみ機能します。」これを実行するにシェルを検証する必要があると言っていますか?うーん...
jpaugh

@jpaugh、リストはのためのケースではない、このコードを調達シェルによって支持されなければならないdashyashあなたが使用している場合など、通常bashzshkshあなたがそのようなことを気にしてはならない-何でも、。
theoden8

bashを「kshのような」ものとして数えているのですか?とった。それはもっと理にかなっています
jpaugh

@jpaugh、まあ、それは私が意味したことです。なぜなら、kshの一連の機能は、ほとんどがbashの機能のサブセットだからです(ただし、これを徹底的にチェックしていません)。
theoden8

1

シェルがDash / Bashを使用しているかどうかを確認するには、次の手順を実行します。

ls –la /bin/sh

  • 結果が/bin/sh -> /bin/bash==>の場合、シェルはBashを使用しています。

  • 結果が/bin/sh ->/bin/dash==>の場合、シェルはDashを使用しています。

BashからDashに、またはその逆に変更する場合は、以下のコードを使用します。

ln -s /bin/bash /bin/sh (シェルをBashに変更)

:上記のコマンドの結果、「/ bin / shはすでに存在しています」というエラーが表示された場合は、/ bin / shを削除して、再試行してください。


0

そして私はこれを思いつきました

sed 's/.*SHELL=//; s/[[:upper:]].*//' /proc/$$/environ

これはLinuxでのみ機能します。MacOSでもBSDでもない!!
F.ハウリ

-1

以下のコマンドを使用してください。

ps -p $$ | tail -1 | awk '{print $4}'

最初の1つはナンセンスでecho $SHELLあり、あなたがやろうとしていることを正しく行います。$SHELL環境変数には現在実行中のシェルではなく、現在のユーザーのデフォルトシェルが含まれているため、2つ目も適切ではありません。たとえばbash、デフォルトのシェルとして設定している場合は、zshおよびを実行するとecho $SHELL、が出力されますbash
David FerenczyRogožan2014年

あなたは正しいDawid Ferenczyです。psコマンドを使用して現在のシェルを特定できます。[#ps -p $$ | 尾-1 | awk '{print $ 4}']。
Ranjithkumar T 2014

echo $SHELLごみの可能性があります: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
SaltwaterC

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.