Skip to content

Instantly share code, notes, and snippets.

@yelban
Created November 10, 2024 06:54
Show Gist options
  • Save yelban/e6b90a96e3afb3d37e652b7756aefbd0 to your computer and use it in GitHub Desktop.
Save yelban/e6b90a96e3afb3d37e652b7756aefbd0 to your computer and use it in GitHub Desktop.
A bash script for recursively finding and replacing text in files while respecting directory exclusions. Specially optimized for macOS with UTF-8 support.
#!/bin/bash
# 遞迴搜尋並取代字串,支援預設排除目錄與預覽模式
# 使用方式: ./script.sh [-p|--preview] "要尋找的字串" "要替換的字串"
# 預設排除的目錄清單
DEFAULT_EXCLUDES=(
"node_modules"
".git"
".next"
"dist"
"build"
".cache"
".terraform"
"coverage"
".DS_Store"
".idea"
".vscode"
"__pycache__"
"vendor"
"tmp"
".npm"
"logs"
)
# ANSI 顏色碼
BLUE='\033[0;34m'
CYAN='\033[0;36m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 初始化預覽模式標記
PREVIEW_MODE=0
# 設定 UTF-8 編碼環境
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
# 檢測作業系統型別並設定適當的 sed 命令
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS (BSD) sed
SED_CMD="sed -i ''"
else
# GNU sed
SED_CMD="sed -i"
fi
# 解析命令列引數
while [[ $# -gt 0 ]]; do
case $1 in
-p|--preview)
PREVIEW_MODE=1
shift
;;
*)
if [ -z "$FIND" ]; then
FIND="$1"
elif [ -z "$REPLACE" ]; then
REPLACE="$1"
fi
shift
;;
esac
done
# 檢查必要引數
if [ -z "$FIND" ] || [ -z "$REPLACE" ]; then
echo "Usage: $0 [-p|--preview] [find string] [replace string]"
echo "Options:"
echo " -p, --preview Preview files that would be modified without making changes"
exit 1
fi
# 構建 find 命令的排除路徑引數
EXCLUDE_PARAMS=""
for dir in "${DEFAULT_EXCLUDES[@]}"; do
EXCLUDE_PARAMS="$EXCLUDE_PARAMS -not -path '*/$dir/*'"
done
# 預覽受影響的檔案與內容
preview_changes() {
local file="$1"
# 計算檔案中匹配的次數
local count=$(grep -c "$FIND" "$file")
echo -e "${BLUE}=== 檢查檔案: $file ${YELLOW}(找到 $count 處比對符合)${NC} ===${NC}"
# 使用 grep 顯示比對符合的行及其上下文(每個比對符合顯示前後 1 行)
# -n 選項新增行號
grep -n -C 1 --color=always "$FIND" "$file"
echo -e "${BLUE}----------------------------------------${NC}\n"
}
if [ $PREVIEW_MODE -eq 1 ]; then
echo -e "${CYAN}預覽模式: 將會影響以下檔案 (不會實際修改)${NC}"
echo -e "${CYAN}要搜尋的字串: '$FIND'${NC}"
echo -e "${CYAN}要替換成: '$REPLACE'${NC}"
echo -e "${BLUE}==========================================${NC}\n"
# 找出所有包含目標字串的檔案並顯示預覽
AFFECTED_FILES=$(eval "find . -type f $EXCLUDE_PARAMS -exec grep -l \"$FIND\" {} \;")
if [ -z "$AFFECTED_FILES" ]; then
echo -e "${CYAN}未找到任何包含目標字串的檔案${NC}"
else
# 對每個檔案顯示詳細預覽
TOTAL_MATCHES=0
while IFS= read -r file; do
# 計算當前檔案的匹配數
FILE_MATCHES=$(grep -c "$FIND" "$file")
TOTAL_MATCHES=$((TOTAL_MATCHES + FILE_MATCHES))
preview_changes "$file"
done <<< "$AFFECTED_FILES"
# 計算影響的檔案數量
FILE_COUNT=$(echo "$AFFECTED_FILES" | wc -l)
echo -e "${BLUE}==========================================${NC}"
echo -e "${CYAN}總計 $FILE_COUNT 個檔案將受影響${NC}"
echo -e "${CYAN}共找到 $TOTAL_MATCHES 處需要替換的文字${NC}"
fi
else
echo "執行替換作業..."
# 針對 macOS 修改的替換命令
if [[ "$OSTYPE" == "darwin"* ]]; then
eval "find . -type f $EXCLUDE_PARAMS -exec $SED_CMD \"s|${FIND}|${REPLACE}|g\" {} \;"
else
eval "find . -type f $EXCLUDE_PARAMS -exec $SED_CMD \"s|${FIND}|${REPLACE}|g\" {} \;"
fi
echo "替換作業完成"
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment