私は現在、複数のマシンで使用されるかなり複雑なbash構成をセットアップしています。 SSH経由でログインしているか、ローカルマシンでログインしているかを判断できるかどうかを確認します。この方法で、たとえば、その事実に応じていくつかのエイリアスを設定できます。リモートサーバーを停止することは最善の方法ではない可能性があるため、halt
からrestart
へのエイリアスのように。
これまで私が知っているのは、ssh経由でログインしたときに環境変数SSH_CLIENT
が設定されていることです。残念ながら、Sudo -s
でスーパーユーザーシェルを起動すると、この変数は破棄されます。また、すべての環境変数を新しいシェル環境にコピーするようにSudoに指示するパラメーターをSudoに渡すことができることも知っていますが、これを実行したくない場合は、別の方法がありますか?
「w」または「who」コマンド出力を使用できます。 ssh経由で接続すると、ソースIPが表示されます。
これが私が nix.stackexchange で見つけた素晴らしい答えです:
SSH_CLIENT
またはSSH_TTY
の1つが定義されている場合、それはsshセッションです。ps -o comm= -p $PPID
で確認できます。 sshd
の場合は、sshセッションです。if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
SESSION_TYPE=remote/ssh
else
case $(ps -o comm= -p $PPID) in
sshd|*/sshd) SESSION_TYPE=remote/ssh;;
esac
fi
あなたはSSH_*
からenv_keep
in sudoers
で、他のユーザーに切り替えているときにこれを検出できるようにします。
Shellが直接sshdの子プロセス(n> 1層ではない)であるかどうかを知りたい場合は、
cat/proc/$ PPID/status |頭-1 |カット-f2
sshd
か、現在のシェルの親プロセス名が何であるかがわかります。
はい、他の人が述べたように、情報はwho am i
の出力で括弧内にIPが存在することを示しています。
Bash正規表現を使用してそれを検出できます。
if [[ $(who am i) =~ \([0-9\.]+\)$ ]]; then echo SSH; else echo no; fi
問題についての考え方を考え直したいと思います。問題は、「特定のコマンドをオフにしたいので、SSH経由でログインしているかどうか」ではありません。 「コンソールにログインしたので、特定のコマンドを有効にする」です。
ここで他の人からのヒントに基づいて、私は以下を思いつきました。
それはキャッシングに変数を使用します-私は私のシェルテーマでそれを使用しています。
is_ssh() {
(( $+SSH_CLIENT )) && return
if ! (( $+_ZSH_IS_SSH )); then
# "who am i" displays current user from utmp(5). This will be empty for
# a "normal" terminal. With Konsole, it is ":0" for display :0,
# for ssh it is the hostname and with tmux sth like "tmux(PID).ID".
local whoami="$(who am i)"}
local Host="${whoami#*\(*}"
[[ -n $Host && $Host != tmux* && $Host != :* ]]
_ZSH_IS_SSH=$?
fi
return $_ZSH_IS_SSH
}
出典:is_ssh
in https://github.com/blueyed/oh-my-zsh/blob/master/themes/blueyed.zsh-theme#L51-6 。
ログインの最初のレベルにいる場合、他のすべての回答が機能します。しかし、ログイン後に「su」または「Sudo」を実行した場合(私の場合、セキュリティ上の理由でシェルなしのユーザーアカウントに切り替えるには、以下を実行する必要がありました:Sudo su-<userid> -s/bin/bash -l)、それらのソリューションは失敗します。
以下は普遍的な解決策です。 pstreeを使用して、親としてsshdをチェックします。
if pstree -p | egrep --quiet --extended-regexp ".*sshd.*\($$\)"; then
echo "I am remote."
else
echo "I am local."
fi
--quietを削除した場合のegrepの出力を次に示します。リモート接続されている場合に一致する階層全体が表示されます。
| |-sshd(18599)---sshd(18603)---bash(18604)---Sudo(18823)---bash(18824)-+-egrep(22417)
シェルの親コマンドラインを探して再帰します。多分次のようなもの:
#!/usr/bin/env bash
## Find out how I'm logged in
# Tested on RHEL5.5
PD=${1:-$$}
ME=`basename $0`
## Read the Shell's PPID
PAR=`ps --no-headers -p $PD -o ppid`
## CMDLINE can contain stuff like the following:
# /sbin/getty-838400tty4 // logged in at a console
# gnome-terminal // logged in Gnome Terminal
# -bash // in a subshell
# su- // we became another user using su
# sshd: jc@pts/1 // logged in over ssh
# login // logged in terminal or serial device
eval `python - << __EOF__
import re
f = open("/proc/${PAR}/cmdline", 'r')
ln = f.readline()
if re.search(r'^ssh', ln):
print "echo Logged in via ssh"
if re.search(r'getty.*?tty', ln):
print "echo Logged in console"
if re.search("gnome-terminal", ln):
print "echo Logged in Gnome"
if re.search(r'^login', ln):
print "echo Logged in console"
if re.search(r'^-?bash', ln) or re.search(r'^su', ln):
print "./$ME $PAR"
f.close()
__EOF__
`
実際に機能するように編集されました:)
この答えは非常にvery Linux固有であることに注意してください。
parent_pid=$$
while [[ -z "${tty_bits-}" || $tty_bits -ne 0 ]]; do
read initiator_name parent_pid tty_bits < <(
awk '{ print substr($2, 2, length($2) - 2) " " $4 " " $7 }' /proc/$parent_pid/stat
)
done
echo $initiator_name
これは重要な仮定になります。ログインプロセスには制御TTYがありません。このコードを実行する前に、あなたがhave制御TTYであるかどうかを確認する必要があります(要件に基づいて、とにかく安全な賭けです)。
コードは、制御TTYを持たないプロセスが見つかるまで、プロセスツリーを上方向に反復します。 $initiator_name
は、このプロセスの名前になります( "sshd"など)。