bashrc가 현재 쉘이 대화식인지 여부를 확인하는 이유는 무엇입니까?


62

내 아치에 설치 /etc/bash.bashrc하고 /etc/skel/.bashrc이 줄을 포함 :

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

데비안 /etc/bash.bashrc에는 :

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

그리고 /etc/skel/.bashrc:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

man bash그러나 에 따르면 , 비 대화식 쉘은이 파일들을 읽지 못한다.

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file
   name.

올바르게 이해하면 *.bashrc파일 BASH_ENV을 가리 키도록 설정된 경우에만 파일을 읽 습니다. 이것은 우연히 일어날 수 없으며 누군가가 변수를 명시 적으로 설정 한 경우에만 발생합니다.

편리한 스크립트 .bashrc를 설정 하여 사용자가 자동으로 스크립트를 제공 할 수있는 가능성을 깨뜨리는 것 같습니다 BASH_ENV. bash가 명시 적으로 지시하지 않는 한 비 대화식으로 실행될 때 bash가 이러한 파일을 읽지 않는다고 가정하면 기본 *bashrc파일에서 허용하지 않는 이유는 무엇입니까?


5
실용적인 대답은 오류없이 SCP 실패
Gilles

답변:


69

이것은 몇 주 전에 여기에 게시 할 질문입니다. terdon 과 마찬가지로 a .bashrc는 대화 형 Bash 셸에서만 제공되므로 .bashrc대화 형 셸에서 실행 중인지 확인할 필요가 없습니다 . 혼란스럽게도, 내가 사용하는 모든 배포판 (Ubuntu, RHEL 및 Cygwin)에는 현재 셸이 대화 형인지 확인하기 위해 몇 가지 유형의 검사 (테스트 $-또는 $PS1)가있었습니다. 화물 컬트 프로그래밍이 마음에 들지 않으므로이 코드의 목적을 이해하기 시작했습니다 .bashrc.

Bash는 원격 쉘을위한 특별한 경우를 가지고 있습니다

문제를 조사한 후 원격 쉘 이 다르게 취급 된다는 것을 발견했습니다 . 비 대화식 Bash 셸은 일반적으로 ~/.bashrc시작시 명령을 실행하지 않지만 원격 셸 데몬 이 셸을 호출 하면 특별한 경우가 발생합니다 .

Bash는 원격 쉘 데몬 (일반적 rshd으로 또는 보안 쉘 데몬)에 의해 실행될 때와 같이 표준 입력이 네트워크 연결에 연결된 상태에서 언제 실행되고 있는지 확인합니다 sshd. Bash가 이러한 방식으로 실행되고 있다고 판단되면 해당 파일이 존재하고 읽을 수있는 경우 ~ / .bashrc에서 명령을 읽고 실행합니다. 로 호출하면이 작업을 수행하지 않습니다 sh. --norc옵션이 동작을 억제하기 위해 사용 될 수 있으며, --rcfile옵션을 읽을 수 있도록 다른 파일을 강제로 사용할 수 있지만, 어느 쪽 rshdsshd일반적으로 그 옵션을 사용하여 쉘을 호출하거나 지정 할 수 있습니다.

리모콘의 시작 부분에 다음을 삽입하십시오 .bashrc. (경우 .bashrc에 의해 공급된다 .profile거나 .bash_profile, 일시적으로 잠시 테스트를 비활성화) :

echo bashrc
fun()
{
    echo functions work
}

다음 명령을 로컬로 실행하십시오.

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • 없음 은 셸이 비대화 형임 i$-나타냅니다 .
  • 선행 없음 은 쉘이 로그인 쉘 이 아님 -$0나타냅니다 .

리모트에 정의 된 쉘 기능 .bashrc도 실행할 수 있습니다.

$ ssh remote_host fun
bashrc
functions work

에 대한 인수로 명령이 지정된 경우 에만 소스 ~/.bashrc가 있음을 알았 습니다 . 이것은 일반 로그인 쉘을 시작하는 데 사용 되거나 실행될 때 ( 이러한 파일 중 하나에 의해 명시 적으로 수행 된 경우에만 제공됨) 의미가 있습니다.sshssh.profile.bash_profile.bashrc

.bashrc(비 대화식) 원격 명령을 실행할 때 소스 를 얻을 수있는 주요 이점 은 쉘 기능을 실행할 수 있다는 것입니다. 그러나 일반적인 명령의 대부분은 .bashrc대화식 셸에만 관련이 있습니다. 예를 들어, 셸이 대화식이 아니면 별칭이 확장되지 않습니다.

원격 파일 전송이 실패 할 수 있음

이 경우 일반적으로 문제가되지 않는다 rsh또는 ssh대화 형 로그인 쉘하거나 (non-interactive) 형 모드 쉘이 명령을 실행하는 데 사용되는을 시작하는 데 사용됩니다. 그러나, 문제가 될 수 있습니다 와 같은 프로그램 rcp, scpsftp그 사용 원격 셸을 데이터를 전송.

