Search and replace with sed

Go To StackoverFlow.com

0

Last week I accidently externalized all my strings of my eclipse project. I need to revert this and my only hope is sed. I tried to create scripts but failed pathetically because I'm new with sed and this would be a very complicated operation. What I need to do is this:

Strings in class.java file is currently in the following format(method) Messages.getString(<key>). Example :

    if (new File(DataSource.DEFAULT_VS_PATH).exists()) {
        for (int i = 1; i <= c; i++) {
            if (!new File(DataSource.DEFAULT_VS_PATH
                    + Messages.getString("VSDataSource.89") + i).exists()) { //$NON-NLS-1$
                getnewvfspath = DataSource.DEFAULT_VS_PATH
                        + Messages.getString("VSDataSource.90") + i; //$NON-NLS-1$
                break;
            }
        }
    }

The key and matching Strings are in messages.properties file in the following format.

VSDataSource.92=No of rows in db = 
VSDataSource.93=Verifying db entry : 
VSDataSource.94=DB is open
VSDataSource.95=DB is closed
VSDataSource.96=Invalid db entry for 
VSDataSource.97=\ removed.
key=string

So I need the java file back in this format:

    if (new File(DataSource.DEFAULT_VS_PATH).exists()) {
        for (int i = 1; i <= c; i++) {
            if (!new File(DataSource.DEFAULT_VS_PATH
                    + "String 2" + i).exists()) { //$NON-NLS-1$
                getnewvfspath = DataSource.DEFAULT_VS_PATH
                        + "String 1" + i; //$NON-NLS-1$
                break;
            }
        }
    }

How can I accomplish this with sed? Or is there an easier way?

2012-04-03 23:25
by Binoy Babu
So I'm guessing VSDataSource.89 is String 2 in your messages.properties? Are you wanting to replace Messages.getString('VSDataSource.xxx') with the yyy from VSDataSource.xxx=yyy in messages.properties - mathematical.coffee 2012-04-03 23:29
@mathematical.coffee yes. The key needn't start with VSDataSource, but it is unique for each string - Binoy Babu 2012-04-03 23:31
Use Java? Here's a similar thing: http://stackoverflow.com/questions/4766602/un-externalize-strings-from-eclipse-or-intellij. Instead of making the strings in the Java file, you can go through all the files and do a regex search and replace - icyrock.com 2012-04-03 23:35
@icyrock.com I'm aware of that question, but my question is a bit different. Also note that the op was not that satisfied with that answer. I did a regex search but still i have to manually type in more than 200 strings top the replace box - Binoy Babu 2012-04-03 23:39
Make a Java program in which you can: 1) read the properties, 2) traverse all your project .java files, 4) read each file line by line, replace all the strings by using regexps, keying from the loaded properties, save when done reading all lines. Not a 2-minute job, but easy enough - icyrock.com 2012-04-03 23:44
@icyrock.com good idea, i'll try that. - Binoy Babu 2012-04-03 23:47


3

This might work for you (GNU sed?):

