1. 환경 변수 기초
환경 변수 vs 쉘 변수
# 쉘 변수: 현재 쉘에서만 유효 (자식 프로세스에 전달되지 않음)
MY_VAR="hello"
echo $MY_VAR # hello
# 환경 변수: 자식 프로세스에도 상속됨
export MY_VAR="hello"
# 또는
export MY_VAR # 이미 존재하는 쉘 변수를 환경 변수로 승격환경 변수 조회
# 모든 환경 변수 출력
env
# 또는
printenv
# 특정 변수만 출력
printenv PATH
echo $PATH
# 환경 변수 + 쉘 변수 + 쉘 함수 모두 출력
set
# 환경 변수만 (set에서 필터링)
env | sort환경 변수 설정/삭제
# 설정 (현재 쉘 + 자식 프로세스)
export JAVA_HOME="/usr/lib/jvm/java-17"
# 특정 명령에만 적용 (일회성)
LANG=C sort file.txt
# 또는
env LANG=C sort file.txt
# 삭제
unset MY_VAR
# 모든 환경 변수 제거 후 깨끗한 상태로 명령 실행
env -i /bin/bash2. 주요 환경 변수
| 변수 | 설명 | 예시 |
|---|---|---|
PATH | 실행 파일 검색 경로 | /usr/local/bin:/usr/bin:/bin |
HOME | 현재 사용자 홈 디렉토리 | /home/phh |
USER | 현재 사용자 이름 | phh |
SHELL | 현재 사용자의 기본 쉘 | /bin/bash |
LANG | 기본 로케일 | ko_KR.UTF-8 |
LC_ALL | 모든 로케일 강제 지정 (LANG보다 우선) | C.UTF-8 |
TERM | 터미널 타입 | xterm-256color |
EDITOR | 기본 텍스트 에디터 | vim |
VISUAL | 비주얼 에디터 (EDITOR보다 우선) | vim |
LD_LIBRARY_PATH | 동적 라이브러리 검색 경로 | /usr/local/lib |
DISPLAY | X11 디스플레이 서버 | :0 |
PWD | 현재 작업 디렉토리 | /home/phh/project |
OLDPWD | 이전 작업 디렉토리 | /home/phh |
HOSTNAME | 호스트 이름 | myserver |
LOGNAME | 로그인 이름 | phh |
HISTSIZE | 메모리에 저장할 히스토리 수 | 1000 |
HISTFILESIZE | 히스토리 파일에 저장할 수 | 2000 |
XDG 디렉토리 변수
freedesktop.org 표준으로 사용자 디렉토리를 정의한다.
# 기본값 (미설정 시 자동 적용)
XDG_CONFIG_HOME="$HOME/.config" # 설정 파일
XDG_DATA_HOME="$HOME/.local/share" # 애플리케이션 데이터
XDG_CACHE_HOME="$HOME/.cache" # 캐시
XDG_STATE_HOME="$HOME/.local/state" # 상태 데이터 (로그, 히스토리)
XDG_RUNTIME_DIR="/run/user/$UID" # 런타임 파일 (소켓, PID 등)
# 시스템 레벨
XDG_DATA_DIRS="/usr/local/share:/usr/share"
XDG_CONFIG_DIRS="/etc/xdg"3. PATH 관리
PATH 추가
# 끝에 추가 (기존 명령보다 낮은 우선순위)
export PATH="$PATH:/opt/myapp/bin"
# 앞에 추가 (기존 명령보다 높은 우선순위)
export PATH="/opt/myapp/bin:$PATH"
# 확인
echo $PATH
which python3 # 어떤 경로의 python3이 실행되는지PATH 순서의 의미
# PATH="/usr/local/bin:/usr/bin:/bin"일 때:
# 명령어를 입력하면 왼쪽 디렉토리부터 순서대로 검색
# 같은 이름의 명령이 여러 경로에 있으면 먼저 발견된 것이 실행됨
# 예: python3이 여러 곳에 있을 때
# /usr/local/bin/python3 ← 이것이 실행됨 (PATH에서 먼저)
# /usr/bin/python3
# 모든 경로 확인
which -a python3
type -a python3보안 주의사항: 현재 디렉토리(.) 포함 금지
# 절대 이렇게 하면 안 됨!
export PATH=".:$PATH" # 위험!
export PATH="$PATH:." # 위험!
# 이유:
# 공격자가 /tmp에 ls라는 악성 스크립트를 만들어 놓으면
# 사용자가 /tmp에서 ls를 실행할 때 악성 스크립트가 실행됨
# → 항상 절대 경로나 PATH에 등록된 경로만 사용
# 현재 디렉토리의 스크립트 실행 시
./myscript.sh # 명시적으로 ./를 붙여야 함4. 쉘 설정 파일 로딩 순서
로그인 쉘 (Login Shell)
SSH 접속, su -, 콘솔 로그인 시 실행.

