간단한 관리 스크립트 작성하기

ShellBeginner
지금 연습하기

소개

시스템 관리자는 반복적인 점검 작업을 작은 셸 스크립트로 자동화하곤 합니다. RHCSA 스타일의 스크립팅은 거창한 프로그램을 만드는 것이 아닙니다. Bash 를 안전하게 사용하여 일반적인 작업을 자동화하고, 입력을 검증하며, 대상 목록을 순회하고, 유용한 종료 코드를 반환하며, 다른 관리자가 이해할 수 있는 출력을 남기는 것이 핵심입니다.

이 실습에서는 디렉터리 요약 스크립트를 단계별로 구축합니다. 이 스크립트는 디렉터리 경로를 인자로 받아 각 경로의 사용 가능 여부를 확인하고, 기본적인 파일 정보를 수집하며, 읽기 쉬운 형식으로 출력하고, 동일한 내용을 로그 파일에 저장합니다.

실행 가능한 스크립트 만들기

이 단계에서는 샘플 디렉터리를 살펴보고 관리 스크립트의 첫 번째 실행 가능한 버전을 만듭니다. 스크립트는 시스템이 어떤 인터프리터를 사용할지 알 수 있도록 셰뱅 (shebang) 으로 시작해야 합니다.

프로젝트 디렉터리로 이동합니다.

cd /home/labex/project

샘플 트리 구조를 확인합니다. find 명령은 파일과 디렉터리를 나열하며, sort는 순서를 일정하게 정렬합니다.

find /home/labex/project/script-practice -maxdepth 2 -print | sort

admin-summary.sh의 첫 번째 버전을 만듭니다. #!/bin/bash 줄은 리눅스에게 이 파일을 Bash 로 실행하라고 지시합니다. set -u 옵션은 설정되지 않은 변수를 사용할 경우 스크립트를 중단시키므로, 많은 오타 실수를 방지할 수 있습니다.

cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u

echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"
EOF

스크립트에 실행 권한을 부여합니다. 실행 권한이 없으면 파일은 단순한 텍스트일 뿐입니다.

chmod 755 /home/labex/project/admin-summary.sh

스크립트를 실행합니다.

/home/labex/project/admin-summary.sh

스크립트 제목, 현재 사용자, 짧은 호스트 이름이 출력되는 것을 확인할 수 있습니다. 호스트 이름은 환경에 따라 다를 수 있습니다.

디렉터리 인자 받기

이 단계에서는 위치 매개변수 (positional parameters) 를 추가합니다. 스크립트는 $#를 사용하여 인자의 개수를 세고, "$@"를 사용하여 전달된 모든 인자를 그대로 나타냅니다.

최소 하나의 디렉터리 인자를 요구하도록 스크립트를 수정합니다.

cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u

if [ "$#" -eq 0 ]; then
  echo "Usage: $0 DIRECTORY [DIRECTORY...]"
  exit 2
fi

echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"

for target in "$@"; do
  echo "TARGET=$target"
done
EOF

스크립트의 실행 권한을 유지합니다.

chmod 755 /home/labex/project/admin-summary.sh

인자 없이 스크립트를 실행합니다. 사용법이 출력되고 종료 상태 2가 반환되어야 합니다. || 연산자는 왼쪽의 명령이 실패할 경우에만 오른쪽의 명령을 실행하므로, 의도적으로 0 이 아닌 상태 값을 표시할 수 있습니다.

/home/labex/project/admin-summary.sh || echo "exit status: $?"

이제 두 개의 디렉터리 인자를 전달하여 실행합니다.

/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs

출력 결과에 각 인자에 대한 TARGET= 줄이 포함되어야 합니다.

각 대상 테스트 및 유용한 상태 반환

이 단계에서는 각 인자에 대한 조건부 테스트를 추가합니다. [ -d "$target" ] 테스트는 경로가 존재하고 디렉터리인 경우에만 성공합니다.

디렉터리인 경우 OK를, 그 외의 경우에는 MISSING을 보고하도록 스크립트를 수정합니다.

cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u

if [ "$#" -eq 0 ]; then
  echo "Usage: $0 DIRECTORY [DIRECTORY...]"
  exit 2
