[2025-07-19] Mac 초기 설정 (개발자용)
안녕하세요 클스 입니다.
드디어 M4 16인치 맥을 구매했습니다. 그러나 매번 맥을 초기화하는 것은 힘들죠,
그리고 기존 인텔맥에서 M1으로 변경된 시점에 백업,복원 하기엔 불안함도 있고, 클린 설치하고 싶기도 한데, Mac 초기 설정하는 것은 매우 시간이 많이 듭니다.
그래서 반드시 맥에 필수로 개발할때 셋팅하는 스크립트를 작성했습니다.
사전 준비:
1. 맥에 사용자 계정과 sudo 권한 준비
2. M1 이상 맥북
설치할 순서:
1. shell 은 zsh 로 가정
2. homebrew 설치, brew update, upgrade
3. wget, curl, openssl, rsync
4. oh my zsh,
4.1 plugin : zsh-autosuggestions, zsh-syntax-highlighting
------------------- 이후는 별도 스크립트로 작성할 예정입니다. --------------------
5. poetry, pyenv, virtual-env, uv
6. nvm, node, npm, pnpm
7. python
------------------------------------
$ vi install_mack.sh
#!/bin/zsh
set -e
# ─────────────────────────────────────────────
# Mac DevBox Full Setup Script (Interactive)
# By 클스AI
# ─────────────────────────────────────────────
# ───────────── 1. 유틸 함수 ─────────────
print_header() {
echo -e "\n🔹 $1 🔹"
}
ask_install() {
read -r "ans?➡️ $1 설치하시겠습니까? (Y/n) "
[[ -z "$ans" || "$ans" =~ ^[Yy]$ ]]
}
confirm() {
local prompt="$1"
local ans
read "ans?➡️ $prompt [Y/n] "
[[ -z "$ans" || "$ans" =~ ^[Yy]$ ]]
}
# ───────────── 2. OS/SED 세팅 ─────────────
print_header "OS 버전 확인 [$(uname)]"
if [[ "$(uname)" == "Darwin" ]]; then
SED_INPLACE=(-i '')
else
SED_INPLACE=(-i)
fi
echo "현재 실행 중인 shell: $(ps -p $$ -o comm=)"
echo "전체 실행 경로: $(ps -p $$ -o args=)"
# ───────────── 4. sudo 권한 ─────────────
print_header "sudo 권한 요청"
sudo -v
# ───────────── 5. macOS/Xcode 업데이트 ─────────────
if ask_install "macOS 및 Xcode Command Line Tools 전체 업데이트"; then
echo "✅ macOS 및 Xcode CLI 도구 업데이트 진행 중..."
softwareupdate --all --install
if ! xcode-select -p &>/dev/null; then
echo "🛠 Command Line Tools가 설치되지 않아 자동 설치 시도"
xcode-select --install
print_header "설치가 완료되면 엔터를 눌러주세요"
read -r
fi
elif ! xcode-select -p &>/dev/null; then
if ask_install "Command Line Tools 설치"; then
xcode-select --install
print_header "설치가 완료되면 엔터를 눌러주세요"
read -r
fi
fi
# ───────────── 6. Rosetta (Apple Silicon 전용) ─────────────
if [[ "$(uname -m)" == "arm64" ]] && ! pgrep -x oahd &>/dev/null; then
print_header "Rosetta 2 설치"
softwareupdate --install-rosetta --agree-to-license
fi
# ───────────── 3. 기존 zsh/oh-my-zsh 백업 및 삭제 ─────────────
if confirm "zsh 및 Oh My Zsh 환경을 완전히 초기화(재설치)하시겠습니까?"; then
rm -f ~/.zshrc
rm -rf ~/.oh-my-zsh
echo "🧹 .zshrc, .oh-my-zsh 모두 삭제(초기화) 완료!"
else
echo "ℹ️ zsh/Oh My Zsh 초기화(삭제) 건너뜁니다."
fi
# ───────────── 7. Homebrew 설치/업데이트 ─────────────
print_header "Homebrew 설치/업데이트"
if ! command -v brew &>/dev/null; then
/bin/bash -c \
"$(curl -k -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# ─────────────────────────────
# ⬆️ Homebrew 최신화
# ─────────────────────────────
if command -v brew &>/dev/null; then
print_header "Homebrew 패키지 정보 최신화"
brew update
brew upgrade
fi
# ───────────── 8. zsh 설치 및 기본 쉘 설정 ─────────────
print_header "zsh 설치 및 기본 쉘 설정"
if brew list --formula | grep -q "^zsh\$"; then
if confirm "zsh는 이미 설치되어 있습니다. 최신 버전으로 업그레이드하시겠습니까?"; then
brew upgrade zsh
else
echo "zsh 업그레이드 건너뜁니다."
fi
else
brew install zsh
fi
ZSH_PATH="$(which zsh)"
# 로그인 셸이 뭔지 확인 (dscl은 macOS 전용)
if [[ "$(uname)" == "Darwin" ]]; then
login_shell=$(dscl . -read /Users/$USER UserShell 2>/dev/null | grep '^UserShell:' | awk '{print $2}')
else
login_shell=$(getent passwd $USER | cut -d: -f7)
fi
# 현재 프로세스 실행 중인 셸
current_shell_running="$(ps -p $$ -o comm=)"
# 또는, 현재 환경변수(로그인 쉘) 사용
current_shell="$SHELL"
# echo "ZSH_PATH : $ZSH_PATH"
# echo "login_shell : $login_shell"
# echo "current_shell : $current_shell"
echo "current_running: $current_shell_running"
if [[ "$login_shell" == "$ZSH_PATH" ]]; then
echo "✔️ 기본 로그인 쉘이 이미 $ZSH_PATH 입니다."
else
if confirm "기본 로그인 쉘을 $ZSH_PATH 로 변경하시겠습니까?"; then
# 쉘 경로가 /etc/shells에 없다면 등록
if ! grep -Fxq "$ZSH_PATH" /etc/shells; then
echo "$ZSH_PATH" | sudo tee -a /etc/shells
fi
chsh -s "$ZSH_PATH"
print_header "기본 쉘이 $ZSH_PATH 으로 변경되었습니다. (터미널 재시작 필수)"
else
echo "기본 쉘 변경을 건너뜁니다."
fi
fi
# ───────────── 9. Oh My Zsh 및 플러그인 설치 ─────────────
if confirm "Oh My Zsh 설치/업데이트 및 플러그인 구성"; then
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
if [[ -d "$HOME/.oh-my-zsh" ]]; then
echo "🔄 Oh My Zsh가 이미 설치되어 있습니다. 업데이트 중…"
zsh -ic "omz update"
else
echo "📥 Oh My Zsh를 설치합니다…"
sh -c "$(curl -k -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
fi
for plugin in zsh-autosuggestions zsh-syntax-highlighting; do
PLUGIN_DIR="$ZSH_CUSTOM/plugins/$plugin"
if [[ -d "$PLUGIN_DIR" ]]; then
echo "✔️ 플러그인 '$plugin' 이미 설치됨"
else
echo "➕ 플러그인 '$plugin' 설치 중…"
git clone "https://github.com/zsh-users/$plugin" "$PLUGIN_DIR"
fi
done
fi
# ───────────── 10. plugins=() 라인 관리 ─────────────
touch ~/.zshrc
if grep -q '^plugins=' ~/.zshrc; then
plugins_raw=$(grep '^plugins=' ~/.zshrc | head -1 | sed 's/^plugins=//' | tr -d '()')
plugins_arr=(${(z)plugins_raw})
typeset -U plugins_arr
plugins_arr+=('zsh-autosuggestions' 'zsh-syntax-highlighting')
new_plugins="plugins=(${plugins_arr[*]})"
sed "${SED_INPLACE[@]}" -E "s/^plugins=\(.*\)/$new_plugins/" ~/.zshrc
else
echo "\nplugins=(zsh-autosuggestions zsh-syntax-highlighting)" >> ~/.zshrc
fi
echo "🔧 plugins 라인 구성 완료"
# ───────────── 11. ZSH_THEME 교체 (robbyrussell → eastwood, 개행) ─────────────
THEME_LINE=$(grep -n '^ZSH_THEME="robbyrussell"' ~/.zshrc | cut -d: -f1)
if [[ -n "$THEME_LINE" ]]; then
sed "${SED_INPLACE[@]}" "${THEME_LINE}s/^/#/" ~/.zshrc
if [[ "$(uname)" == "Darwin" ]]; then
sed "${SED_INPLACE[@]}" "$((THEME_LINE+1))i\\
ZSH_THEME=\"eastwood\"\\
\\
" ~/.zshrc
else
sed "${SED_INPLACE[@]}" "$((THEME_LINE+1))i ZSH_THEME=\"eastwood\"\n" ~/.zshrc
sed "${SED_INPLACE[@]}" "$((THEME_LINE+2))i " ~/.zshrc
fi
echo "🎨 ZSH_THEME 변경: 'robbyrussell' → 'eastwood' (개행 포함)"
else
echo "⚠️ ZSH_THEME=\"robbyrussell\" 라인이 없습니다. 직접 확인 요망"
fi
# 6. 기본 CLI 도구 설치
###############################################################################
print_header "기본 CLI 도구 설치 (curl wget jq openssl python) 및 업그레이드"
# ───────────── 패키지 목록 선언 (재활용!) ─────────────
BREW_PACKAGES=(
curl
wget
git
subversion
rsync
jq
zlib
sqlite3
xz
readline
ncurses
openssl
python
asitop
showcert
libiconv
convmv
tree
)
# ───────────── 패키지 설치/업그레이드 루프 ─────────────
for pkg in "${BREW_PACKAGES[@]}"; do
if brew list --formula | grep -qx "$pkg"; then
echo "✔️ $pkg 설치됨. 업데이트 가능한지 확인 중…"
if brew outdated --formula | grep -qx "$pkg"; then
echo "⬆️ $pkg 업그레이드 중..."
brew upgrade "$pkg"
else
echo "✅ $pkg는 최신 버전입니다."
fi
else
echo "➕ $pkg가 설치되지 않았습니다. 설치합니다…"
brew install "$pkg"
fi
done
append_custom_setting_block() {
local zshrc="$HOME/.zshrc"
local mark_begin="# AI Solution Basic Block Begin ---------"
local mark_end="# AI Solution Basic Block End ---------"
mkdir -p ~/cncity/devtools
mkdir -p ~/svn
mkdir -p ~/data
# 👉 여기서 BREW_PACKAGES를 그대로 사용!
local PATH_LINE=""
for pkg in "${BREW_PACKAGES[@]}"; do
local bin_path="$(brew --prefix $pkg 2>/dev/null)/bin"
if [[ -d "$bin_path" ]]; then
PATH_LINE="${PATH_LINE:+$PATH_LINE:}$bin_path"
fi
done
if [[ -n "$PATH_LINE" ]]; then
PATH_LINE="export PATH=\".:$PATH_LINE:\$PATH\""
fi
touch "$zshrc"
if grep -F -q "$mark_begin" "$zshrc"; then
echo "➖ {$mark_begin} 블록이 이미 .zshrc에 존재합니다. 중복 추가하지 않습니다."
else
echo "➕ {$mark_begin} 블록을 .zshrc에 추가합니다."
cat << EOF >> "$zshrc"
${mark_begin}
${PATH_LINE}
# git 계열 ssl 무시
export GIT_SSL_NO_VERIFY=true
# 히스토리 설정
HISTSIZE=3000
SAVEHIST=3000
HISTFILE=~/.zsh_history
# Alias
alias ll='ls -alF'
alias lll='ls -al'
alias la='ls -A'
alias l='ls -CF'
alias grep='grep --color=auto'
alias show-openport="lsof -PiTCP -sTCP:LISTEN"
alias gputop="sudo asitop"
alias docker=podman
mcd() { mkdir -p "$1" && cd "$1"; }
${mark_end}
EOF
echo "✅ {$mark_begin} 블록이 추가되었습니다."
fi
}
append_custom_setting_block
#---------------- /etc/hosts -------------
replace_host_block() {
local hosts_file="/etc/hosts"
local mark_begin="# My Host Begin"
local mark_end="# My Host End"
local tmpfile
tmpfile=$(mktemp)
# ✅ 교체할 블록 내용 (필요시 주인님이 수정 가능)
local block_content
block_content=$(cat << 'EOF'
# My Host Begin --------
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section
# SSL for local
127.0.0.1 localtest.dev
# End SSL
# My Host End --------
EOF
)
# 🔄 기존 블록이 있으면 교체, 없으면 추가
if grep -Fq "$mark_begin" "$hosts_file"; then
sudo awk -v begin="$mark_begin" -v end="$mark_end" -v content="$block_content" '
$0 ~ begin { print content; skip=1; next }
$0 ~ end { skip=0; next }
skip==0 { print }
' "$hosts_file" > "$tmpfile" && sudo mv "$tmpfile" "$hosts_file"
echo "♻️ 기존 Host Block을 교체했습니다."
else
printf "\n%s\n" "$block_content" | sudo tee -a "$hosts_file" >/dev/null
echo "✅ Host Block이 추가되었습니다."
fi
}
if confirm "AI 솔루션팀 /etc/hosts 파일을 구성하시겠습니까?(Y/N)"; then
replace_host_block
fi
# ───────────── 13. 완료 메시지 ─────────────
print_header "🎉 모든 설정이 완료되었습니다!"
printf "\n🎉 모든 설정이 완료되었습니다!\n"
echo "source ~/.zshrc 를 실행하세요."
----------------------------------------------------------------------------------------
:wq
----------------------------------------------------------------------------------------
파일에 실행 권한 부여
$ chmod +x install_mac.sh
--------------------------------
스크립트는 본인의 환경에 맞게 필요한 것을 설치하면 됩니다.
이상 클스 였습니다.
댓글
댓글 쓰기