現在作業中のシェルをどのように判断できますか?
ps
コマンドの出力だけで十分でしょうか?
Unixの異なるフレーバーでこれをどのように行うことができますか?
現在作業中のシェルをどのように判断できますか?
ps
コマンドの出力だけで十分でしょうか?
Unixの異なるフレーバーでこれをどのように行うことができますか?
回答:
現在のシェルの実行可能ファイルの名前を見つけるには、3つの方法があります。
シェルの実行可能ファイルがである場合、3つのアプローチすべてがだまされる可能性がありますが/bin/sh
、実際にはbash
、たとえば名前が変更されています(これは頻繁に発生します)。
したがって、ps
出力が行うかどうかについての2番目の質問は、「常にではない」で答えられます。
echo $0
-プログラム名を出力します...シェルの場合は実際のシェルです。
ps -ef | grep $$ | grep -v grep
-実行中のプロセスのリストから現在のプロセスIDを探します。現在のプロセスはシェルなので、含まれます。
これは100%信頼できるものではありません。他のプロセスにps
シェルのプロセスIDと同じ番号が含まれている可能性があるため、特にそのIDが小さい場合(たとえば、シェルのPIDが「5」の場合)、プロセスが呼び出されることがあります。同じgrep
出力で「java5」または「perl5」!)。これは、シェル名に依存できないことに加えて、「ps」アプローチの2番目の問題です。
echo $SHELL
-現在のシェルへのパスは、SHELL
任意のシェルの変数として保存されます。この警告は、シェルをサブプロセスとして明示的に起動した場合(たとえば、ログインシェルではない場合)、代わりにログインシェルの値を取得することです。それが可能である場合は、ps
または$0
アプローチを使用してください。
ただし、実行可能ファイルが実際のシェルと一致しない場合(たとえば/bin/sh
、実際にはbashまたはksh)、ヒューリスティックが必要です。以下は、さまざまなシェルに固有の環境変数です。
$version
tcshに設定されている
$BASH
バッシュに設定されています
$shell
(小文字)は、cshまたはtcshで実際のシェル名に設定されます
$ZSH_NAME
zshに設定されています
kshには$PS3
と$PS4
set がありますが、通常のBourneシェル(sh
)には$PS1
と$PS2
set しかありません。これは、一般的に区別するために最も困難なように思える- のみの間で、環境変数のセット全体で違いをsh
してksh
、我々は、Solarisのツゲにインストールされているで$ERRNO
、$FCEDIT
、$LINENO
、$PPID
、$PS3
、$PS4
、$RANDOM
、$SECONDS
、と$TMOUT
。
echo ${.sh.version}
「Bad Substitution」を返します。上記の私のソリューションを参照してください
ps -ef | grep …
…これは…のように100%信頼できるわけではありません。」 を介して単純な正規表現を使用するegrep
か、またはgrep -e
すべての目的と目的で100%の信頼性を簡単に実現できますps -ef | egrep "^\s*\d+\s+$$\s+"
。^
作るには、必ず私たちは、行の先頭から開始している\d+
、UID食べるの$$
PIDと一致し、\s*
かつ\s+
、アカウントの他の部分との間に空白を確保&ため。
ps -ef | awk '$2==pid' pid=$$
ps -p $$
が関与しps -ef
、grep
実行するソリューションが動作する場所(のPOSIXオプションps
をサポートする任意のUnixバリアント)で機能し、他の場所に出現する可能性がある一連の数字のgreppingによって導入される誤検知の影響を受けません。
ps
あり、理解できない-p
場合があるため、を使用する必要があります/bin/ps -p $$
。
$$
除いてfish
、私がよく知っているすべてのシェルは理解していますps -p %self
。
/bin/ps
。ps
に簡単に(実際には今日では非常に正常です)をにインストールできます/usr/bin
。$(which ps) -p $$
より良い方法です。もちろん、これは魚では機能せず、おそらく他のいくつかの貝では機能しません。(which ps) -p %self
魚だと思います。
readlink /proc/$$/exe
sh
でエミュレートされている場合bash
、ps -pを/usr/bin/bash
実行すると、次のように実行できます。sh
試す
ps -p $$ -oargs=
または
ps -p $$ -ocomm=
ps -o fname --no-headers $$
。
test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bash
です。(私のスクリプトの次の行はcshと同等です。)
-q
の代わりに、-p
:SHELL=$(ps -ocomm= -q $$)
ユーザーがBashでスクリプトを呼び出していることを確認するだけの場合:
if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi
#!/bin/bash
ますif [ ! -n "$BASH" ] ;then exec bash $0; fi
。この行では、kshまたはshを使用して開始した場合でも、スクリプトはbashを使用して実行されます。私のユースケースではコマンドライン引数は必要ありませんが$0
、必要に応じて後で追加できます。
あなたが試すことができます:
ps | grep `echo $$` | awk '{ print $4 }'
または:
echo $SHELL
/pattern/ { action }
ですか?
$SHELL
環境変数には、現在のユーザーのデフォルトとして設定されているシェルが含まれています。現在実行中のシェルを反映していません。またps -p $$
、誤検知のため、$$をgrepping するよりも使用することをお勧めします。
awk
、ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
$SHELL
常に現在のシェルを表示する必要はありません。呼び出されるデフォルトのシェルのみを反映しています。
上記をテストするにbash
は、デフォルトのシェルであると言って、を試してecho $SHELL
から、同じターミナルで他のシェル(KornShell(ksh)など)にアクセスしてを試してください$SHELL
。どちらの場合も、結果はbashとして表示されます。
現在のシェルの名前を取得するには、を使用しcat /proc/$$/cmdline
ます。そして、シェル実行可能ファイルへのパスreadlink /proc/$$/exe
。
/proc
。
現在のシェルを見つける簡単な方法があります。ランダムな文字列を入力するだけです(これはコマンドではありません)。失敗して「見つかりません」というエラーが返されますが、行の先頭ではどのシェルであるかが表示されます。
ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found
echo 'aaaa' > script; chmod +x script; ./script
ギブ./script.sh: 1: aaaa: not found
以下は常に実際に使用されるシェルを提供します-シェル名ではなく実際の実行可能ファイルの名前を取得します(つまり、のksh93
代わりにksh
)。の場合/bin/sh
、実際に使用されているシェル、つまりが表示されdash
ます。
ls -l /proc/$$/exe | sed 's%.*/%%'
私は言う多くのことを知っています ls
出力を処理してはならないとますが、特殊文字で名前が付けられている、または特殊文字で名前が付けられたディレクトリに配置されているシェルを使用する可能性はどのくらいありますか?これが依然として当てはまる場合は、別の方法で行う他の例がたくさんあります。
Toby Speightが指摘したように、これは同じことを実現するためのより適切でよりクリーンな方法です。
basename $(readlink /proc/$$/exe)
/proc
です。世界中のすべてがLinuxボックスであるわけではありません。
basename $(readlink /proc/$$/exe)
にls
+ sed
+ echo
。
ash -> /bin/busybox
)としてリンクされている場合、これは/ bin / busyboxを提供します。
私は多くの異なるアプローチを試しましたが、私にとって最良のものは:
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でテストされました。
ps
、tail
そしてgawk
、cmdが定義されていません$$
、それはPIDだとして、それは間違いなく、プレーンCMDの下で働くことができないようにします。
ps -p$$ -o comm=
か?POSIXは、すべてのヘッダーを空に指定するとヘッダーが完全に抑制されると述べています。ps
直接実行されるスクリプト(例:)をソースとする場合でも、(すべての回答と同様に)失敗しています#!/bin/sh
。
親プロセスの印刷に関する私の変種:
ps -p $$ | awk '$1 == PP {print $4}' PP=$$
AWKが実行できるときに不要なアプリケーションを実行しないでください。
awk
するとき、ps -p "$$" -o 'comm='
あなたのためにそれを行うことができますか?
シェルとそれに対応するバージョンを見つける方法はたくさんあります。ここに私のために働いたいくつかがあります。
単純明快
ハックなアプローチ
$> *******(ランダムな文字のセットを入力すると、出力にシェル名が表示されます。私の場合、-bash:chapter2-a-sample-isomorphic-app:コマンドが見つかりません)
あなたのことを提供する/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}'
-i
(-> ignore environment)オプションが利用可能env
かどうかを確認する行にあるため、bashで失敗しlsof
ます。それは失敗します:env -i PATH="${PATH}" type lsof
->env: ‘type’: No such file or directory
(特定のバージョンの)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バージョンに互換性があると想定するだけで済みます。
fish
シェルで動作する回答はありません(変数$$
またははありません$0
)。
(上のテスト私のためにこの作品をsh
、bash
、fish
、ksh
、csh
、true
、tcsh
、およびzsh
、openSUSEの13.2):
ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'
このコマンドは、のような文字列を出力しますbash
。ここでは、、、および(GNU拡張機能なしps
でtail
、それをチェックするsed
ために追加--posix
してみます)のみを使用しています。これらはすべて標準のPOSIXコマンドです。私は確実tail
に取り除くことができますが、私のsed
fuはこれを行うのに十分な強さではありません。
このソリューションはOS Xでは機能しないため、移植性があまり高くないようです。
sed: invalid option -- 'E'
はbash 3.2.51とtcsh 6.15.00に乗ります
私の解決策:
ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1
これは、異なるプラットフォームおよびシェル間で移植可能でなければなりません。これは、使用するps
他のソリューションと同様に、それは依存しませんsed
かawk
とフィルター配管からジャンクから出て、ps
自身がそうシェルは常に最後のエントリでなければならないこと。これにより、移植性のないPID変数に依存したり、正しい行や列を選択したりする必要がなくなります。
私は、Bash、Zシェル(zsh
)、およびfish(異なるPID変数を使用するため、fish専用の式を変更せずにこれらのソリューションのほとんどで機能しない)で、DebianおよびmacOSでテストしました。
echo $$ # Gives the Parent Process ID
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.
grep $$
は信頼できません。ps -ef | awk -v pid=$$ '$2==pid { print $8 }'
より良いですが、なぜ単に使用しないのps -p $$
ですか?
Mac OS X(およびFreeBSD)の場合:
ps -p $$ -axco command | sed -n '$p'
zsh
ました-bash
。
mutt
...:
/ procディレクトリ構造から任意のPIDのそれぞれのコマンドラインを読み取ることができるため、「ps」の出力からPIDを取得する必要はありません。
echo $(cat /proc/$$/cmdline)
ただし、それは単に次のことよりも優れているわけではありません。
echo $0
名前が示すものと実際に異なるシェルを実行することについての1つのアイデアは、以前に取得した名前を使用してシェルからバージョンを要求することです。
<some_shell> --version
sh
終了コード2で失敗するようですが、他のユーザーは何か有用なものを提供します(ただし、私はそれらがないため、すべてを確認することはできません)。
$ sh --version
sh: 0: Illegal option --
echo $?
2
これは非常にクリーンなソリューションではありませんが、あなたが望むことを行います。
# 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
、yash
あなたが使用している場合など、通常bash
、zsh
、ksh
あなたがそのようなことを気にしてはならない-何でも、。
ksh
の一連の機能は、ほとんどがbash
の機能のサブセットだからです(ただし、これを徹底的にチェックしていません)。
シェルが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を削除して、再試行してください。
以下のコマンドを使用してください。
ps -p $$ | tail -1 | awk '{print $4}'
echo $SHELL
あり、あなたがやろうとしていることを正しく行います。$SHELL
環境変数には現在実行中のシェルではなく、現在のユーザーのデフォルトシェルが含まれているため、2つ目も適切ではありません。たとえばbash
、デフォルトのシェルとして設定している場合は、zsh
およびを実行するとecho $SHELL
、が出力されますbash
。
echo $SHELL
ごみの可能性があります: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
これは、Red Hat Linux(RHEL)、macOS、BSD、および一部のAIXでうまく機能します。
ps -T $$ | awk 'NR==2{print $NF}'
または、pstreeが利用可能な場合は、次のコードも機能するはずです。
pstree | egrep $$ | awk 'NR==2{print $NF}'
!
置換を行うかどうか)は、シェルの名前を見つけるよりもおそらく移植性があります。ローカルカスタムは、あなたが名前の何か実行している場合があります/bin/sh
実際など灰、ダッシュ、bashの、可能性