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.

Revisions

  1. yelban created this gist Nov 10, 2024.
    134 changes: 134 additions & 0 deletions script.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    #!/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