기본 콘텐츠로 건너뛰기

[2025-07-19] Mac 초기 설정 (M시리즈, 개발자용)

[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

--------------------------------




스크립트는 본인의 환경에 맞게 필요한 것을 설치하면 됩니다.

이상 클스 였습니다.

댓글

이 블로그의 인기 게시물

[quaser.dev][2014-09-14] 윈도우즈(10, 64bit)에 개발환경 설정하기

[quaser.dev][2014-09-14] 윈도우즈(10, 64bit)에 개발환경 설정하기

[2024-10-19] iPhone, iPad에서 ChatGPT로 PDF 생성시 한글 깨짐 해결 방법

iPhone, iPad에서 ChatGPT로 PDF 생성 시 한글 깨짐 해결 방법

[2025-04-16(수)] OpenAI gpt-4.1 시리즈 발표, Anthropic Claude에 대한 생각

OpenAI gpt-4.1 시리즈 발표, Anthropic Claude에 대한 생각 안녕하세요. 클스 입니다. 4/15일자로 openai가 gpt-4.1 시리즈를 발표 했습니다. 현재는 api로만 사용가능합니다. 점차 웹/앱 사용자에게 오픈 될거라 생각 됩니다. 비용상 문제로 4.1-mini, nano를 사용해서 chatbot을 만들어 보고 있습니다. 4o 시리즈 보다는 확실히 빠르고, 답변의 정확도는 올라간 것 같습니다. 앤트로픽 클로드와 비교를 많이 하는데, 업무 시스템 혹은 AI 솔루션을 개발하는 입장에서는 어떤 생태계를 제공하는가가 주요한 결정 입니다. AI관련 인력을 충분히 보유한 회사의 경우는 어떤걸 사용해도 좋을 결과를 가지겠지만 일반적인 챗봇 개발 절차를 보면 다음과 같이 볼 수 있습니다. 1. 문서를 준비한다. 대부분 pdf, text, markdown 2. 문서를 파싱해서 vectordb에 올린다.     - 별도 벡터디비 구성 필요. 어떤 db를 선택할지 고민 필요     - 어떤 Parser를 사용할지, 텍스트 오버래핑은 얼마가 적당한지 고민 필요        (회사의 문서가 워낙 많고, 다양하면 하나하나 테스트 해서 좋은걸 선택하는 것이 어렵다)     - 유사도 측정은 어떤 알고리즘을 써야할지 고민 필요     - llamaindex도 고민해야 함. 3. RAG flow를 만든다.     - langchain을 쓸지, 각 AI 벤더에서 제공하는 sdk를 쓸지 고민 필요       (대부분 락인이 되지 않으려면 langchain을 사용하면 좋지만, 벤더에 특화면 기능 적용이 늦음) 4. 챗봇 UI 앱을 만든다.     - 답변이 text 로 구성되다 보니. 그래프, 이미지등 복합적인 컨텐츠를 재배치 하여 표현하기 상당히 어렵네요. (이건 제가 실력이 모자라서 .. 패스) ...