시스템에 로그인 할 때 bash readline을 vi 모드로 자동 설정하는 방법은 무엇입니까?


9

우리 팀은 수천 대의 Linux / Unix 머신을 담당하므로 루트 계정은 당연히 관리자간에 "공유"됩니다. 나는 vi 모드를 선호하고, 다른 사람들은 emacs 모드를 선호합니다.

다른 사람이 vi 모드를 사용하지 않고 SSH를 로그인 할 때 bash의 readline을 vi 모드로 설정하려면 어떻게해야합니까?

본질적으로 set -o vi매번 실제로 입력하지 않고 다른 사람들에게 강제로 입력하지 않고 로그인 후 효과를 원합니다 (emacs 모드가 나에게 성가신 것처럼 vi 모드는 그들에게 성가시다).

모든 사람이 sudo와 함께 자신의 계정을 사용하여 권한있는 명령을 실행하는 경우 이것이 문제가되지 않는다는 것을 알고 있지만, 통제 할 수없는 상황으로 인해 슬프게도 옵션이 아닙니다.


1
쉽지 않습니다. 한 가지 방법은 sshd의 로그 파일을 구문 분석하고 로그인하는 데 사용 된 키를 확인하는 것입니다. 클라이언트 측 솔루션, 예를 들어 로컬 readline 구성을 원격 측 또는 이와 유사한 방식으로 전달하는 방법을 원했습니다. set -o vi쉘을 제어하기 전에 자동으로 실행되는 어두운 OpenSSH 마법 .
Patrick

1
서버에 ssh가있는 클라이언트에서 Expect 스크립트를 사용하여 set -o vi명령을 보낸 다음 대화식 모드로 전환 할 수 있습니다.
Barmar

1
적어도 OpenSSH sshd는 다른 환경 변수를 설정하는 데 도움이되는 몇 가지 환경 변수를 설정합니다. 예를 들어, SSH_CLIENT연결 IP 주소 (및 클라이언트의 발신 / 수신 포트)가 포함됩니다. 이것을 다루면 ~/.bashrc당신을 위해서만 할 수 있습니다 .
Sami Laine

1
현상금은 "클라이언트 측 솔루션"을 찾고 있다고 말합니다. 그게 뭐죠? 유닉스 호스트에 ssh? 퍼티? 벌새? 자바 SSH? 시그윈?
Jeff Schaller

1
당신은 수만 대의 기계를 언급합니다. 하나의 머신 에서 시작 하여이 머신에 도달하겠습니까, 아니면 머신에서 머신으로 vi 모드를 전송하는 머신으로 홉핑 할 수 있습니까?
이카루스

답변:


3

공개 키 인증에서만 잘 작동하는 바보 같은 방법이 있습니다.

먼저 로컬 머신이 있는지 확인 nc하십시오.

둘째, 여전히 로컬 컴퓨터에서 스크립트를 작성하고 (내가 전화 할 것입니다. connect-to-server) ${PATH}* 알고 있는 곳에 두십시오 .

#!/bin/sh
# connect-to-server
ssh -q server-hostname "touch .yourname" </dev/null >/dev/null 2>&1
nc server-hostname 22

다음으로, .bashrc원격 시스템에서 다음을 포함하도록 수정하십시오 .

# partial .bashrc
if [ -f "${HOME}/.yourname" ]; then
  rm "${HOME}/.yourname"
  set -o vi
fi

마지막으로 로컬 컴퓨터로 돌아가서 다음 ~/.ssh/config을 추가하여 편집 하십시오.

# partial ssh config
Host serverNickname
  Hostname server-hostname
  ProxyCommand connect-to-server

이 접근법의 단점 (그리고 내가 바보라고 부르는 이유) :

  • 실제 프록시 명령이 필요한 경우 더 복잡해집니다.
  • 다른 사람이 로그인하는 것과 동시에 로그인하면 .yourname파일이 아직 삭제되지 않았을 가능성이 set -o vi있습니다.
  • 당신이 경우에 가장 중요한 것은, ssh serverNickname command다음 command(이후 실행 하겠지만 .bashrc공급되지 않습니다)가 .yourname이 의사 프록시를 사용하지 않는 ssh를 설정에서 두 번째 별명을 가지고 정중 될 수 있도록, 파일 유적.

