오늘도 기록하는 중 GitHub

Linux

Shell

YongE 2025. 4. 23. 20:34

Shell이란?


리눅스나 유닉스 시스템에서 자동화된 작업을 수행하기 위한 프로그램이다. 사용자와 운영체제 커널 사이의 인터페이스 역할을 하며, 사용자의 명령을 해석하고 실행한다.

shell의 종류는 다음과 같다.

  • bash : Bourne-Again Shell(프롬프트 : #, 경로 : /bin/bash)
  • sh : Bourne Shell(프롬프트 : $, 경로 : /bin/sh)
  • csh : C Shell(프롬프트 : %, 경로 : /bin/csh)
  • ksh : Kron Shell(프롬프트 : $, 경로 : /bin/ksh)
  • tcsh : TENEX C Shell(프롬프트 : >, 경로 : /bin/tcsh)

Shell 명령어 기호

shell 명령어를 다음과 같은 기호와 함께 사용하면 다양한 작업이 효율적으로 가능해진다.

| : 한 명령어의 출력(stdout)을 다음 명령어의 입력(stdin)으로 전달하는 프로세스 간 통신 메커니즘이다.

ls /var/log | grep error  # /var/log 디렉토리 목록에서 'error' 포함 라인 필터링[6]
연산자 설명 예시
> 파일을 새로 생성하거나 덮어쓰기 echo "신규 내용" > file.txt
>> 파일에 내용을 추가 date >> log.txt
<< Here Document, 여러 줄 입력 전달
bashcat <<EOF
첫 번째 라인
두 번째 라인
EOF

주요 특징

  • >: 기존 파일 내용 삭제 후 새로 기록
  • >>: 기존 내용 유지하며 추가
  • <<: 지정한 구분자까지 입력을 명령어에 전달

Shell Script


쉘(Shell)에서 실행되는 명령어들의 집합, 즉 파일이다.

기본 구조

  1. 셔뱅(Shebang): 스크립트 첫 줄에 위치하며, 어떤 인터프리터로 실행할지 지정한다.
  2. #!/bin/bash
  3. 주석(Comments): # 기호로 시작하며, 코드 설명을 위해 사용된다.
  4. *# 이것은 주석입니다*
  5. 변수 선언 및 사용: 변수를 선언하고 값을 할당한다.
  6. NAME="홍길동" echo $NAME
  7. 명령어 실행: 시스템 명령어를 실행합니다
  8. ls -la pwd

주요 기능

  • 변수 사용
    • 변수 선언: 변수명=값 형태로 선언(등호 앞뒤에 공백이 없어야 함)
    • 변수 참조: $변수명 또는 $변수명 형태로 참조
    • 환경 변수: export 변수명=값으로 선언하여 자식 프로세스에서도 사용 가능하게 함
    • 배열 선언
    • arr=("a" "b" "c") echo "${arr[0]}" #인덱스를 사용 echo "${arr[@]}" #전체 원소를 의미 #원소추가 arr+=("d")
  • 조건문
    • 비교 연산자
      • -eq : equal, 같음을 의미 (java의 ==와 동일)
      • -ne : 같지 않음
      • -gt : 더 큼
      • -ge : 더 크거나 같음
      • -lt : 더 작음
      • -le : 더 작거나 같음
      • < : 더 작음, 이중소괄호에서 사용됨 → (("$a" < "$b"))
      • ≤ : 이중소괄호에서 사용, >, ≥도 동일함
      • = : 같음
      • == : =와 동일, 사용은 아래를 참조
      • [[ $a == z* ]] # $a 가 "z"로 시작하면 참(패턴 매칭) [[ $a == "z*" ]] # $a 가 z* 와 같다면 참 [ $a == z* ] # 파일 globbing이나 낱말 조각남이 일어남 [ "$a" == "z*" ] # $a 가 z* 와 같다면 참
      • -a : and 연산
      • -o : or 연산
      • -z : 빈 문자열 검사
var="Hello" # 공백 없이 할당

if [ "$var" -eq 10 ]; then
  echo "10입니다"
elif [ "$var" -gt 5 ]; then
  echo "5보다 큽니다"
else
  echo "기타"
fi
  • 반복문
# 배열 순회
fruits=("apple" "orange")
for fruit in "${fruits[@]}"; do
  echo "$fruit"
done

# 숫자 범위
for ((i=0; i<3; i++)); do
  echo "$i"
done

# while 예시
num=0
while [ $num -lt 3 ]; do
  echo $num
  num=$((num+1))
done
  • 함수
    • return이나 function 키워드를 생략할 수 있다.
function greet() {
  echo "Hello, $1!"
}
greet "World"  # 출력: Hello, World!

실행 방법

만들었으면 실행을 해야 한다. 실행과정을 보자.

  1. 실행 권한 부여: chmod +x 스크립트파일명으로 실행 권한을 부여
  2. 직접 실행: ./스크립트파일명 또는 전체 경로를 지정하여 실행
  3. 인터프리터 지정 실행: bash 스크립트파일명과 같이 인터프리터를 직접 지정하여 실행
chmod +x script.sh  # 실행 권한 부여
./script.sh         # 서브쉘에서 실행

# 혹은
bash script.sh

# 현재 쉘에서 직접 실행
# 특징이라면 변수/함수가 현재 세션에 유지
source script.sh

디버깅

  • x 옵션: 실행되는 각 명령을 출력 (예 : bash -x 스크립트파일명)
# 출력 예시

+ echo 'Starting the script...'
Starting the script...
+ MY_VARIABLE='Hello, World'
+ echo 'Hello, World'
Hello, World

# 부분 디버깅도 가능하다!

echo "일반 출력"
set -x  # 디버깅 시작
echo "디버그 영역"
set +x  # 디버깅 종료
  • v 옵션: 스크립트의 각 라인을 실행 전에 출력
  • -n 옵션 : 문법 검사! 논리적인 오류는 감지가 불가하나 빠르게 문법 검증이 가능하다.
bash -n script.sh  # 실행 없이 구문 오류만 검사
  • set -e: 오류가 발생하면 스크립트 실행을 중단
  • set -u: 정의되지 않은 변수를 사용하면 오류를 발생

실험


배웠으니 이제 실험 삼아 사용해보자. 하지만 일일이 작성하는 것은 매우 귀찮다. o4-mini에게 다음과 같은 조건으로 리눅스 환경에서 spring 어플리케이션을 실행할 테니 스크립트를 작성해달라고 했다. 기본적으로 잘 나와주었다.

조건

  1. 8080포트로 들어오는 트래픽을 처리할 수 있어야 한다.
  2. 로그파일을 ./var/spring/ 경로에 저장해야 한다.
  3. nohup 명령어를 사용해서 백그라운드에서 동작하도록 한다.
  4. spring application을 현재 우분투 환경에 내가 직접 다운로드한 상황이다.
#!/usr/bin/env bash

#─────────────────────────────────────────────────────────────────────────────
# 1) 변수 정의
#─────────────────────────────────────────────────────────────────────────────
APP_JAR="your-spring-app.jar"
#   - 실행할 Spring Boot fat‑jar 파일명
#   - 스크립트와 동일 디렉토리에 다운로드되어 있다고 가정

PORT=8080
#   - Spring 애플리케이션을 바인딩할 포트 번호

LOG_DIR="./var/spring"
#   - 로그를 저장할 디렉토리 경로(상대 경로)

LOG_FILE="$LOG_DIR/app.log"
#   - stdout과 stderr를 합쳐 기록할 로그 파일 경로
#─────────────────────────────────────────────────────────────────────────────

#─────────────────────────────────────────────────────────────────────────────
# 2) 필수 명령어(java) 존재 여부 확인
#─────────────────────────────────────────────────────────────────────────────
command -v java >/dev/null 2>&1
#   - command -v java: java 실행 파일이 PATH상에 있는지 검사
#   - stdout과 stderr를 /dev/null로 버려서 화면에 출력되지 않게 함
if [ $? -ne 0 ]; then
  echo "[ERROR] java 명령을 찾을 수 없습니다. 설치 후 재시도하세요."
  exit 1
fi
#   - java가 없으면 에러 메시지 출력 후 스크립트 종료
#─────────────────────────────────────────────────────────────────────────────

#─────────────────────────────────────────────────────────────────────────────
# 3) 로그 디렉토리 생성
#─────────────────────────────────────────────────────────────────────────────
mkdir -p "$LOG_DIR"
#   - -p 옵션: 상위 디렉토리가 없어도 한 번에 생성, 
#     이미 디렉토리가 있으면 에러 없이 통과
#─────────────────────────────────────────────────────────────────────────────

#─────────────────────────────────────────────────────────────────────────────
# 4) 기존 Spring 앱 프로세스 종료 (옵션)
#─────────────────────────────────────────────────────────────────────────────
if lsof -i TCP:"$PORT" >/dev/null 2>&1; then
  # lsof -i TCP:8080
  #   - 8080 포트를 열고 있는 프로세스 정보를 출력
  #   - >/dev/null 2>&1: 성공/실패 메시지를 모두 버림
  PID=$(lsof -i TCP:"$PORT" -t)
  #   - -t 옵션: 프로세스 ID만 출력(스크립트 내에서 사용하기 편리)
  echo "[INFO] 포트 $PORT 사용 중인 PID=$PID 종료"
  kill "$PID"
  #   - 해당 PID에 TERM 시그널 보내서 종료 시도
  sleep 2
  #   - 프로세스가 정상 종료될 시간을 잠시 대기
fi
#─────────────────────────────────────────────────────────────────────────────

#─────────────────────────────────────────────────────────────────────────────
# 5) Spring 애플리케이션 백그라운드 실행
#─────────────────────────────────────────────────────────────────────────────
echo "[INFO] Spring App 시작 (PORT=$PORT) → 로그: $LOG_FILE"

nohup java -jar "$APP_JAR" --server.port="$PORT" \
  > "$LOG_FILE" 2>&1 &
# ────────────────────────────────────────────────────────────────────────────
# - nohup: 터미널 종료(로그아웃) 후에도 프로세스가 살아 있도록 함  
# - java -jar ... --server.port: Spring Boot 기본 포트 설정  
# - > "$LOG_FILE": 표준출력(stdout)을 로그 파일로 리다이렉션  
# - 2>&1: 표준에러(stderr)도 동일한 로그 파일로 합침  
# - &: 쉘을 차단하지 않고 백그라운드에서 실행
#─────────────────────────────────────────────────────────────────────────────

#─────────────────────────────────────────────────────────────────────────────
# 6) 실행 결과 안내
#─────────────────────────────────────────────────────────────────────────────
NEW_PID=$!
#   - $!: 바로 직전에 백그라운드로 실행된 프로세스의 PID
echo "[INFO] Spring App PID=$NEW_PID"
echo "[INFO] 실행 완료. 로그 확인: tail -f $LOG_FILE"
#─────────────────────────────────────────────────────────────────────────────
반응형

'Linux' 카테고리의 다른 글

리눅스 커널 모듈  (0) 2025.05.15
시스템 로그 분석 및 모니터링(logrotate)  (0) 2025.05.15
리눅스  (0) 2025.04.28