본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로인프라 › 운영체제 › Linux

SU에서 EOF 사용시 내부 변수 처리 방법

목차

SU에서 EOF 사용시 내부 변수 처리 방법

여기서 $가 사라진 이유는 su가 아니라 here-document를 만드는 바깥 셸이 먼저 변수를 확장하기 때문이다. 바깥 셸과 전환된 사용자 셸 중 어디에서 변수를 해석할지 결정해야 한다.

안쪽 셸에서 변수를 해석하기

구분자 EOF를 작은따옴표로 감싸면 본문 전체를 그대로 전달한다. 안쪽 셸에서 outdata1을 설정하고 출력하는 경우에 맞는다.

sudo -u user sh <<'EOF'
outdata1='helloworld'
printf 'outdata1=%s\n' "$outdata1"
EOF
flowchart LR
  바깥[바깥 셸: 원문 전달] --> 안쪽[전환된 사용자 셸: 변수 확장]
  안쪽 --> 출력[출력: outdata1=helloworld]

반대로 바깥 셸의 값을 전달하려면 따옴표 없는 구분자를 쓰거나 명시적으로 인자를 전달할 수 있다. 따옴표 없는 구분자에서는 $outdata1이 바깥쪽에서 확장되므로, 안쪽에서 해석할 변수만 \$outdata1처럼 이스케이프해야 한다. 값에 공백이나 셸 특수 문자가 있다면 본문에 직접 끼워 넣는 대신 인자나 환경 변수로 안전하게 전달한다.

바깥 셸과 안쪽 셸을 눈으로 확인하기

다음 예제에서는 두 셸의 사용자와 변수값을 따로 출력한다. EOF가 따옴표로 감싸지지 않았기 때문에 첫 번째 $value와 $(whoami)는 sudo가 실행되기 전, 바깥 셸에서 확장된다. 문자열이 전환된 사용자에게 전달됐다는 사실과 변수가 안쪽 셸에 존재한다는 것은 다르다.

value='outer value'
sudo -u user sh <<EOF
printf '바깥에서 확장된 값: %s\n' "$value"
printf '바깥에서 실행된 사용자: %s\n' "$(whoami)"
printf '안쪽에서 실행된 사용자: %s\n' "\$(whoami)"
EOF

\$(whoami)의 역슬래시는 바깥 셸의 명령 치환을 막는다. 따라서 마지막 줄의 명령 치환은 안쪽 셸에서 일어난다. 변수에 공백, 따옴표, 줄바꿈이 들어가면 이처럼 스크립트 본문에 값을 끼워 넣는 방법은 의도하지 않은 셸 구문을 만들 수 있다. 외부 입력값에는 사용하지 않는다.

바깥 변수를 안전하게 전달하려면 본문을 따옴표로 감싼 고정 스크립트로 두고, 값을 인자로 넘긴다. 아래에서 첫 번째 sh는 $0 자리를 채우고 "$value"가 안쪽 셸의 $1이 된다.

value='hello world'
sudo -u user sh -c 'printf "받은 값: %s\n" "$1"' sh "$value"

예상과 다르면 확인할 순서

  1. <<EOF인지 <<'EOF'인지 확인한다. 따옴표가 있으면 바깥 셸은 변수·명령 치환을 하지 않는다.
  2. 안쪽에서 사용할 변수를 어느 셸에서 정의했는지 확인한다. 바깥의 일반 셸 변수는 별도 프로세스의 환경 변수로 자동 전달되지 않는다.
  3. sudo나 su -가 환경 변수를 초기화할 수 있다. 값 전달이 필요하면 환경 보존을 막연히 기대하지 말고 인자를 쓰거나 허용된 환경 변수 전달 방식을 명시한다.
  4. Permission denied가 나온다면 변수 확장이 아니라 전환 대상 사용자와 대상 파일의 권한을 확인한다.

여기서 사용한 예제의 user는 실제 계정명으로 바꿔야 한다. 스크립트 안에 암호나 토큰을 넣으면 파일·로그·프로세스 인수에 남을 수 있으므로, 자격 증명 전달에는 별도의 비밀 관리 수단을 사용한다. GNU Bash의 here-document 규칙에 따옴표 유무에 따른 확장 시점이 정리돼 있다.

같은 카테고리의 글