Вопрос

У меня есть файл, который содержит такого рода пути:

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

И я хотел бы получить следующий файл:

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

Обратите внимание, что несовпадающий путь не должен быть изменен.

Я знаю, как сделать это с помощью sed для фиксированного количества вложенных файлов, но переменное число вызывает у меня проблемы.На самом деле, мне пришлось бы использовать многие s/x/y/ выражения (столько, сколько максимальная глубина...не очень элегантно).

Может быть, с awk, но этот вид магии выходит за рамки моих навыков.

К вашему сведению, мне нужен этот трюк, чтобы исправить некоторые двоичные файлы gcov на платформе cygwin.


Я имею дело с двоичными файлами;следовательно, у меня могут быть данные следующего типа:

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

который должен быть переведен как:

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

Первый \ не должен быть переведен, несмотря на то, что он находится в той же строке.

Однако я только что проверил свой .gcno файлы при редактировании этого текста, и похоже, что все пути обрамлены нулями, поэтому большинство приведенных ниже ответов должны соответствовать.

Это было полезно?

Решение

sed -e '/^C:\\good/ s/\\/\//g' input_file.txt

Другие советы

Я бы порекомендовал вам заглянуть в cygpath утилита, которая преобразует имена путей из одного формата в другой.Например, на моей машине:

$ cygpath `pwd`
/home/jericson

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

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

Вот реализация на Perl того, о чем вы просили:

$ 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

Он работает непосредственно со строкой, поэтому будет работать где угодно.Вы могли бы совместить это с cygpath, но это работает только на машинах , у которых есть этот путь:

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

(Поскольку у меня нет C:\good на моей машине я получаю вывод, подобный C:goodfoo.c.Если вы используете реальный путь на своем компьютере, он должен работать правильно.)

Вы хотите заменить '/" для всех "\' но только в тех строках, которые соответствуют правильному пути к каталогу.И sed, и awk позволят вам сделать это, имея выражение LHS (matching), которое выбирает только строки с правильным путем.

Тривиальный sed-скрипт для этого выглядел бы следующим образом:

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

Для файла:

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

Вы получите результат, приведенный ниже:

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

Вот как я бы сделал это в awk:

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

Затем запустите его, используя команду:

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

Или с некоторой помощью старого доброго Баша:

#!/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

попробуй это

sed -re '/\\good\\/ s/\\/\//g' temp.txt

или это

awk -F"\\" '{if($2=="good"){OFS="\/"; $1=$1;} print $0}' temp.txt

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top