UPDATE: loevborg's python script is certainly the simplest and best solution (there's no doubt about that) and I'm very happy with it, but I'd like to point out that the bash script I presented (at the end of the question) is nowhere near as complicated as it looks.. I trimmed out all the debugging dross which I used to test it.. and here it is again without the overburden (for anyone visiting this page).. It's basically a sed
one-liner, with pre and post hex-conversions :
F=("$haystack" "$needle" "$replacement")
for f in "${F[@]}" ; do cat "$f" | hexdump -v -e '1/1 "%02x"' > "$f.hex" ; done
sed -i "s/$(cat "${F[1])}.hex")/$(cat "${F[2])}.hex")/p" "${F[0])}.hex"
cat "${F[0])}.hex" | xxd -r -p > "${F[0])}"
# delete the temp *.hex files.
Just to throw my hat into the ring, I've come up with a 'sed' solution which won't run into any problems with special regex characters, because it uses not even one! .. instead it works on Hexdumped versions of the files...
I think it is too "top heavy", but it works, and is apparently not restricted by any size limitations.. GNU sed has an unlimited pattern buffer size, and that is where the Hexdumped block of search-lines ends up.. So it's okay in that respect...
I am still looking for a diff
solution, because it will be more flexible regarding white-space (and I would expect; faster)... but until then.. It's the famous Mr Sed. :)
This script is fully running as is, and is reasonably commented...
It looks bigger that it is; I has only 7 lines of essential code.
For a semi-realistic test, it downloads the book "Alice Through the Looking Glass" from Project Gutenberg (363.1 KB) ... and replaces the original Jabberwocky poem with a line-reversed version of itself.. (Interestingly, it's not much different reading it backwards :)
PS. I just realized that a weakness in this method is if your original uses \r\n (0xODOA) as it's newline, and your "text to match" is saved with \n (0x0A).. then this matching process is dead in the water... ('diff' doesn't have such a issues) ...
# In a text file, replace one block of lines with another block
#
# Keeping with the 'Jabberwocky' theme,
# and using 'sed' with 'hexdump', so
# there is no possible *special* char clash.
#
# The current setup will replace only the first instance.
# Using sed's 'g' command, it cah change all instances.
#
lookinglass="$HOME/Through the Looking-Glass by Lewis Carroll"
jabberwocky="$lookinglass (jabberwocky)"
ykcowrebbaj="$lookinglass (ykcowrebbaj)"
##### This section if FOR TEST PREPARATION ONLY
fromURL="http://www.gutenberg.org/ebooks/12.txt.utf8"
wget $fromURL -O "$lookinglass"
if (($?==0))
then echo "Download OK"
else exit 1
fi
# Make a backup of the original (while testing)
cp "$lookinglass" "$lookinglass(fromURL)"
#
# Extact the poem and write it to a file. (It runs from line 322-359)
sed -n 322,359p "$lookinglass" > "$jabberwocky"
cat "$jabberwocky"; read -p "This is the original.. (press Enter to continue)"
#
# Make a file containing a replacement block of lines
tac "$jabberwocky" > "$ykcowrebbaj"
cat "$ykcowrebbaj"; read -p "This is the REPLACEMENT.. (press Enter to continue)"
##### End TEST PREPARATION
# The main process
#
# Make 'hexdump' versions of the 3 files... source, expected, replacement
cat "$lookinglass" | hexdump -v -e '1/1 "%02x"' > "$lookinglass.xdig"
cat "$jabberwocky" | hexdump -v -e '1/1 "%02x"' > "$jabberwocky.xdig"
cat "$ykcowrebbaj" | hexdump -v -e '1/1 "%02x"' > "$ykcowrebbaj.xdig"
# Now use 'sed' in a safe (no special chrs) way.
# Note, all files are now each, a single line ('\n' is now '0A')
sed -i "s/$(cat "$jabberwocky.xdig")/$(cat "$ykcowrebbaj.xdig")/p" "$lookinglass.xdig"
##### This section if FOR CHECKING THE RESULTS ONLY
# Check result 1
read -p "About to test for the presence of 'jabberwocky.xdig' within itself (Enter) "
sed -n "/$(cat "$jabberwocky.xdig")/p" "$jabberwocky.xdig"
echo -e "\n\nA dump above this line, means: 'jabberwocky' is as expected\n"
# Check result 2
read -p "About to test for the presence of 'ykcowrebbaj.xdig' within itself (Enter) "
sed -n "/$(cat "$ykcowrebbaj.xdig")/p" "$ykcowrebbaj.xdig"
echo -e "\n\nA dump above this line, means: 'ykcowrebbaj' is as expected\n"
# Check result 3
read -p "About to test for the presence of 'lookinglass.xdig' within itself (Enter) "
sed -n "/$(cat "$ykcowrebbaj.xdig")/p" "$lookinglass.xdig"
echo -e "\n\nA dump above this line, means: 'lookinglass' is as expected\n"
# Check result 4
read -p "About to test for the presence of 'lookinglass.xdig' within itself (Enter) "
sed -n "/$(cat "$jabberwocky.xdig")/p" "$lookinglass.xdig"
echo -e "\n\nNo dump above this line means: 'lookinglass' is as expected\n"
##### End of CHECKING THE RESULTS
# Now convert the hexdump to binary, and overwrite the original
cat "$lookinglass.xdig" | xxd -r -p > "$lookinglass"
# Echo the "modified" poem to the screen
sed -n 322,359p "$lookinglass"
echo -e "\n\nYou are now looking at the REPLACEMENT text (dumped directly from the source 'book'"