diff --git a/bin/sgit b/bin/sgit index fb68f2d47..f865948b0 100755 --- a/bin/sgit +++ b/bin/sgit @@ -5,28 +5,33 @@ # # 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) but this can be -# overridden with the -I option. See -h option for all the options. +# 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 good to add any additional features -# except perhaps allowing for one to specify path to sed. +# 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.7-1 12-04-2023" # format: major.minor.patch-release DD-MM-YYYY +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] [-o sed_options] [-s sed] [-e command] +USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-x] [-I] [-i extension] [-o sed_options] [-s sed] [-e command] -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 '-') + -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 @@ -38,6 +43,7 @@ export SED export SED_OPTIONS="" export I_FLAG= export VERBOSITY=0 +export EXTENSION="" # we need an array for sed commands declare -a SED_COMMANDS @@ -47,7 +53,7 @@ IFS=$'\t\n' # parse args # -while getopts :hVv:xIo:s:e: flag; do +while getopts :hVv:xIi:o:s:e: flag; do case "$flag" in h) echo "$USAGE" 1>&2 exit 2 @@ -61,6 +67,8 @@ while getopts :hVv:xIo:s:e: flag; do ;; I) I_FLAG="-I" ;; + i) EXTENSION="$OPTARG" + ;; o) SED_OPTIONS="-$OPTARG" ;; s) SED="$OPTARG" @@ -148,6 +156,12 @@ 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 @@ -155,12 +169,13 @@ while [[ "$i" -lt "$GLOBS" ]]; do 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\"\" $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2 + 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\"\" ${SED_COMMANDS[*]}" 1>&2 + 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 @@ -173,9 +188,9 @@ while [[ "$i" -lt "$GLOBS" ]]; do if [[ -z "$I_FLAG" ]]; then if [[ -n "$SED_OPTIONS" ]]; then - git ls-files "$1" | xargs "$SED" -i"" "$SED_OPTIONS" "${SED_COMMANDS[@]}" + git ls-files "$1" | xargs "$SED" -i"$EXTENSION" "$SED_OPTIONS" "${SED_COMMANDS[@]}" else - git ls-files "$1" | xargs "$SED" -i"" "${SED_COMMANDS[@]}" + git ls-files "$1" | xargs "$SED" -i"$EXTENSION" "${SED_COMMANDS[@]}" fi else if [[ -n "$SED_OPTIONS" ]]; then diff --git a/bin/sgit.README.md b/bin/sgit.README.md index e3d716076..32f6e4c54 100644 --- a/bin/sgit.README.md +++ b/bin/sgit.README.md @@ -7,36 +7,71 @@ efficiency because it ran git ls-files for each `sed` command. Now it is a bit more thorough and is more efficient (though not perfect). It allows you to specify a path to `sed`, `sed` options and multiple `sed` commands -(though this always existed). The default behaviour is to use in place editing -**WITHOUT A BACKUP EXTENSION** but you may override the saving to disk with the -`-I` option. +(though this always existed). The _default_ behaviour is to use in place editing +(**WITHOUT A BACKUP EXTENSION**; use `-i` to provide a backup extension) but you +can override the saving to disk with the `-I` option. ## Usage ```sh -usage: sgit [-h] [-V] [-v level] [-x] [-I] [-o sed_options] [-s sed] [-e command] +usage: sgit [-h] [-V] [-v level] [-x] [-I] [-i extension] [-o sed_options] [-s sed] [-e command] -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 '-') + -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 execute on globs - -sgit version: 0.0.7-1 12-04-2023 + -e command append sed command to to list to execute on globs +sgit version: 0.0.8-1 19-04-2023 ``` You **MUST** specify at least one `sed` command and one glob: the sed command by way of the `-e` option (just like with `sed`); anything after the last option is a glob. You may specify more than one of each. Specify `-e` for each command. +# A note about the `-i` option and backup extensions + +It works like `sed -i` except that the default behaviour of the script is to use +`-i` just with an empty backup extension (this is required for some versions of +`sed` which force that a backup extension actually be provided with the `-i` +option .. I'm looking at you, BSD/macOS `sed`). + + +# `-i` WARNING: each file edited will result in another file in the working directory + +Of course if you have 50 files that are affected then 50 new files will be +created. + +# `-i` WARNING: `sed -i` **WILL OVERWRITE EXISTING FILES**! + +Please be aware that if a backup file already exists it **WILL** be overwritten! +I won't even try and detect this because it's not how `sed` works and it would +overly complicate the script. + + +# `-o n` WARNING: invalid use of -o n can empty files! + +Because `sed -n` does not print output if you do not use `-I` and you use +substitute you can empty the entire file. For instance **DO NOT** do this: + + +```sh +./sgit -o n -e 's/.//g' sgit +``` + +because it would empty `sgit`! + + # Examples -## Change in this file (in memory only) `\` to be `used` but only show lines changed: +## Change in this file (_IN MEMORY ONLY_) `\` to `used` but only show lines changed: ```sh ./sgit -I -o n -e 's/\/used/p' README.md @@ -53,38 +88,69 @@ needs to be: ./sgit -I -o n -e '/\/p' . ``` -## Change references of `\` to be `used` in this file and save it: +## With tracing enabled, change references of `\` to `used` in this file and save it: ```sh -./sgit -e 's/\/used/p' -v3 -x README.md +./sgit -e 's/\/used/g' -x README.md ``` -## Change `\` to `used` but only if it's on the third line + +## With tracing enabled, change references of `\` to `used`, duplicating the lines, in this file and save it: ```sh -./sgit -e '3s/\/used/g' README.md +./sgit -e 's/\/used/p' -x README.md + +``` + +## Verbosely (level 1) change references of `\` to `used` in this file and save it: + +```sh +./sgit -e 's/\/used/g' -v1 README.md + +``` + +## Verbosely (level 3) change references of `\` to `used` in this file with a backup as `README.md.bak` + +```sh +./sgit -i.bak -e 's/\/used/g' -v3 README.md + +``` + +With that you would see something like: + +```sh +debug[2]: sed commands: -e s/\/used/g +debug[2]: looping through all globs +debug[1]: using backup extension: .bak +debug[2]: found glob: 0 +debug[1]: about to run: git ls-files README.md | xargs /opt/local/bin/sed -i".bak" -e s/\/used/g +debug[2]: 0 remaining globs +``` + +Level 2 would not show how many globs remain after each operation. + + +## Change `\` to `used` but only if it's on the first line + +```sh +./sgit -e '1s/\/used/g' README.md ``` Alternatively you could do one of: ```sh -./sgit -e '3s/\/u&/g' README.md -./sgit -e '3s/\(\\)/u\1/g' README.md +./sgit -e '1s/\/u&/g' README.md +./sgit -e '1s/\(\\)/u\1/g' README.md ``` -# WARNING: invalid use of -o -n can empty files! - -Because `sed -n` does not print output if you do not use `-I` and you use -substitute you can empty the entire file. For instance **DO NOT** do this: - +## Change `\` to `crack` but only if it's on the third line ```sh -./sgit -o n -e 's/.//g' sgit +./sgit -e '3s/\/crack/g' README.md ``` -because it would empty `sgit`! ## Installation