views:

1348

answers:

5

I have a file that contains this kind of paths:

C:\bad\foo.c
C:\good\foo.c
C:\good\bar\foo.c
C:\good\bar\[variable subdir count]\foo.c

And I would like to get the following file:

C:\bad\foo.c
C:/good/foo.c
C:/good/bar/foo.c
C:/good/bar/[variable subdir count]/foo.c

Note that the non matching path should not be modified.

I know how to do this with sed for a fixed number of subdir, but a variable number is giving me trouble. Actually, I would have to use many s/x/y/ expressions (as many as the max depth... not very elegant).

May be with awk, but this kind of magic is beyond my skills.

FYI, I need this trick to correct some gcov binary files on a cygwin platform.


Edit: There is a point I did not emphasised enough; I am dealing with binary files; therefore, I might have the following kind of data:

bindata\bindata%bindataC:\good\foo.c

which should be translated as:

bindata\bindata%bindataC:/good/foo.c

The first \ must not be translated, despites that it is on the same line.

However, I have just check my .gcno files while editing this text and it looks like all the paths are flanked with zeros, so most of the answers below should fit.

Thanks!

+1  A: 

You want to substitute '/' for all '\' but only on the lines that match the good directory path. Both sed and awk will let you do this by having a LHS (matching) expression that only picks the lines with the right path.

A trivial sed script to do this would look like:

/[Cc]:\\good/ s/\\/\//g

For a file:

c:\bad\foo
c:\bad\foo\bar
c:\good\foo
c:\good\foo\bar

You will get the output below:

c:\bad\foo
c:\bad\foo\bar
c:/good/foo
c:/good/foo/bar
ConcernedOfTunbridgeWells
+5  A: 
sed -e '/^C:\\good/ s/\\/\//g' input_file.txt
Sean Bright
+2  A: 

I would recommend you look into the cygpath utility, which converts path names from one format to another. For instance on my machine:

$ cygpath `pwd`
/home/jericson

$ cygpath -w `pwd`
D:\root\home\jericson

$ cygpath -m `pwd`
D:/root/home/jericson

Here's a Perl implementation of what you asked for:

$ echo 'C:\bad\foo.c
C:\good\foo.c
C:\good\bar\foo.c
C:\good\bar\[variable subdir count]\foo.c' | perl -pe 's|\\|/|g if /good/'
C:\bad\foo.c
C:/good/foo.c
C:/good/bar/foo.c
C:/good/bar/[variable subdir count]/foo.c

It works directly with the string, so it will work anywhere. You could combine it with cygpath, but it only works on machines that have that path:

perl -pe '$_ = `cygpath -m $_` if /good/'

(Since I don't have C:\good on my machine, I get output like C:goodfoo.c. If you use a real path on your machine, it ought to work correctly.)

Jon Ericson
A: 

Or with some help from good ol' Bash:

#!/bin/bash

cat file | while read LINE
do
        if <bad_condition>
        then
                echo "$LINE" >> newfile
        else
                echo "$LINE" | sed -e "s/\\/\//g" >> newfile
        fi
done
Eduard - Gabriel Munteanu
A: 

Here's how I would do it in awk:

# fixpaths.awk
/C:\\good/ {
   gsub(/\\/,"/",$1);
   print $1 >> outfile;
}

Then run it using the command:

awk -f fixpaths.awk paths.txt; mv outfile paths.txt
Scottie T