A problem existed where more than one command would not work (always or
in some conditions depending on the command: not sure which). This
prevented a fix in years.html which will be in the next commit. The sgit
repo has been updated with this fix as well.
The fix is to remove space from IFS and to change "${SED_COMMANDS[*]}"
to be "${SED_COMMANDS[@]}".
183 lines
5.0 KiB
Bash
Executable File
183 lines
5.0 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.5-1 16-02-2023" # format: major.minor.patch-release DD-MM-YYYY
|
|
|
|
USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-x] [-I] [-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
|
|
-o sed options (don't pass '-')
|
|
-s sed set path to sed
|
|
-e command append sed command to execute on globs
|
|
|
|
sgit version: $SGIT_VERSION"
|
|
|
|
SED="$(type -P sed)"
|
|
export SED
|
|
export SED_OPTIONS=""
|
|
export I_FLAG=
|
|
export VERBOSITY=0
|
|
|
|
# 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:xIo: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"
|
|
;;
|
|
o) SED_OPTIONS="-$OPTARG"
|
|
;;
|
|
s) SED="$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
|
|
|
|
# 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 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
|
|
if [[ -z "$I_FLAG" ]]; then
|
|
if [[ -n "$SED_OPTIONS" ]]; then
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"\" $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2
|
|
else
|
|
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"\" ${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"" "$SED_OPTIONS" "${SED_COMMANDS[@]}"
|
|
else
|
|
git ls-files "$1" | xargs "$SED" -i"" "${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
|
|
done
|