실제로이 방법 의 유일한 장점은 ssh명령에 추가 인수를 제공 할 필요가 없다는 것입니다.


* 원격 시스템에서 아무것도 변경하지 않으려는 경우 임시 의사를 생성하는 대체 의사 프록시가 있습니다 .bashrc.

#!/bin/sh
# connect-to-server
ssh -q server-hostname 'ln .bashrc .bashrc.real; cat .bashrc.real <(printf "set -o vi; ln -f .bashrc.real .bashrc\n") >.bashrc.yourname; ln -f .bashrc.yourname .bashrc' </dev/null >/dev/null 2>&1
nc server-hostname 22

이것은 다른 방법과 동일한 단점이 있으므로 ssh의사 프록시를 호출하지 않는 구성 의 두 번째 별칭을 계속 원할 것 입니다.


아주 창의적인. 제안 해 주셔서 감사합니다. ProxyCommand를 이미 광범위하게 사용하고 있습니다 (일부 네트워크 / 호스트에 도달하려면 5 회 이상 홉이 필요함). 편집 : 당신의 생각이 가장 가깝다고 생각하는 모든 답변을 살펴보십시오.
Patrick

4

나는 갈 것이다 :

ssh server -t "bash --login -o vi"

그러나 그것은 당신이 관리자입니다, 당신은 더 깨끗한 것을 시도 할 수 있습니다. 예를 들어 SendEnv, 클라이언트 측 에서 ssh 옵션을 사용하여 특정 변수를 전송 AcceptEnv하고 sshd구성 (서버 측) 에서 사용 하여 변수 를 승인 한 후이를 기반으로 .bashrc변수의 값에 따라 동작을 조정 하도록 루트 파일을 수정할 수 있습니다.

이는 sshd모든 호스트 의 구성과 호스트 의 구성 을 변경하는 것을 의미합니다 .bashrc. 그러나 "독립적 인"방법은 아닙니다.


3

쉬운 클라이언트 측 솔루션 :

alias connect='ssh -t root@server "bash -o vi"'

이 실패합니다 루트의 쉘 초기화 스크립트를 명시 적으로 사용 set -o emacs또는 세트 EDITORemacs, 또는 루트의 경우 .initrc파일가 호출하는 emacs키 바인딩.

이 답변의 나머지 부분은 서버 측 솔루션에 관한 것입니다.


이것은 ssh기계에 들어가서 다음을 사용할 때 작동 합니다 sudo -i.

당신을 위해 /root/.bashrc:

if [[ -n "$SUDO_USER" ]] && [[ -f /root/.bashrc-"$SUDO_USER" ]]; then
  source /root/.bashrc-"$SUDO_USER"
fi

이를 통해 원하는대로 무엇이든 할 수 있는 개인 bashrc파일 을 가질 /root/.bashrc-patrick수 있습니다 set -o vi.

이것을 다음과 같이 rc 파일을 선택하는 다소 순진한 접근 방식과 결합하십시오 $SSH_CLIENT.

if [[ -n "$SUDO_USER" ]]; then
  person="$SUDO_USER"
elif [[ -n "$SSH_CLIENT" ]]; then

  case "$SSH_CLIENT" in
    192.168.216.100*)  person="joe" ;;
    192.168.216.120*)  person="patrick" ;;
    192.168.216.150*)  person="lindsey" ;;
  esac

fi

if [[ -n "$person" ]] && [[ -f /root/.bashrc-"$person" ]]; then
  source /root/.bashrc-"$person"
fi

이것은 항상 동일한 IP 주소에서 연결하는 경우에만 작동합니다 ...

