string_replacer

Repeatedly replace text in a file without disturbing the rest of the file.

Use

$ string_replacer PATH STRING [REPLACEMENT_ID] [AFTER_LINE]

For example:

$ echo "hello" > test.txt
$ cat test.txt 
hello
$ string_replacer test.txt "Don't forget to say \"hello world\"" "Just a reminder"
$ cat test.txt
hello

# START StringReplacer Just a reminder -- DO NOT MODIFY
Don't forget to say "hello world"
# END StringReplacer Just a reminder -- DO NOT MODIFY

Now I swap it out by using the same REPLACEMENT_ID

$ string_replacer test.txt "YOU ARE STILL FORGETTING to say \"hello world\"" "Just a reminder"
$ cat test.txt
hello

# START StringReplacer Just a reminder -- DO NOT MODIFY
YOU ARE STILL FORGETTING to say "hello world"
# END StringReplacer Just a reminder -- DO NOT MODIFY

And finally, to demonstrate that REPLACEMENT_ID is case-sensitive…

$ string_replacer test.txt "Nevermind" "Just a Reminder"
$ cat test.txt
hello

# START StringReplacer Just a reminder -- DO NOT MODIFY
YOU ARE STILL FORGETTING to say "hello world"
# END StringReplacer Just a reminder -- DO NOT MODIFY

# START StringReplacer Just a Reminder -- DO NOT MODIFY
Nevermind
# END StringReplacer Just a Reminder -- DO NOT MODIFY

If you don’t specify REPLACEMENT_ID, it will default to “1.”

Real-world usage

brighterplanet.com uses it to unmask the memcached 1.4.4 package on engineyard.com AppCloud (i.e. Amazon EC2) instances.

We have this in our before_restart.rb hook:

###############################################################
# make sure we have string_replacer installed at the system level
###############################################################
sudo 'gem install string_replacer --no-rdoc --no-ri'

###############################################################
# install memcached 1.4.4, which is not available by default
###############################################################
memcached_server_version = '1.4.4'
unless `/usr/bin/memcached -h`.include?(memcached_server_version)
  sudo "/usr/bin/string_replacer /etc/portage/package.keywords/local \"=net-misc/memcached-#{memcached_server_version}\" \"make sure memcached #{memcached_server_version} is available\""
  sudo "emerge net-misc/memcached"
end
sudo "cp #{release_path}/deploy/memcached/memcached.#{node[:environment][:name]} /etc/conf.d/memcached"

Before:

$ cat /etc/portage/package.keywords/local
=dev-lang/ruby-1.8.7_p174

After:

$ cat /etc/portage/package.keywords/local
=dev-lang/ruby-1.8.7_p174

# START StringReplacer make sure memcached 1.4.4 is available -- DO NOT MODIFY
=net-misc/memcached-1.4.4
# END StringReplacer make sure memcached 1.4.4 is available -- DO NOT MODIFY

Obvious flaws

  • assumes whitespace is ignored

  • assumes # means comment

  • no idea how it would work on big files

  • there is probably a unix program that has done this since the 1970s

Copyright © 2010 Seamus Abshere. See LICENSE for details.