sed 's|^\([^=]*\)=\(.*\)|s@Messages.getString("\1")@"\2"@g|;s/\\/\\\\/g' messages.properties |
sed -i -f - *.java
2012-04-04 00:31
by potong
Nice. I would suggest -i.bak or something, just for double-checking later - Miserable Variable 2012-04-04 00:40
OSListActivity.100=/system/bootmenu/recovery/sbin/tune2fs -j There are many entries like this in messages.properties. So sed: file - line 52: unknown option to `s - Binoy Babu 2012-04-04 00:45
Just change the s/../../g to some s@..@..@g see solution: You can also run the first part and check the sed generated script by hand, when happy save it as temp.sed and run sed -f temp.sed *.javapotong 2012-04-04 00:49
It worked, other answers are great too, but this one's special because it's a oneliner. I love stackoverfow - Binoy Babu 2012-04-04 01:14
+1 Agree, nice one potong - icyrock.com 2012-04-04 01:15
@potong It don't replace some entries.. - Binoy Babu 2012-04-05 01:09
Without seeing the data I can't tell you why or how to amend the solution. However, since this is a one-off you might just have to dive into an editor and fix up those exceptions by hand, Good luck - potong 2012-04-05 05:26


2

To repeat my comment on the question - I think that Java problems are best solved in Java :) Though this arguably is an Eclipse-helped problem caused by you :)

Make a Java program in which you can:

  • Read the properties,
  • Traverse all your project .java files,
  • For each file:
    • Read each file line by line,
    • Replace all the strings by using regexps, keying from the loaded properties,
    • Save when done reading all lines.

Not a 2-minute job, but easy enough.

But if you really want to use sed ;)

mkt.sh

$ cat mkt.sh
# Test structure
rm -rf a b
mkdir a
mkdir b
cat > a/A.java <<EOF
my plans for replace
this will be left alone 
EOF
cat > b/B.java <<EOF
propery ginger
broccoli tomato potato
EOF

display() {
  for i in a/A.java b/B.java; do
    echo --- $i
    cat $i
  done
}

display

# Prop change
echo 'echo --- Replacing in: $1' > replace.sh
sed -r 's/([^=]+)=(.+)/sed -i '\''s#\1#\2#'\'' $1/' sample.properties >> replace.sh
chmod u+x replace.sh

# Replace
find -type f -name "*.java"|xargs -n1 ./replace.sh

# Test
display

Run:

$ ./mkt.sh 
--- a/A.java
my plans for replace
this will be left alone 
--- b/B.java
propery ginger
broccoli tomato potato
--- Replacing in: ./a/A.java
--- Replacing in: ./b/B.java
--- a/A.java
my plans for world domination
this will be left alone 
--- b/B.java
propery ginger
steak tomato potato

This should work properly on your .java files, but do make a copy before ;) You will have some issues if # is in the strings, but you can solve this by removing these from properties file, doing a replace, bringing them back and changing this line:

sed -r 's/([^=]+)=(.+)/sed -i '\''s#\1#\2#'\'' $1/' sample.properties >> replace.sh

to e.g.:

sed -r 's/([^=]+)=(.+)/sed -i '\''s+\1+\2+'\'' $1/' sample.properties >> replace.sh

where + is not a remaining character. A bit of a hassle, but...

Hope this helps.

2012-04-03 23:59
by icyrock.com
I have trouble getting this to work. http://pastebin.com/nWMCHEF - Binoy Babu 2012-04-04 00:20
Can you give me a few (random lines of the ones that had error) from the generated replace.sh (and / or your properties file if possible) - icyrock.com 2012-04-04 00:38
Besides - which OS, bash version, sed version? That can be very important, as some of them don't support options (such as -r given to sed or things like that - icyrock.com 2012-04-04 00:45
sure http://pastebin.com/m0tfZyY - Binoy Babu 2012-04-04 00:48
ubuntu 12.04, GNU bash, version 4.2.20(1)-release (i686-pc-linux-gnu), GNU sed version 4.2. - Binoy Babu 2012-04-04 00:50
Ubuntu, nice :) OK, this is good - I have Ubuntu 11.10, so should be good. Can you give me some of the rows that failed? Like this one: ./replace.sh: 350: ./replace.sh: VSDataSource.40=: not found and around (seems these in VSDataSource fail often) - icyrock.com 2012-04-04 00:54
http://pastebin.com/yYBmTAH - Binoy Babu 2012-04-04 01:01
let us continue this discussion in chaticyrock.com 2012-04-04 01:01


2

makesed.awk:

BEGIN {
    FS="=";
    print "for i in *.java"
    print "do"
    print "sed \\"
}

{
    msg = "Messages.getString(\"" $1 "\")";
    gsub("/","\\/",$2);
    print "-e 's/" msg "/\"" $2 "\"/g' \\"
}

END {
    print "$i > $$"
    print "mv $$ $i"
    print "done" 
}

Run:

awk -f makesed.awk yourpropertiesfile.dat > process.sh

This gives you a shell script:

for i in *.java
do
sed \
-e 's/Messages.getString("VSDataSource.92")/"No of rows in db "/g' \
-e 's/Messages.getString("VSDataSource.93")/"Verifying db entry : "/g' \
-e 's/Messages.getString("VSDataSource.94")/"DB is open"/g' \
-e 's/Messages.getString("VSDataSource.95")/"DB is closed"/g' \
-e 's/Messages.getString("VSDataSource.96")/"Invalid db entry for "/g' \
-e 's/Messages.getString("VSDataSource.97")/"\ removed."/g' \
$i > $$
mv $$ $i
done

Then go in to your respective Java directories and run:

sh process.sh

That will "fix" all of the java files in that directory.

If your properties file is long, you may very well run in to a command line limit with sed. Simply split the file up in to chunks until the script is happy.

Obviously this doesn't work with any escape character, if you have "=" in your messages you'll suffer some pain as well. If you're fool enough to run this on code that isn't backed up, then you certainly deserve whatever happens to you.

But it should be a good first start.

2012-04-04 00:10
by Will Hartung
"sed: -e expression #52, char 46: unknown option to `s'" http://pastebin.com/bCVrL2V - Binoy Babu 2012-04-04 00:41
I added the gsub to escape any / in the replacement text. Those are causing problems. Try that to see if it works - Will Hartung 2012-04-04 03:43
Some entries are not getting replaced, otherwise you script works fine. : - Binoy Babu 2012-04-05 01:23


-1

You don't need to program anything. Right-click on one of your modified files and select "Replace With >", "Previous from Local History". Repeat as necessary.

2012-04-03 23:36
by phatfingers
Please read the first line of the question. I have modified the code many times after externalization. It's almost impossible to replace with history - Binoy Babu 2012-04-03 23:40
That would be the line that says last week you accidentally externalized your strings in your eclipse project? It's only Tuesday, you know.. - phatfingers 2012-04-03 23:45
:D thats funny, I did it last monday - Binoy Babu 2012-04-03 23:46
If you chose Replace With and Local History, it lists a set of dates for each change. Should be easy enough to find the date/time on Monday on which the change occurred, then revert each file based on that date. But of course we don't know if you've been heavily developing your code over the last week - phatfingers 2012-04-03 23:53
I've been heavily developing, as I said replacing with local history is not an option - Binoy Babu 2012-04-03 23:57