사용중인 특정 SSH 키의 설명 필드를 사용하는 또 다른 방법은 SSH 에이전트를 서버로 전달하는 경우 작동합니다.

ssh_comment="$( ssh-add -L | grep -f /root/.ssh/authorized_keys | awk '{ print $NF '} | head -n 1 )"

서버에 연결하는 데 사용한 키의 설명 필드를 선택합니다. 은 head -n 1당신이 당신의 키의 몇 가지가 일어날 경우에이 authorized_keys파일을.

그런 다음 위 $ssh_comment$SUDO_USER접근 방식 과 마찬가지로 (주석 $ssh_comment이 경로 이름 인 경우 정리가 필요할 수 있음) 접근 방식 case과 같은 명령문을 통해 소스로 rc 파일을 선택하는 데 사용할 수 있습니다 $SSH_CLIENT.


일치 SSH_CLIENT하고 SUDO_USER현재 사용하고 있지만 서버 측 수정이 필요하며 특히 신뢰할 수는 없습니다. 나는 순수한 클라이언트 측 솔루션을 원했습니다. 그래도 제안 해 주셔서 감사합니다.
Patrick

3

서버 측에서 수정하지 않고 실제로 수행하려면 다음 중 하나를 수행하십시오.

1) 다음과 같은 것을 실행하십시오.

$ ssh user@host -t 'bash -l -o vi' 

나는 그 문서 가 너무 명확 하지 않다고 생각 하지만 -o option언급되어 작동하는 것 같습니다.

2) 사용 예상 :

expect스크립트 :

$ cat bashsetup.expect
#!/usr/bin/expect -f 

set user [lindex $argv 0];
set host [lindex $argv 1];

spawn ssh -l $user $host
expect "$ "
send "set -o vi\n"
interact

실행 가능하게 만들고 다음을 실행하십시오.

$ ./bashsetup.expect user testhost
spawn ssh -l user testhost
[motd, blahblah...]
user@testhost ~$ set -o vi
user@testhost ~$ 

이것은 원격 호스트 나 키에 암호를 입력하지 않고 로그인 할 수 있다고 가정합니다. 그렇지 않으면 expect 스크립트가 암호를 고려해야합니다. 그러나 많은 기계를 사용하면 이미 가지고있을 것입니다. 또한 달러 기호와 공백이 필요할 것으로 예상 되므로 프롬프트에 따라 편집하십시오 "# ".

프롬프트 전에 인쇄 된 내용에 동일한 문자가 포함되어 있으면 예상되는 문자열에보다 구체적인 내용을 포함해야합니다.

또한 해당 스크립트는에 대한 추가 인수 제공을 지원하지 않습니다 ssh. 명시적인 명령을 실행하려면 vi 모드가 필요하지 않지만 포트 터널링이 필요한 경우 문제가 될 수 있습니다.


그러나 어쨌든, 나는 이것이 별도의 계정 ( sudo또는 평범한 오래된 UID 0)을 가진 대상 시스템에서 해결되어야한다고 생각합니다 . 개인화 된 구성은 다른 많은 경우에도 유용하며 일반적으로 설정하려는 구성 파일과 환경 변수가 많이 있습니다. (관리자가의 값 $EDITOR이나 내용에 동의하지 않을 수도 있습니다 virc.)

또한 별도의 계정으로 사용자를 제거하는 것이 더 쉬울 것입니다.

모든 호스트에서 파일을 동기화하는 어떤 방법도 하찮게 같은로 로그인을 허용함으로써이 문제를 해결 것 ssh -t user@host 'patricks_shell.sh'ssh -t user@host 'bash --rcfile patrick.rc'.


나는 expect 사용을 생각했지만 이미 질문에서 지적했듯이 문제는 프롬프트가 시작되는 고유 한 것과 일치합니다 interact. 존재하지 않으면 프로파일의 motds / output과 마찬가지로 프롬프트가 다를 수 있습니다. 그래도 제안 해 주셔서 감사합니다.
Patrick

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.