Created
February 1, 2026 10:48
-
-
Save kuyagic/b573c3cfa7f038ecc51006e01a340300 to your computer and use it in GitHub Desktop.
Generate the file list based on the ignore configuration and CACHEDIR.TAG.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| fdfile() { | |
| local output_file="" | |
| local OPTIND opt | |
| # === 选项解析:仅支持 -o output_file === | |
| while getopts "o:" opt; do | |
| case "$opt" in | |
| o) output_file="$OPTARG" ;; | |
| *) | |
| echo "Usage: fdfile [-o OUTPUT_FILE] DIR1 [DIR2 ...]" >&2 | |
| echo " -o FILE Write results to FILE instead of stdout" >&2 | |
| return 1 | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| # === 参数校验:至少需要一个目录 === | |
| if [[ $# -eq 0 ]]; then | |
| echo "❌ Error: At least one directory argument required" >&2 | |
| echo "Usage: fdfile [-o OUTPUT_FILE] DIR1 [DIR2 ...]" >&2 | |
| return 1 | |
| fi | |
| # === 创建全局临时目录(用于 EXIT trap 清理) === | |
| _FDFILE_TEMP_DIR=$(mktemp -d) || { | |
| echo "❌ mktemp failed" >&2 | |
| return 1 | |
| } | |
| cleanup() { | |
| [[ -n "${_FDFILE_TEMP_DIR:-}" ]] && rm -rf "$_FDFILE_TEMP_DIR" | |
| } | |
| trap cleanup EXIT | |
| # === 保留文件清单(用于缓存目录内白名单) === | |
| local KEEP_IN_CACHE_DIR=( | |
| "CACHEDIR.TAG" | |
| ".ignore" | |
| ".gitignore" | |
| ".fdignore" | |
| ".rgignore" | |
| ".kopiaignore" | |
| ) | |
| printf '%s\n' "${KEEP_IN_CACHE_DIR[@]}" > "$_FDFILE_TEMP_DIR/keep_in_cache.txt" | |
| local RESULT="$_FDFILE_TEMP_DIR/files.txt" | |
| > "$RESULT" | |
| # === 遍历所有目录参数 === | |
| local ROOT | |
| for ROOT in "$@"; do | |
| [[ -z "$ROOT" ]] && continue | |
| ROOT="$(realpath "$ROOT" 2>/dev/null)" || { | |
| echo "⚠️ Invalid path: $ROOT" >&2 | |
| continue | |
| } | |
| [[ -d "$ROOT" ]] || { | |
| echo "⚠️ Skip non-dir: $ROOT" >&2 | |
| continue | |
| } | |
| echo "🔎 Scanning $ROOT" >&2 | |
| # 生成唯一临时文件名(基于目录路径哈希) | |
| local HASH | |
| HASH=$(printf '%s' "$ROOT" | sha1sum 2>/dev/null | cut -c1-8 || echo "default") | |
| local FD_LIST="$_FDFILE_TEMP_DIR/fd_${HASH}.txt" | |
| local CACHE_DIRS="$_FDFILE_TEMP_DIR/cache_dirs_${HASH}.txt" | |
| # Step 1: 使用 fdfind 获取文件列表(尊重 ignore 规则) | |
| (cd "$ROOT" && fdfind --type f --hidden --strip-cwd-prefix 2>/dev/null) > "$FD_LIST" || { | |
| echo "⚠️ fd failed in $ROOT" >&2 | |
| continue | |
| } | |
| # Step 2: 查找所有包含 CACHEDIR.TAG 的缓存目录 | |
| find "$ROOT" -name CACHEDIR.TAG -exec dirname {} \; 2>/dev/null | sed 's|/*$|/|' > "$CACHE_DIRS" | |
| # Step 3: 过滤逻辑 | |
| local relpath abspath basename cache_dir in_cache_dir | |
| while IFS= read -r relpath || [[ -n "$relpath" ]]; do | |
| [[ -z "$relpath" ]] && continue | |
| abspath="$ROOT/$relpath" | |
| basename="${relpath##*/}" | |
| in_cache_dir=false | |
| while IFS= read -r cache_dir || [[ -n "$cache_dir" ]]; do | |
| [[ -z "$cache_dir" ]] && continue | |
| [[ "$abspath/" == "$cache_dir"* ]] && { in_cache_dir=true; break; } | |
| done < "$CACHE_DIRS" | |
| if $in_cache_dir; then | |
| grep -Fxq "$basename" "$_FDFILE_TEMP_DIR/keep_in_cache.txt" 2>/dev/null && echo "$abspath" | |
| else | |
| echo "$abspath" | |
| fi | |
| done < "$FD_LIST" >> "$RESULT" | |
| done | |
| # === 输出结果:根据 -o 参数决定输出目标 === | |
| if [[ -n "$output_file" ]]; then | |
| if ! sort -u "$RESULT" > "$output_file"; then | |
| echo "❌ Failed to write output to: $output_file" >&2 | |
| return 1 | |
| fi | |
| echo "✅ Results written to: $output_file" >&2 | |
| else | |
| sort -u "$RESULT" | |
| fi | |
| } | |
| # === 新增:如果脚本被直接执行,则调用函数 === | |
| if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then | |
| # 被直接执行(而非被 source) | |
| fdfile "$@" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment