現在作業しているシェルを確認するにはどうすればよいですか?
コマンドの出力ps
だけで十分でしょうか?
Unixのさまざまなフレーバーでこれをどのように行うことができますか?
現在のシェルの実行可能ファイルの名前を見つけるには、次の3つの方法があります。
シェルの実行可能ファイルがである場合、3つのアプローチすべてがだまされる可能性があることに注意してください。ただし、たとえば、/bin/sh
実際には名前が変更されています(これは頻繁に発生します)。bash
したがって、ps
出力が機能するかどうかの2番目の質問は、「常にではない」で答えられます。
echo $0
-プログラム名を出力します...シェルの場合は実際のシェルです。
ps -ef | grep $$ | grep -v grep
-これにより、実行中のプロセスのリストで現在のプロセスIDが検索されます。現在のプロセスはシェルであるため、含まれます。
リストにシェルのプロセスIDと同じ番号が含まれている他のプロセスがある可能性があるため、これは100%信頼できるわけではありませんps
。特に、そのIDが小さい場合(たとえば、シェルのPIDが「5」の場合)、同じ出力の「java5」または「perl5」grep
!)。これは、シェル名に依存できないことに加えて、「ps」アプローチの2番目の問題です。
echo $SHELL
-現在のシェルへのパスは、SHELL
任意のシェルの変数として保存されます。これに関する注意点は、シェルをサブプロセスとして明示的に起動した場合(たとえば、ログインシェルではない場合)、代わりにログインシェルの値を取得することです。それが可能であれば、ps
または$0
アプローチを使用してください。
ただし、実行可能ファイルが実際のシェルと一致しない場合(たとえば/bin/sh
、実際にはbashまたはksh)、ヒューリスティックが必要です。さまざまなシェルに固有の環境変数を次に示します。
$version
tcshに設定されています
$BASH
bashに設定されています
$shell
(小文字)は、cshまたはtcshの実際のシェル名に設定されます
$ZSH_NAME
zshに設定されています
kshにはとが$PS3
設定されてい$PS4
ますが、通常のBourneシェル(sh
)$PS1
にはとが$PS2
設定されています。これは一般的に区別するのが最も難しいように思われます-Solarisboxenにインストールした環境変数のセット全体の唯一の違いは、、、、、、、、、、、およびです。sh
ksh
$ERRNO
$FCEDIT
$LINENO
$PPID
$PS3
$PS4
$RANDOM
$SECONDS
$TMOUT
ps -p $$
ps -ef
を含むソリューションが( POSIXオプションgrep
をサポートするUnixバリアントで)実行する場所であればどこでも機能するはずであり、他の場所に表示される可能性のある一連の数字のgrepingによって導入される誤検知の影響を受けません。ps
試す
ps -p $$ -oargs=
また
ps -p $$ -ocomm=
ユーザーがBashでスクリプトを呼び出していることを確認したいだけの場合:
if [ -z "$BASH" ] ;then echo "Please run this script $0 with bash"; exit 1; fi
あなたが試すことができます:
ps | grep `echo $$` | awk '{ print $4 }'
または:
echo $SHELL
$SHELL
常に現在のシェルを表示する必要はありません。呼び出されるデフォルトのシェルのみを反映します。
上記をテストするには、たとえばbash
デフォルトのシェルを試しecho $SHELL
てから、同じターミナルで他のシェル(KornShell(ksh)など)にアクセスして試してください$SHELL
。どちらの場合も、結果はbashとして表示されます。
現在のシェルの名前を取得するには、を使用しcat /proc/$$/cmdline
ます。そして、によるシェル実行可能ファイルへのパスreadlink /proc/$$/exe
。
シェルとそれに対応するバージョンを見つける方法はたくさんあります。ここに私のために働いたいくつかがあります。
簡単
ハックなアプローチ
$> *******(ランダムな文字のセットを入力すると、出力にシェル名が表示されます。私の場合は-bash:chapter2-a-sample-isomorphic-app:コマンドが見つかりません)
psは最も信頼できる方法です。SHELL環境変数は、設定が保証されているわけではなく、設定されている場合でも、簡単になりすますことができます。
現在のシェルを見つけるための簡単なトリックがあります。ランダムな文字列を入力するだけです(これはコマンドではありません)。失敗して「見つかりません」エラーが返されますが、行の先頭に、それがどのシェルであるかが示されます。
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
私は多くの異なるアプローチを試しましたが、私にとって最良のアプローチは次のとおりです。
ps -p $$
また、Cygwinでも機能し、PIDgreppingとして誤検知を生成することはできません。いくつかのクリーニングを行うと、実行可能ファイル名(パス付きのCygwinの下)のみが出力されます。
ps -p $$ | tail -1 | awk '{print $NF}'
関数を作成して、覚える必要がないようにすることができます。
# Print currently active shell
shell () {
ps -p $$ | tail -1 | awk '{print $NF}'
}
...そして実行するだけshell
です。
DebianとCygwinでテストされました。
以下は、常に実際に使用されるシェルを示します。シェル名ではなく、実際の実行可能ファイルの名前を取得します(つまり、などksh93
の代わりにksh
)。の場合/bin/sh
、実際に使用されているシェルが表示されdash
ます。
ls -l /proc/$$/exe | sed 's%.*/%%'
出力は決して処理されるべきではないと言う人がたくさんいることは知っていls
ますが、特殊文字で名前が付けられた、または特殊文字で名前が付けられたディレクトリに配置されたシェルを使用する確率はどれくらいですか?それでもそうであれば、別の方法でそれを行う例は他にもたくさんあります。
Toby Speightが指摘しているように、これは同じことを達成するためのより適切でクリーンな方法です。
basename $(readlink /proc/$$/exe)
親プロセスの印刷に関する私の変種:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
AWKが実行できる場合は、不要なアプリケーションを実行しないでください。
がPOSIX標準を/bin/sh
サポートし、システムに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}'
私の解決策:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
これは、さまざまなプラットフォームやシェル間で移植可能である必要があります。他のソリューションと同じように使用しますが、またはにps
依存せず、配管やそれ自体からジャンクを除外するため、シェルは常に最後のエントリになります。このように、移植性のないPID変数に依存したり、適切な行と列を選択したりする必要はありません。sed
awk
ps
私はDebianとmacOSでBash、Zシェル(zsh
)、および魚をテストしました(これは、異なるPID変数を使用するため、特に魚の式を変更しない限り、これらのソリューションのほとんどでは機能しません)。
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バージョンに互換性があると想定することができます。
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
いずれの回答もfish
シェルでは機能しませんでした(変数$$
または$0
)はありません。
これは私にとってはうまくいきます(、、、、、、、、、および; openSUSE 13.2sh
でテスト済みbash
) :fish
ksh
csh
true
tcsh
zsh
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
このコマンドは、のような文字列を出力しますbash
。ここでは、、、およびのみを使用してps
いtail
ますsed
(GNU拡張機能なし。追加--posix
して確認してください)。これらはすべて標準のPOSIXコマンドです。確かtail
に取り除くことができますが、私のsed
fuはこれを行うのに十分な強さではありません。
このソリューションはOSXでは機能しないため、移植性が低いように思われます。:(
これはあまりクリーンなソリューションではありませんが、必要なことを実行します。
# 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)でのみ機能します。
シェルが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を削除して再試行してください。
私はNahuelFouilleulのソリューションが特に好きですが、組み込みのBashシェルを使用してUbuntu18.04で次のバリアントを実行する必要がありました。
bash -c 'shellPID=$$; ps -ocomm= -q $shellPID'
一時変数がない場合shellPID
、たとえば次のようになります。
bash -c 'ps -ocomm= -q $$'
私のために出力ps
します。たぶん、あなたはすべて非対話型モードを使用しているわけではありません、そしてそれは違いを生みますか?
Mac OS X(およびFreeBSD)の場合:
ps -p $$ -axco command | sed -n '$p'
/ procディレクトリ構造から任意のPIDのそれぞれのコマンドラインを読み取ることができるため、「ps」の出力からPIDを取得する必要はありません。
echo $(cat /proc/$$/cmdline)
ただし、それは単に次のことよりも優れているとは限りません。
echo $0
名前が示すものとは実際に異なるシェルを実行することについて、1つのアイデアは、以前に取得した名前を使用してシェルからバージョンを要求することです。
<some_shell> --version
sh
他の人が何か役に立つものを与える間、終了コード2で失敗するようです(しかし、私はそれらを持っていないので、私はすべてを確認することができません):
$ sh --version
sh: 0: Illegal option --
echo $?
2
varで取得してみませんか$SHELL
。単純なsedでパスを削除できます。
$ echo $SHELL | sed -E 's/^.*\/([aA-zZ]+$)/\1/g'
bash
MacOS、Ubuntu、CentOSでテスト済み
1つの方法は次のとおりです。
ps -p $$ -o exe=
これは、IMOを使用するよりも、-o args
または-o comm
別の回答で提案されているように優れています(これらは/bin/sh
、ダッシュやbashなどの特定のシェルを指す場合などのシンボリックリンクを使用する場合があります)。
上記は実行可能ファイルのパスを返しますが、/ usr-mergeのために、複数のパス(例/bin/bash
と /usr/bin/bash
)をチェックする必要がある場合があることに注意してください。
また、上記は完全にPOSIX互換ではないことに注意してください(POSIX psにはありませんexe
)。
以下のコマンドをご利用ください。
ps -p $$ | tail -1 | awk '{print $4}'
そして、私はこれを思いついた
sed 's/.*SHELL=//; s/[[:upper:]].*//' /proc/$$/environ
使用できますecho $SHELL|sed "s/\/bin\///g"
これは、Red Hat Linux(RHEL)、macOS、BSD、および一部のAIXでうまく機能します。
ps -T $$ | awk 'NR==2{print $NF}'
または、 pstreeが利用可能な場合は、次のものも機能するはずです。
pstree | egrep $$ | awk 'NR==2{print $NF}'