116 lines
2.3 KiB
Bash
Executable File
116 lines
2.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
echo "Usage: $(basename "$0") <command> [options] TARGET"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " add Add/update path comment in first 5 lines of each file"
|
|
echo " undo Remove any path comment from first 5 lines of each file"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -c Comment symbol (e.g., '#' or '//') [required for add]"
|
|
echo " -e Exclude pattern (can be specified multiple times)"
|
|
exit 1
|
|
}
|
|
|
|
[[ $# -lt 1 ]] && usage
|
|
|
|
cmd="$1"
|
|
shift
|
|
|
|
[[ "$cmd" != "add" && "$cmd" != "undo" ]] && usage
|
|
|
|
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
|
|
|
|
if [[ "$cmd" == "add" ]]; then
|
|
[[ -z "$comment_sym" ]] && {
|
|
echo "Error: -c is required for add" >&2
|
|
usage
|
|
}
|
|
fi
|
|
|
|
target="$(realpath "$1")"
|
|
base_dir="$(pwd)"
|
|
|
|
strip_path_comment() {
|
|
local file="$1"
|
|
awk 'NR <= 5 && /path: / { next } { print }' "$file" >"$file.tmp"
|
|
mv "$file.tmp" "$file"
|
|
}
|
|
|
|
process_file() {
|
|
local file="$1"
|
|
# shellcheck disable=SC2295
|
|
local rel_path="${file#$base_dir/}"
|
|
local path_comment="$comment_sym path: $rel_path"
|
|
|
|
strip_path_comment "$file"
|
|
|
|
local line1
|
|
IFS= read -r line1 <"$file" 2>/dev/null || line1=""
|
|
|
|
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"
|
|
}
|
|
|
|
dispatch() {
|
|
local file="$1"
|
|
if [[ "$cmd" == "add" ]]; then
|
|
process_file "$file"
|
|
else
|
|
strip_path_comment "$file"
|
|
fi
|
|
}
|
|
|
|
if [[ -f "$target" ]]; then
|
|
dispatch "$target"
|
|
elif [[ -d "$target" ]]; then
|
|
find_cmd=(find "$target" \( -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
|
|
dispatch "$file"
|
|
done < <("${find_cmd[@]}")
|
|
else
|
|
echo "Error: $target is not a file or directory" >&2
|
|
exit 1
|
|
fi
|