#!/usr/bin/env bash set -euo pipefail usage() { echo "Usage: $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)" should_exclude() { local path="$1" for pattern in "${excludes[@]}"; do if [[ "$path" == *"$pattern"* ]]; then return 0 fi done return 1 } process_file() { local file="$1" local rel_path="${file#"$base_dir"/}" should_exclude "$rel_path" && return 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="" # Check if path comment exists in first or second line [[ "$line1" == *"path: "* ]] && return [[ "$line2" == *"path: "* ]] && return # Insert after shebang if present, otherwise at top if [[ "$line1" =~ ^#! ]]; then { echo "$line1" echo "$path_comment" tail -n +2 "$file" } >"$file.tmp" else { echo "$path_comment" cat "$file" } >"$file.tmp" fi mv "$file.tmp" "$file" } if [[ -f "$target" ]]; then process_file "$target" elif [[ -d "$target" ]]; then while IFS= read -r -d '' file; do process_file "$file" done < <(find "$target" -type f -print0) else echo "Error: $target is not a file or directory" >&2 exit 1 fi