scp명령을 사용할 때 원격 사용자의 기본 셸 (예 : Bash)이 암시 적으로 시작된 것으로 나타났습니다 . 매뉴얼 페이지에는 이에 대한 언급이 없으며 데이터 전송에 scp사용 되는 언급 만 ssh있습니다. 이는 표준 출력으로 인쇄하는 명령이 포함 된 경우 .bashrc파일 전송이 실패합니다 (예 : scp가 오류없이 실패 함) .

15 년 전에에서이 관련 레드햇 버그 리포트를 참조 SCP 휴식을 / etc / bashrc에있는 echo 명령있다 (결국 같은 폐쇄되었다 WONTFIX).

scp그리고 sftp실패

SCP (보안 사본)SFTP (보안 파일 전송 프로토콜) 에는 전송중인 파일에 대한 정보를 교환하기 위해 로컬 및 원격 엔드에 대한 자체 프로토콜이 있습니다. 원격 끝에서 예기치 않은 텍스트가 프로토콜의 일부로 잘못 잘못 해석되어 전송이 실패합니다. 달팽이 책FAQ 에 따르면

종종 어떻게됩니까하지만, 서버 중 하나를 시스템의 문이나 사용자 별 쉘 시작 파일 (가되어 .bashrc, .profile, /etc/csh.cshrc, .login구성 로그인에 출력 문자 메시지 같은 (인간이 읽을 수 등) fortune, echo "Hi there!", 기타.).

이러한 코드는 tty표준 입력에 첨부 된 경우 대화식 로그인에서만 출력을 생성해야합니다 . 이 테스트를 수행하지 않으면 다음과 같은 문자 메시지가 포함되지 않은 위치에 삽입됩니다.이 경우 scp2/ sftp와 사이의 프로토콜 스트림을 오염시킵니다 sftp-server.

쉘 시작 파일이 전혀 관련이없는 이유는 sshd 사용자 대신 프로그램을 시작할 때 (예 : / bin / sh -c "command") 사용자의 쉘을 사용하기 때문입니다. 이것은 유닉스 전통이며 다음과 같은 장점이 있습니다.

  • 원격 명령이 실행될 때 사용자의 일반적인 설정 (명령 별칭, 환경 변수, umask 등)이 적용됩니다.
  • 계정 셸을 / bin / false로 설정하여 계정을 사용하지 않도록 설정하는 일반적인 방법은 어떤 이유로 인증이 여전히 우연히 성공하는 경우 소유자가 명령을 실행하지 못하게합니다.

SCP 프로토콜 세부 사항

SCP가 작동하는 방법의 세부 사항에 관심이있는 사람들을 위해, 나는 흥미로운 정보를 발견 SCP가 프로토콜 작동 방법 에 대한 자세한 포함하는 원격 측에 수다 쉘 프로파일과 SCP 실행을? :

예를 들어, 이것을 원격 시스템의 쉘 프로파일에 추가하면 발생할 수 있습니다.

에코 ""

왜 그냥 걸려? 그건 어떻게하는 방식에서 오는 scp소스 모드가 처음 프로토콜 메시지의 확인을 기다립니다. 이진 0이 아닌 경우 원격 문제를 알리고 새 줄이 도착할 때까지 더 많은 문자가 오류 메시지를 표시 할 때까지 기다립니다. 첫 번째 줄 이후에 다른 줄을 새로 인쇄하지 않았기 때문에 로컬 scp은에 계속 연결되어 read(2)있습니다. 그 동안, 쉘 프로파일이 원격 측에서 처리 된 후 scp싱크 모드에서 시작되어 싱크 모드가 시작 read(2)되어 데이터 전송 시작을 나타내는 2 진 0을 대기합니다.

결론 / TLDR

일반적인 문장의 대부분은 .bashrc대화식 쉘에만 유용합니다 . rsh또는로 원격 명령을 실행할 때는 그렇지 않습니다 ssh. 대부분의 이러한 상황, 쉘 변수, 별칭을 설정하고 바람직하지 않은 함수를 정의에서 - 및 인쇄 텍스트 밖으로 표준을 같은 프로그램을 사용하여 파일을 전송하는 경우 적극적으로 유해 scp하거나 sftp. 현재 쉘이 비 대화식인지 확인한 후 종료하는 것이 가장 안전한 동작입니다 .bashrc.


좋은 기사. 하지만 난 그걸로해야합니까? 내가 .bashrc에 의해 확인하지만 여전히 0 코드로 종료 scp를해야합니까 원격 상자에 아무 것도 복사하지 마십시오
SES

@ses 상황을보다 자세하게 설명 할 수있는 새로운 질문을하는 것이 가장 좋습니다.
Anthony G-Monica에 대한 정의

16

매뉴얼 페이지 bash는 다음 .bashrc과 같이 비 대화식 원격 쉘의 소스도 언급하지 않습니다.

