#!/usr/bin/env bash set -euo pipefail usage() { echo "Usage: $(basename "$0") -c COMMENT_SYMBOL [-e EXCLUDE_PATTERN]... TARGET" echo " -c Comment symbol (e.g., '#' or '//')" echo " -e Exclude pattern (can be specified multiple times)" echo " TARGET File or directory to process" exit 1 } comment_sym="" excludes=() while getopts "c:e:h" opt; do case $opt in c) comment_sym="$OPTARG" ;; e) excludes+=("$OPTARG") ;; h) usage ;; *) usage ;; esac done shift $((OPTIND - 1)) [[ $# -ne 1 ]] && usage [[ -z "$comment_sym" ]] && usage target="$(realpath "$1")" base_dir="$(pwd)" process_file() { local file="$1" # shellcheck disable=SC2295 local rel_path="${file#$base_dir/}" local path_comment="$comment_sym path: $rel_path" # Read first two lines local line1 line2 IFS= read -r line1 <"$file" 2>/dev/null || line1="" IFS= read -r line2 < <(tail -n +2 "$file") 2>/dev/null || line2="" # Handle shebang case if [[ "$line1" =~ ^#! ]]; then if [[ "$line2" == *"path: "* ]]; then # Replace existing path comment on line 2 { echo "$line1" echo "$path_comment" tail -n +3 "$file" } >"$file.tmp" else # Insert new path comment after shebang { echo "$line1" echo "$path_comment" tail -n +2 "$file" } >"$file.tmp" fi else if [[ "$line1" == *"path: "* ]]; then # Replace existing path comment on line 1 { echo "$path_comment" tail -n +2 "$file" } >"$file.tmp" else # Insert new path comment at top { echo "$path_comment" cat "$file" } >"$file.tmp" fi fi mv "$file.tmp" "$file" } if [[ -f "$target" ]]; then process_file "$target" elif [[ -d "$target" ]]; then find_cmd=(find "$target") # Always exclude hidden files and directories find_cmd+=(\( -name ".*" -prune \)) if [[ ${#excludes[@]} -gt 0 ]]; then find_cmd+=(-o \() for i in "${!excludes[@]}"; do [[ $i -gt 0 ]] && find_cmd+=(-o) find_cmd+=(-path "*/${excludes[$i]}" -prune) find_cmd+=(-o -path "*/${excludes[$i]}/*" -prune) done find_cmd+=(\)) fi find_cmd+=(-o -type f -print0) while IFS= read -r -d '' file; do process_file "$file" done < <("${find_cmd[@]}") else echo "Error: $target is not a file or directory" >&2 exit 1 fi