bash 스크립트 : sudo를 사용하거나 사용하지 않고 호출 할 때 다른 결과


10

Ubuntu 16.04.3에는 매우 간단한 bash 스크립트가 있습니다.

test.sh

[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0

루트가 아닌 사용자 me또는로 호출하면 root예상대로 작동합니다. 을 사용 sudo ./test.sh하면 구문 오류에 대해 불평합니다.

$ ./test.sh
true
me /bin/bash ./test.sh

$ sudo su
# ./test.sh 
true
root /bin/bash ./test.sh

# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh

이 문제의 원인은 무엇입니까? me이 스크립트를 정상적으로 사용할 수 있도록 수정하려면 어떻게 해야 sudo합니까?


3
전문가 팁 : 달리기에 아무 소용이 없습니다sudo su . 그냥 sudo -i또는 sudo -s대신 실행하십시오 .
terdon

@terdon sudo -i은 위치를로 변경합니다 /root. sudo su또는 sudo -s디렉토리 위치를 변경하지 마십시오.
James Newton

예, 왜 이전에 연결했던 질문을 읽으십시오. 죄송합니다. 이전 의견을 수정했습니다 -s. 언급하지 않았습니다 .
terdon

답변:


20

모든 스크립트는 시작 오두막 없이, 스크립트를 실행해야하는 인터프리터 모르는 스크립트를 시작하는 쉘 (1) 의 경우처럼 -와 힘을 sudo ./script.sh여기에 - 그것을 실행 sh, 우분투 16.04에 연결되어 있습니다 dash. 조건식 [[ A는 bash화합물 명령 때문에, dash그것을 처리하고 발생한 오류를 발생하는 방법을 알고하지 않습니다.

여기에 해결책은 추가하는 것입니다

#!/bin/bash

스크립트의 첫 줄로. 로 명시 적으로 호출하면 동일한 결과를 얻을 수 sudo bash ./script.sh있지만 shebang이 방법입니다.
스크립트를 실행하는 쉘을 확인하려면 추가 echo $0하십시오. 그건 동일하지 echo $SHELL 인용, wiki.archlinux.org를 :

SHELL에는 사용자가 선호하는 쉘의 경로가 포함되어 있습니다. Bash는 시작할 때이 변수를 설정하지만 반드시 현재 실행중인 쉘일 필요는 없습니다.

1 :되면서 ./test.sh함께 bash이 단지 가정 bash, 같은가 간다 sudo su서브 쉘.


1
또한 bash는 bash를 사용하지 않고 shebang없이 스크립트를 실행합니다 /bin/sh.
muru

@dessert 문제가 해결되었습니다. 감사! 어떤 쉘 에서 스크립트 를 실행하고 있는지 어떻게 확인할 수 있습니까? ( echo $0나에게 스크립트의 이름을 제공합니다 : ./test.sh)
제임스 뉴턴

@JamesNewton AFAIK, 휴대용 방법은 없지만 어떤 /proc/$$/exe점을 확인할 수 있습니다 . 또한 당신은 같은 다양한 변수를 테스트 할 수 있습니다 $BASH_VERSION, $ZSH_VERSION등 (그러나 대시는 이러한 변수를 설정하지 않습니다)
muru

5

으로 @dessert 설명 , 여기에 문제는 스크립트가없는 것입니다 오두막 라인을 . shebang이 없으면 sudo기본적 으로을 사용하여 파일을 실행하려고합니다 /bin/sh. 어디서나 문서화 할 수는 없지만 sudo파일에서 다음을 찾은 소스 코드를 확인하여 확인했습니다 pathnames.h.

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

이는 "변수 _PATH_BSHELL가 정의되지 않은 경우 설정하고"로 설정하는 것을 의미 /bin/sh합니다. 그런 다음 configure소스 tarball에 포함 된 스크립트에는 다음 이 있습니다.

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

이 루프를 찾습니다 /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/sh또는 /bin/ksh다음 설정 _PATH_BSHELL먼저 발견 한 중 . 이후 /bin/sh목록의 첫 번째이고 그 존재 _PATH_BSHELL로 설정됩니다 /bin/sh. 이 모든 결과는 sudo달리 정의되지 않는 한 기본 쉘의 결과입니다 /bin/sh.

따라서 우분투에서는 최소한 POSIX 호환 쉘에 대한 심볼릭 링크를 sudo사용하여 작업을 실행하도록 기본 설정됩니다 ./bin/shdash

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash

[[구조체는, 그것은 POSIX 표준에 의해 떠들썩한 기능 정의되어 있지 않으므로 이해되지 않는다 dash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

자세하게는 세 번의 호출에서 시도했습니다.

  1. ./test.sh

    아니요 sudo; shebang 행이 없으면 쉘은 파일 자체를 실행하려고 시도합니다. 당신이 달리고 있기 때문에 bash, 이것은 효과적으로 실행 bash ./test.sh되고 작동합니다.

  2. sudo su뒤에 ./test.sh.

    여기에서 사용자를위한 새로운 쉘을 시작합니다 root. 이것은 $SHELL해당 사용자 의 환경 변수에 정의 된 모든 쉘이며 Ubuntu에서 루트의 기본 쉘은 bash다음과 같습니다.

    $ grep root /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    
  3. sudo ./test.sh

    여기서 sudo명령을 직접 실행할 수 있습니다. 기본 쉘이되어 있기 때문에 /bin/sh위와 같이 설명, 이것은으로 스크립트를 실행하도록 원인이 /bin/sh되는, dash그리고 이후 실패 dash이해하지 않습니다 [[.


참고 : sudo기본 쉘을 설정하는 방법에 대한 세부 사항은 조금 더 복잡해 보입니다. 내 대답에 언급 된 파일을 가리 키도록 변경 /bin/bash했지만 sudo여전히 기본 설정이었습니다 /bin/sh. 따라서 소스 코드에는 기본 쉘이 정의 된 다른 위치가 있어야합니다. 그럼에도 불구하고, 기본 포인트 는 여전히 sudo기본값 sh입니다.


어디에서나 문서화 할 수 없었 습니다. 나도 /bin/sh오류 메시지에서 사용할 것이라고 생각했습니다. 다른 가능한 방법은 무엇입니까? 이 질문은 sudo가 사용하는 쉘은 무엇입니까? · SO man sudo, 섹션 COMMAND EXECUTION을 참조하십시오 . sudo중간 쉘을 사용하지 않는 것이 밝혀졌습니다 !
디저트

1
@dessert 예. execve시스템 호출 의 자체 구현을 사용하며 기본값은 sh입니다. 그리고 중간 쉘은 관련이 없습니다. 이것은 명령을 실행하는 쉘이 아니라 주어진 쉘 스크립트를 읽는 데 사용되는 쉘 인터프리터에 관한 것입니다. 따라서 아니오, 중간 쉘을 시작하지는 않지만 쉘 스크립트를위한 쉘 인터프리터가 여전히 필요합니다.
terdon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.