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)에서 실행되는 명령어들의 집합, 즉 파일이다.
기본 구조
- 셔뱅(Shebang): 스크립트 첫 줄에 위치하며, 어떤 인터프리터로 실행할지 지정한다.
#!/bin/bash
- 주석(Comments):
#
기호로 시작하며, 코드 설명을 위해 사용된다. *# 이것은 주석입니다*
- 변수 선언 및 사용: 변수를 선언하고 값을 할당한다.
NAME="홍길동" echo $NAME
- 명령어 실행: 시스템 명령어를 실행합니다
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!
실행 방법
만들었으면 실행을 해야 한다. 실행과정을 보자.
- 실행 권한 부여:
chmod +x 스크립트파일명
으로 실행 권한을 부여 - 직접 실행:
./스크립트파일명
또는 전체 경로를 지정하여 실행 - 인터프리터 지정 실행:
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 어플리케이션을 실행할 테니 스크립트를 작성해달라고 했다. 기본적으로 잘 나와주었다.
조건
- 8080포트로 들어오는 트래픽을 처리할 수 있어야 한다.
- 로그파일을 ./var/spring/ 경로에 저장해야 한다.
- nohup 명령어를 사용해서 백그라운드에서 동작하도록 한다.
- 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 |