fi

echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"

exit_status=0

for target in "$@"; do
  if [ -d "$target" ]; then
    echo "OK $target"
  else
    echo "MISSING $target"
    exit_status=1
  fi
done

exit "$exit_status"
EOF

유효한 디렉터리로 스크립트를 실행합니다. 최종 종료 상태는 0이어야 합니다.

/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app
echo "exit status: $?"

존재하지 않는 디렉터리로 다시 실행합니다. 이번에는 스크립트가 MISSING을 출력하고 종료 상태 1을 반환해야 합니다.

/home/labex/project/admin-summary.sh /home/labex/project/script-practice/missing || echo "exit status: $?"

실용적인 디렉터리 정보 수집

이 단계에서는 명령 치환 (command substitution) 을 추가합니다. 명령 치환은 $() 내부의 명령을 실행하고 그 결과를 변수에 저장합니다.

유효한 각 디렉터리에 대해 파일 개수, 실제 크기, 소유자를 보고하도록 스크립트를 수정합니다.

cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u

if [ "$#" -eq 0 ]; then
  echo "Usage: $0 DIRECTORY [DIRECTORY...]"
  exit 2
fi

echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"

exit_status=0

for target in "$@"; do
  if [ -d "$target" ]; then
    file_count="$(find "$target" -type f | wc -l)"
    size="$(du -sh "$target" | awk '{print $1}')"
    owner="$(stat -c '%U:%G' "$target")"
    echo "OK $target FILES=$file_count SIZE=$size OWNER=$owner"
  else
    echo "MISSING $target"
    exit_status=1
  fi
done

exit "$exit_status"
EOF

준비된 세 개의 디렉터리를 대상으로 스크립트를 실행합니다.

/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs /home/labex/project/script-practice/cache

app 디렉터리는 FILES=3, logs는 FILES=2, cache는 FILES=1을 보여야 합니다.

로그 파일에 출력 저장

이 단계에서는 간단한 헬퍼 함수와 로그 파일을 추가합니다. 함수를 사용하면 코드 중복을 방지할 수 있으며, tee -a를 사용하면 출력을 화면에 표시하는 동시에 파일 끝에 내용을 추가할 수 있습니다.

스크립트를 최종 버전으로 수정합니다.

cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u

LOG="/home/labex/project/admin-summary.log"
: > "$LOG"

emit() {
  echo "$*" | tee -a "$LOG"
}

if [ "$#" -eq 0 ]; then
  emit "Usage: $0 DIRECTORY [DIRECTORY...]"
  exit 2
fi

emit "RHCSA admin summary"
emit "RUN_AS=$(id -un)"
emit "HOST=$(hostname -s)"

exit_status=0

for target in "$@"; do
  if [ -d "$target" ]; then
    file_count="$(find "$target" -type f | wc -l)"
    size="$(du -sh "$target" | awk '{print $1}')"
    owner="$(stat -c '%U:%G' "$target")"
    emit "OK $target FILES=$file_count SIZE=$size OWNER=$owner"
  else
    emit "MISSING $target"
    exit_status=1
  fi
done

exit "$exit_status"
EOF

두 개의 유효한 디렉터리와 하나의 존재하지 않는 디렉터리를 인자로 하여 최종 스크립트를 실행합니다.

/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs /home/labex/project/script-practice/missing || echo "exit status: $?"

저장된 로그를 확인합니다.

sed -n '1,8p' /home/labex/project/admin-summary.log

터미널 출력과 로그 파일에 동일한 요약 내용이 포함되어야 합니다. 하나의 대상이 누락되었으므로 종료 상태는 1이어야 합니다.

요약

실용적인 Bash 관리 스크립트를 성공적으로 작성했습니다. 셰뱅, 실행 권한, 위치 매개변수, 인자 개수 확인, 루프, 디렉터리 테스트, 명령 치환, 명시적 종료 상태, 헬퍼 함수 및 로그 파일 사용법을 익혔습니다. 이러한 스크립팅 패턴은 소규모 RHCSA 스타일 관리 작업에 가장 유용하게 활용됩니다.