Замена пути из DOS в UNIX внутри файла
Вопрос
У меня есть файл, который содержит такого рода пути:
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