ssh hostname command

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1010

 COMMAND        EXECUTE BASHRC
 --------------------------------
 bash -c foo        NO
 bash foo           NO
 foo                NO
 rsh machine ls     YES (for rsh, which calls 'bash -c')
 rsh machine foo    YES (for shell started by rsh) NO (for foo!)
 echo ls | bash     NO
 login              NO
 bash               YES

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1050

          /* If we were run by sshd or we think we were run by rshd, execute
             ~/.bashrc if we are a top-level shell. */
          if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
            {
              maybe_execute_file (SYS_BASHRC, 1);
              maybe_execute_file (bashrc_file, 1);

.bash_profile (또는 .profile)에서 .bashrc를 제공합니까?
glenn jackman

예,하지만 요점이 아닙니다. 공란 .bash_profile은 같은 행동을 보일 것입니다.
Mikel

그것이 무엇을 보여주는 지 잘 모르겠습니다. 당신은 rsh(내가 사용한 적이없는) 출처 를 말하는가 ~/.bashrc? 그리고 확장명으로 리눅스 배포판 bash은 누군가가 rsh? 어쨌든 로그인 쉘이므로 ssh server터치하지 않아야 .bashrc합니다. 귀하의 시스템이 ~ / .bashrc를 제공하는 시스템 중 하나가 아니라면 아닙니다 ~/.profile. 그리고 그렇게 ssh server command해서는 안됩니다. 확실히 내 시스템에는 없습니다.
terdon

2
아니요. bash소스가 아닌 rsh소스에 연결했습니다. :)이 의견도 ssh매우 오래 전에 쓰여졌습니다. 더 많은 출처로 업데이트 된 답변을 참조하십시오.
Mikel

아, 도움이됩니다. 감사합니다. 그래도 어떻게 테스트합니까? 나는 (대화식 쉘 테스트 전에) echo맨 위에 /etc/bash.bashrcand를 추가하려고 시도한 ~/.bashrc다음 실행중인 ssh server hostname동안 대상 컴퓨터에 ssh를 추가 hostname했지만 내 에코 중 하나를 보지 못했습니다. 내 shell_level(무엇이든) 그렇지 <2않습니까?
terdon

5

일반적 .bashrc으로 사용자가 쉘의 사용자 정의 구성을 저장하는 위치입니다.

이러한 사용자 정의 구성은 환경 변수, 별명, 고급 프롬프트 일 수 있습니다. 비 대화식 쉘을 사용하면 부족한 점이 의미가 없습니다. 또한 많은 상황에서 비 대화식 쉘을 호출 할 수 있습니다. 이러한 환경 변수가 잘못된 부정 사례 나 보안 취약성을 초래할 수 있는지 확신 할 수 없습니다.

가장 가까운 예는 다음과 같은 별칭입니다.

alias cp='cp -i'

그런 다음 비 대화식 쉘을 영원히 중단시킵니다.

따라서 점검 .bashrc은 문제가 발생하지 않도록 상단에서 수행됩니다 .


쉘은 비 대화식 로그인 쉘로 호출 될 수 있으므로 명시 적으로 블록 소싱 *bashrc은 의미가 없습니다.

쉘이 때 비 대화 형 로그인 쉘이라 , 그 소스 /etc/profile, 그 첫 번째가에서 발견 소스 ~/.bash_profile, ~/.bash_login~/.profile:

bash가 대화식 로그인 쉘 또는 --login 옵션을 사용하는 비 대화식 쉘로 호출 되면 파일이 존재하는 경우 먼저 / etc / profile 파일에서 명령을 읽고 실행합니다. 해당 파일을 읽은 후 ~ / .bash_profile, ~ / .bash_login 및 ~ / .profile을 순서대로 찾고 존재하고 읽을 수있는 첫 번째 파일에서 명령을 읽고 실행합니다.

이러한 파일 .bashrc자체 가 소싱되는 것을 막을 수는 없으므로 내부 검사 .bashrc는 더 안전하고 간단합니다.


예, 알아요 이것이 비 대화식 쉘이 *bashrc파일을 전혀 소스하지 않는 이유 입니다. 내 질문은 왜 비 대화식 쉘이 이러한 파일을 읽지 않으면 비 대화식 쉘이 이러한 파일을 읽지 못하도록 명시 적으로 차단하는 데 어려움을 겪는가?
terdon

1
@terdon : 쉘은 비 대화식 로그인 쉘로 불릴 수 있기 때문에, 로그인 쉘은 source .bash_profile일 수 있습니다 .bashrc.
cuonglm

아니오, 비 대화식 쉘에서 읽을 수있는 유일한 것은입니다 $BASH_ENV. 모두 *profile와는 *bashrc무시됩니다. 또는 적어도 맨 페이지에서 말한 것입니다. 그러나 Mikel이 보여 주듯이 맨 페이지가 거짓말을하고있을 수 있습니다.
terdon

@ terdon : 링크가있는 업데이트 된 답변을 읽으십시오. bash -l -c :비 대화식 로그인 쉘을 호출 하려고 했습니까 ?
cuonglm

와. 당신 말이 맞아요 나는 그 부분을 약 --login100 번 읽었 지만 분명히 등록 된 적은 없었습니다. 감사!
terdon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.