Now supports backup extension. Some warnings are noted in the usage (about backup extensions - one of which goes for sed in general) and the README.md file. Typo fixed the README.md file (some examples were in error for instance) as well and add additional examples. The new version corresponds to https://github.com/xexyl/sgit/commit/9fccaa8cd680d3ed7cd91516710a5672630b5dff; the README.md file had several new commits.
213 lines
5.9 KiB
Bash
Executable File
213 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# sgit - run sed (by default with -i) on all files (or one or more globs) under
|
|
# git control
|
|
#
|
|
# This script allows one to run sed under git control without having to come up
|
|
# with a list of files first and then passing those to the command.
|
|
#
|
|
# It allows for multiple sed commands and multiple globs. By default it uses -i
|
|
# to edit the file in place (WITHOUT BACKUP EXTENSION; use -i option if you want
|
|
# a backup!) but in place editing can be overridden with the -I option. See -h
|
|
# option for all the options.
|
|
#
|
|
# DISCLAIMER AND WARNING: this is something of a hack and might be error prone.
|
|
# It works for what is needed but possibly could be improved. Even so I like it
|
|
# how it is and I don't think it would do much good to add many more additional
|
|
# features.
|
|
#
|
|
# - Cody Boone Ferguson (@xexyl)
|
|
#
|
|
|
|
export SGIT_VERSION="0.0.8-1 19-04-2023" # format: major.minor.patch-release DD-MM-YYYY
|
|
|
|
USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-x] [-I] [-i extension] [-o sed_options] [-s sed] [-e command] <glob...>
|
|
|
|
-h print help and exit
|
|
-V print version and exit
|
|
-v level set verbosity level
|
|
-x turn on tracing (set -x)
|
|
-I disable in place editing
|
|
-i extension set backup extension (default none)
|
|
WARNING: sed -i overwrites existing files
|
|
WARNING: this will create another file for each file changed
|
|
-o sed options (NOTE: don't pass '-'!)
|
|
WARNING: use of '-o n' without '-I', can depending on command, empty files
|
|
-s sed set path to sed
|
|
-e command append sed command to to list to execute on globs
|
|
|
|
sgit version: $SGIT_VERSION"
|
|
|
|
SED="$(type -P sed)"
|
|
export SED
|
|
export SED_OPTIONS=""
|
|
export I_FLAG=
|
|
export VERBOSITY=0
|
|
export EXTENSION=""
|
|
|
|
# we need an array for sed commands
|
|
declare -a SED_COMMANDS
|
|
|
|
# we need to remove ' ' from the IFS!
|
|
IFS=$'\t\n'
|
|
|
|
# parse args
|
|
#
|
|
while getopts :hVv:xIi:o:s:e: flag; do
|
|
case "$flag" in
|
|
h) echo "$USAGE" 1>&2
|
|
exit 2
|
|
;;
|
|
V) echo "$SGIT_VERSION" 1>&2
|
|
exit 2
|
|
;;
|
|
v) VERBOSITY="$OPTARG";
|
|
;;
|
|
x) set -x
|
|
;;
|
|
I) I_FLAG="-I"
|
|
;;
|
|
i) EXTENSION="$OPTARG"
|
|
;;
|
|
o) SED_OPTIONS="-$OPTARG"
|
|
;;
|
|
s) SED="$OPTARG"
|
|
;;
|
|
e) SED_COMMANDS+=(-e "$OPTARG")
|
|
;;
|
|
\?) echo "$0: ERROR: invalid option: -$OPTARG" 1>&2
|
|
exit 3
|
|
;;
|
|
:) echo "$0: ERROR: option -$OPTARG requires an argument" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 3
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
done
|
|
|
|
shift $(( OPTIND - 1 ));
|
|
|
|
# firewall
|
|
|
|
# check that SED_COMMANDS is not empty!
|
|
if [[ -z "${SED_COMMANDS[*]}" ]]; then
|
|
echo "$(basename "$0"): ERROR: you must specify at least one sed command" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 2
|
|
fi
|
|
|
|
# check that sed is executable
|
|
if [[ -z "$SED" ]]; then
|
|
echo "$(basename "$0"): ERROR: sed cannot be empty" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 2
|
|
elif [[ ! -f "$SED" ]]; then
|
|
echo "$(basename "$0"): ERROR: sed is not a regular file: $SED" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 2
|
|
elif [[ ! -x "$SED" ]]; then
|
|
echo "$(basename "$0"): ERROR: sed is not an executable file: $SED" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 2
|
|
fi
|
|
|
|
# also check number of remaining args
|
|
if [[ "$#" -eq 0 ]]; then
|
|
echo "$(basename "$0"): ERROR: you must specify at least one glob" 1>&2
|
|
echo 1>&2
|
|
echo "$USAGE" 1>&2
|
|
exit 2
|
|
fi
|
|
|
|
# then check that this is a git repo!
|
|
git status 2>/dev/null 1>&2
|
|
status="$?"
|
|
if [[ "$status" -ne 0 ]]; then
|
|
echo "$(basename "$0"): ERROR: ${PWD} not a git repository" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $VERBOSITY -gt 1 ]]; then
|
|
echo "debug[2]: sed commands: ${SED_COMMANDS[*]}" 1>&2
|
|
fi
|
|
|
|
# This might not the best performance because it does this on all files of the
|
|
# glob rather than only those files matched by the glob with matching text but
|
|
# it's better than it used to be (it used to run git ls-files on the repo for
|
|
# each sed command so the more you had the slow it would become as it had to get
|
|
# the list of files each time!).
|
|
#
|
|
# A better approach would be to somehow use git grep to find files that match
|
|
# but this would complicate the command line (at least in anyway I can think of
|
|
# how to do it) so we do it on all files in the repo.
|
|
#
|
|
# But these would possibly require additional args to the command and
|
|
# unnecessarily complicate matters. Anyway it's something of a hack so it
|
|
# doesn't have to be perfect (not that there even is such a thing as perfect).
|
|
#
|
|
if [[ "$VERBOSITY" -gt 1 ]]; then
|
|
echo "debug[2]: looping through all globs" 1>&2
|
|
fi
|
|
|
|
if [[ -n "$EXTENSION" ]]; then
|
|
if [[ "$VERBOSITY" -ge 1 ]]; then
|
|
echo "debug[1]: using backup extension: $EXTENSION" 1>&2
|
|
fi
|
|
fi
|
|
|
|
GLOBS="$#"
|
|
i=0
|
|
while [[ "$i" -lt "$GLOBS" ]]; do
|
|
if [[ "$VERBOSITY" -gt 1 ]]; then
|
|
echo "debug[2]: found glob: $i" 1>&2
|
|
fi
|
|
|
|
|
|
if [[ "$VERBOSITY" -ge 1 ]]; then
|
|
if [[ -z "$I_FLAG" ]]; then
|
|
if [[ -n "$SED_OPTIONS" ]]; then
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"$EXTENSION\" $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2
|
|
else
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"$EXTENSION\" ${SED_COMMANDS[*]}" 1>&2
|
|
fi
|
|
else
|
|
if [[ -n "$SED_OPTIONS" ]]; then
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2
|
|
else
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED ${SED_COMMANDS[*]}" 1>&2
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$I_FLAG" ]]; then
|
|
if [[ -n "$SED_OPTIONS" ]]; then
|
|
git ls-files "$1" | xargs "$SED" -i"$EXTENSION" "$SED_OPTIONS" "${SED_COMMANDS[@]}"
|
|
else
|
|
git ls-files "$1" | xargs "$SED" -i"$EXTENSION" "${SED_COMMANDS[@]}"
|
|
fi
|
|
else
|
|
if [[ -n "$SED_OPTIONS" ]]; then
|
|
git ls-files "$1" | xargs "$SED" "$SED_OPTIONS" "${SED_COMMANDS[@]}"
|
|
else
|
|
git ls-files "$1" | xargs "$SED" "${SED_COMMANDS[@]}"
|
|
fi
|
|
fi
|
|
((i++))
|
|
shift 1
|
|
if [[ "$VERBOSITY" -gt 2 ]]; then
|
|
if [[ "$#" -eq 1 ]]; then
|
|
echo "debug[2]: $# remaining glob" 1>&2
|
|
else
|
|
echo "debug[2]: $# remaining globs" 1>&2
|
|
fi
|
|
fi
|
|
|
|
done
|