관례:
~/.bash_profile에서~/.bashrc를 source하여 양쪽 모두 적용되게 한다.
# ~/.bash_profile 일반적인 내용
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
# 로그인 쉘 전용 설정 (환경 변수 등)
export JAVA_HOME="/usr/lib/jvm/java-17"
export PATH="$JAVA_HOME/bin:$PATH"비로그인 쉘 (Non-Login Shell)
터미널 에뮬레이터(GNOME Terminal 등)에서 새 탭/창 열 때, bash 명령 실행 시.
시스템 전역: /etc/bash.bashrc
│
▼
사용자별: ~/.bashrc
# ~/.bashrc 일반적인 내용
# alias 설정
alias ll='ls -alF'
alias la='ls -A'
alias grep='grep --color=auto'
# 프롬프트 설정
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '
# 쉘 옵션
shopt -s histappend
shopt -s checkwinsize로그아웃 시
# 로그인 쉘 종료 시 실행
~/.bash_logout정리: 설정 파일 용도 가이드
| 설정 종류 | 어디에 넣을지 | 이유 |
|---|---|---|
| 환경 변수 (PATH, JAVA_HOME 등) | ~/.bash_profile 또는 ~/.profile | 로그인 시 한 번만 설정하면 됨 |
| alias, 쉘 옵션, 프롬프트 | ~/.bashrc | 모든 쉘에서 필요 |
| 시스템 전역 설정 | /etc/profile.d/custom.sh | 모든 사용자에게 적용 |
5. alias
alias 설정 및 관리
# alias 확인
alias # 모든 alias 표시
alias ll # 특정 alias 확인
type ll # 명령어 타입 확인 (alias, builtin, file 등)
# alias 설정 (현재 세션)
alias ll='ls -alF'
alias gs='git status'
alias dc='docker compose'
alias ..='cd ..'
alias ...='cd ../..'
# 복잡한 alias
alias myip='curl -s ifconfig.me'
alias ports='ss -tulanp'
alias update='sudo apt update && sudo apt upgrade -y'
# alias 삭제
unalias ll
# 모든 alias 삭제
unalias -a
# alias를 무시하고 원래 명령 실행
\ls # 백슬래시
command ls # command 내장 명령
/bin/ls # 절대 경로영구 alias 설정
# ~/.bashrc에 추가
echo "alias ll='ls -alF'" >> ~/.bashrc
# 변경사항 즉시 적용
source ~/.bashrc
# 또는
. ~/.bashrc6. 쉘 옵션
shopt - Bash 전용 옵션
# 모든 옵션 상태 확인
shopt
# 특정 옵션 상태 확인
shopt -s cdspell # 활성화 (-s: set)
shopt -u cdspell # 비활성화 (-u: unset)
# 유용한 shopt 옵션
shopt -s cdspell # cd 오타 자동 교정 (cd /hme → /home)
shopt -s dirspell # 디렉토리 이름 탭 완성 시 오타 교정
shopt -s histappend # 히스토리 덮어쓰기 대신 추가 (여러 터미널 사용 시 중요)
shopt -s checkwinsize # 터미널 크기 변경 시 자동 업데이트
shopt -s globstar # ** 재귀 glob 활성화 (ls **/*.py)
shopt -s nocaseglob # glob 패턴에서 대소문자 무시
shopt -s dotglob # glob에 숨김파일(.) 포함set - POSIX 쉘 옵션
# 주요 옵션
set -e # 명령 실패 시 즉시 종료 (스크립트에서 유용)
set -u # 미정의 변수 사용 시 에러 (set -o nounset)
set -x # 실행되는 명령 출력 (디버깅) (set -o xtrace)
set -o pipefail # 파이프라인 중 하나라도 실패하면 실패
# 스크립트 시작 시 권장 설정
set -euo pipefail
# 해제
set +e # -e 해제
set +x # -x 해제
# 모든 옵션 확인
set -o7. 로케일 설정
현재 로케일 확인
locale
# LANG=ko_KR.UTF-8
# LC_CTYPE="ko_KR.UTF-8"
# LC_NUMERIC="ko_KR.UTF-8"
# LC_TIME="ko_KR.UTF-8"
# LC_COLLATE="ko_KR.UTF-8"
# ... (모든 LC_* 변수)
# LC_ALL=
# 사용 가능한 로케일 목록
locale -aLANG vs LC_* vs LC_ALL
우선순위: LC_ALL > LC_* (개별) > LANG
LANG - 기본 로케일 (모든 LC_*의 기본값)
LC_CTYPE - 문자 분류 (대소문자, 멀티바이트 등)
LC_NUMERIC - 숫자 표기법 (소수점, 천단위 구분자)
LC_TIME - 시간/날짜 표기법
LC_COLLATE - 문자열 정렬 순서
LC_MESSAGES - 시스템 메시지 언어
LC_ALL - 모든 LC_*를 강제 설정 (최우선)
# 시스템 기본 로케일 설정
sudo localectl set-locale LANG=ko_KR.UTF-8
# 로케일 생성
sudo locale-gen ko_KR.UTF-8
sudo dpkg-reconfigure locales # Debian 계열 대화형 설정
# 정렬 문제 해결 (C 로케일 사용)
# 한글/특수문자 정렬이 예상과 다를 때:
export LC_COLLATE=C
# C 로케일: 바이트 값 기준 정렬 (ASCII 순서)8. 시간대 설정
timedatectl (systemd)
# 현재 시간대 확인
timedatectl
# Local time: Fri 2024-01-15 14:30:00 KST
# Universal time: Fri 2024-01-15 05:30:00 UTC
# RTC time: Fri 2024-01-15 05:30:00
# Time zone: Asia/Seoul (KST, +0900)
# 시간대 목록 조회
timedatectl list-timezones
timedatectl list-timezones | grep Seoul
# 시간대 변경
sudo timedatectl set-timezone Asia/Seoul
# NTP 동기화 활성화
sudo timedatectl set-ntp true수동 설정
# 심볼릭 링크 방식
sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
# 또는 tzdata 재설정
sudo dpkg-reconfigure tzdata # Debian 계열
# TZ 환경 변수로 일시적 변경
TZ='America/New_York' date
TZ='UTC' date9. 커널 파라미터
sysctl - 런타임 커널 파라미터 조회/변경
# 모든 파라미터 조회
sysctl -a
# 특정 파라미터 조회
sysctl net.ipv4.ip_forward
sysctl vm.swappiness
# 임시 변경 (재부팅 시 초기화)
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w vm.swappiness=10
# /proc/sys/를 통해 직접 조회/변경
cat /proc/sys/net/ipv4/ip_forward
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward영구 설정
# /etc/sysctl.conf 또는 /etc/sysctl.d/*.conf 에 추가
# 예: /etc/sysctl.d/99-custom.conf
net.ipv4.ip_forward = 1
vm.swappiness = 10
net.core.somaxconn = 65535
fs.file-max = 2097152
net.ipv4.tcp_max_syn_backlog = 65535
# 적용
sudo sysctl -p # /etc/sysctl.conf 적용
sudo sysctl -p /etc/sysctl.d/99-custom.conf # 특정 파일 적용
sudo sysctl --system # 모든 설정 파일 적용주요 커널 파라미터
| 파라미터 | 설명 | 기본값 |
|---|---|---|
net.ipv4.ip_forward | IP 포워딩 (라우터 역할) | 0 |
vm.swappiness | swap 사용 적극성 | 60 |
fs.file-max | 시스템 전체 최대 파일 핸들 수 | ~100000 |
net.core.somaxconn | 소켓 listen 백로그 최대값 | 4096 |
net.ipv4.tcp_max_syn_backlog | SYN 대기 큐 크기 | 128~1024 |
kernel.pid_max | 최대 PID 값 | 32768 |
vm.overcommit_memory | 메모리 오버커밋 정책 (0/1/2) | 0 |
10. 리소스 제한
ulimit - 현재 세션 리소스 제한
# 모든 제한 확인
ulimit -a
# soft limit 확인/설정 (일반 사용자가 변경 가능, hard 이하)
ulimit -n # 오픈 파일 수 확인 (soft)
ulimit -n 65535 # 변경
# hard limit 확인 (root만 변경 가능)
ulimit -Hn # 오픈 파일 수 hard limit
# 주요 옵션
ulimit -n # 오픈 파일 수 (nofile)
ulimit -u # 사용자 프로세스 수 (nproc)
ulimit -f # 파일 크기 (blocks)
ulimit -v # 가상 메모리 크기 (kbytes)
ulimit -c # 코어 덤프 크기 (blocks, 0=비활성화)
ulimit -s # 스택 크기 (kbytes)/etc/security/limits.conf - 영구 설정
# 형식: <domain> <type> <item> <value>
# domain: 사용자명, @그룹명, * (모든 사용자)
# type: soft, hard, - (양쪽 모두)
# item: nofile, nproc, memlock 등
# 예시:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
@developers soft nofile 100000
@developers hard nofile 100000
www-data soft nofile 100000
www-data hard nofile 100000
# systemd 서비스의 경우 limits.conf 대신 유닛 파일에서 설정
# [Service]
# LimitNOFILE=65535
# LimitNPROC=65535/etc/security/limits.d/
# limits.conf보다 우선적으로 적용되는 추가 설정
# 예: /etc/security/limits.d/99-custom.conf11. alternatives 시스템
같은 기능을 하는 여러 프로그램 중 기본 사용할 것을 관리하는 시스템.
update-alternatives (Debian/Ubuntu)
# 현재 설정 확인
sudo update-alternatives --display java
sudo update-alternatives --display editor
# 대화형으로 선택
sudo update-alternatives --config java
# Selection Path Priority
# --------------------------------------------------------
# * 0 /usr/lib/jvm/java-17-openjdk-amd64/bin/java 1711
# 1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111
# 2 /usr/lib/jvm/java-17-openjdk-amd64/bin/java 1711
# 수동 설정
sudo update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
# 새 대안 등록
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.11 2
# 형식: --install <링크> <이름> <경로> <우선순위>
# 대안 제거
sudo update-alternatives --remove python /usr/bin/python3.10
# 모든 alternatives 목록
sudo update-alternatives --get-selectionsalternatives (RHEL/CentOS)
# RHEL 계열도 동일한 명령 사용 가능
alternatives --config java
alternatives --display java활용 예시
# Python 버전 관리
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 2
sudo update-alternatives --config python3
# Java 버전 관리
sudo update-alternatives --config java
sudo update-alternatives --config javac
# 기본 에디터 변경
sudo update-alternatives --config editor
# 또는 환경 변수로
export EDITOR=vim
export VISUAL=vim실전 정리: 새 서버 초기 환경 설정 체크리스트
# 1. 시간대 설정
sudo timedatectl set-timezone Asia/Seoul
# 2. 로케일 설정
sudo localectl set-locale LANG=ko_KR.UTF-8
# 3. 호스트네임 설정
sudo hostnamectl set-hostname myserver
# 4. 커널 파라미터 조정
cat << 'EOF' | sudo tee /etc/sysctl.d/99-custom.conf
net.core.somaxconn = 65535
fs.file-max = 2097152
vm.swappiness = 10
EOF
sudo sysctl --system
# 5. 리소스 제한 설정
cat << 'EOF' | sudo tee /etc/security/limits.d/99-custom.conf
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
EOF
# 6. 쉘 환경 설정 (~/.bashrc)
cat << 'EOF' >> ~/.bashrc
# Custom aliases
alias ll='ls -alF --color=auto'
alias grep='grep --color=auto'
# History settings
export HISTSIZE=10000
export HISTFILESIZE=20000
export HISTTIMEFORMAT="%F %T "
shopt -s histappend
# Default editor
export EDITOR=vim
export VISUAL=vim
EOF
source ~/.bashrc