Files
ioccc/bin/sgit
T
Cody Boone Ferguson 1464a25e5a Fix spaces in sed commands in sgit
New version of sgit.

Script now allows for spaces in sed commands. Thus one can do something
like:

    sgit -v3 -x -e 's/web site/website/g'  .

to set verbosity to level 3, turn on tracing (see below) and change
occurrences of 'web site' to be 'website'.

Also added -x option to turn on tracing.
2023-02-15 06:21:10 -08:00

122 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# sgit - sed -i on all files under git control
#
# usage: sgit -e 'sed command'... <glob...>
#
# This script will allow one to update files under git control without having to
# come up with a list of files and then passing those to the command. It allows
# for multiple sed commands (all with in-place editing) and multiple globs.
#
# 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 good to add any additional features
# except perhaps allowing for one to specify path to sed.
#
# - Cody Boone Ferguson (@xexyl)
#
export SGIT_VERSION="0.0.2-1 13-02-2023" # format: major.minor.patch-release DD-MM-YYYY
USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-x] [-e command] <glob...>
-h print help and exit
-V print version and exit
-x turn on tracing (set -x)
-v level set verbosity level
-e command append sed command to execute on globs
sgit version: $SGIT_VERSION"
export VERBOSITY=0
# parse args
#
while getopts :hVxv:e: flag; do
case "$flag" in
h) echo "$USAGE" 1>&2
exit 2
;;
V) echo "$SGIT_VERSION" 1>&2
exit 2
;;
x) set -x
;;
v) VERBOSITY="$OPTARG";
;;
e) SED_COMMANDS+=(-e "$OPTARG")
;;
:) 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
# 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 is 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 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
i=0
while [[ "$i" -le "$#" ]]; do
if [[ "$VERBOSITY" -gt 1 ]]; then
echo "debug[2]: found glob: $1" 1>&2
fi
if [[ "$VERBOSITY" -ge 1 ]]; then
echo "debug[1]: about to run: git ls-files $1 | xargs sed -i\"\" ${SED_COMMANDS[*]}" 1>&2
fi
# shellcheck disable=SC2086
# SC2086 (info): Double quote to prevent globbing and word splitting. We can't
# quote this because we need to have word splitting.
git ls-files "$1" | xargs sed -i"" "${SED_COMMANDS[@]}"
((i++))
shift 1
done