Skip to content

Instantly share code, notes, and snippets.

@kitzberger
Last active January 27, 2025 16:34
Show Gist options
  • Save kitzberger/59a93e7136d006baa780f96607584501 to your computer and use it in GitHub Desktop.
Save kitzberger/59a93e7136d006baa780f96607584501 to your computer and use it in GitHub Desktop.
Git Replace
# --------------------------------------------------------------------
# 1st parameter: regex search string
# - if you wanna match brackets (, ), [, ] you need to escape them
# - otherwise they are handled as capture groups and character classes
# 2nd parameter: regex replace string (can be empty as well)
# - don't escape anything
# - back references to the first 3 capture groups can be used here: \1, \2 and \3
# --------------------------------------------------------------------
function gitreplace() {
if [ -z "$1" ]; then
echo "No pattern given!"
echo
echo "Examples:"
echo "gitreplace 'something old' 'nice and new'"
echo "gitreplace 'something really old' DROP/DROP+1/DROP+2/..."
echo "gitreplace 'old' 'new' <target>"
echo
echo "__BOL__ and __EOL__ can be used to match beginning and end of line!"
return
fi
search="$1"
replace="$2"
if [ -z "$3" ]; then
target="."
else
target="$3"
fi
# -----------------------
# Escape search parameter
# -----------------------
# Substitute escaped characters by temporary tokens
search="${search/\\\[/__SQUARE_OPEN__}"
search="${search/\\\]/__SQUARE_CLOSE__}"
search="${search/\\\(/__ROUND_OPEN__}"
search="${search/\\\)/__ROUND_CLOSE__}"
search="${search/\\\$/__DOLLAR__}"
search="${search/\\\./__DOT__}"
# Escape backslashes & slashes
search="${search//\\/\\\\}"
search="${search//\//\\/}"
# Re-substitute temporary tokens back to escape characters
search="${search/__SQUARE_OPEN__/\\\[}"
search="${search/__SQUARE_CLOSE__/\\\]}"
search="${search/__ROUND_OPEN__/\\\(}"
search="${search/__ROUND_CLOSE__/\\\)}"
search="${search/__DOLLAR__/\\\$}"
search="${search/__DOT__/\\\.}"
# Replace magic tokens
search="${search/__BOL__/\^}"
search="${search/__EOL__/\$}"
# --------------------------------------
# Find matching text files of repository
# --------------------------------------
# -l Instead of showing every matched line, show only the names of files that contain matches
# -I Don’t match the pattern in binary files
# -E extended regex
#echo git grep -l -I -E \""$search"\" -- "$target"
files=$(git grep -l -I -E "$search" -- "$target")
if [ -z "$files" ]; then
echo "No files found matching pattern '$search'!"
echo
echo "Hint: literal brackets have to be escaped!"
return
#else
# echo "Files: $files"
fi
# ------------------------
# Escape replace parameter
# ------------------------
# Substitute capture group back references by temporary tokens
replace="${replace//\\1/__REFERENCE_1__}"
replace="${replace//\\2/__REFERENCE_2__}"
replace="${replace//\\3/__REFERENCE_3__}"
# Escape backslashes & slashes
replace="${replace//\\/\\\\}"
replace="${replace//\//\\/}"
# Re-substitute temporary tokens back to capture group back references
replace="${replace//__REFERENCE_1__/\\1}"
replace="${replace//__REFERENCE_2__/\\2}"
replace="${replace//__REFERENCE_3__/\\3}"
# -----------------------
# Perform the replacement
# -----------------------
# -r extended regex
# Matching line should be simply dropped:
if [[ "$replace" == DROP* ]]; then
lines=${replace/DROP+/}
lines=$((lines)) # cast to integer
echo "$files" | while IFS= read -r file; do
sed -r -i "/$search/,+${lines}d" -- "$file"
done
else
echo "$files" | while IFS= read -r file; do
sed -r -i "s/$search/$replace/g" -- "$file"
done
fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment