sed, чтобы заменить только соответствующую часть в строке поиска - PullRequest
6 голосов
/ 26 ноября 2011

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

Lorem ipsum dolem file1.jar.

  • file1.jar (MD5: 12345678901234567890123456789012)
  • file2.jar (MD5: 09876543210987654321098765432109)
  • file3.jar (MD5: 24681357902468135790246813579024)

и я хотел бы заменить первый MD5. Эта команда sed выполняет работу:

sed "s/file1.*MD5\:\(.*\)/file1.jar \(MD5\: `md5 file1.jar | awk '{print $4}'`\)/"

Есть ли способ сказать sed о замене только соответствующей группы, оставляя остальную часть строки в покое? Например:

sed "s/file1.*MD5\:\(.*\)/`md5 file1.jar | awk '{print $4}'`/"

Ответы [ 2 ]

6 голосов
/ 26 ноября 2011

Вы можете использовать поиск, чтобы указать строку для сопоставления, а затем использовать более простое регулярное выражение в замене:

sed "/file1\.jar (MD5: [0-9A-Fa-f]*)/s/(MD5: [^)]*)/(MD5: $(md5 file1.jar | awk '{print $4}'))/"

, которое использует нотацию $(...) для запуска команды.Хитрый бит в этом находится в конце, где появляется последовательность ))/".Первая закрывающая скобка - это конец обозначения $(...);второй символ в тексте замены.

Первое регулярное выражение /file1\.jar (MD5: [0-9A-Fa-f]*)/ довольно точно указывает строку, которую нужно сопоставить.Затем, зная, что это правильная строка, шаблон в замене может быть проще: поисковая часть /(MD5: [^)]*)/ ищет только данные MD5 в скобках, будучи уверенными в том, что, хотя многие другие строки содержат тот же шаблон, подстановка будетприменяется только к одной желаемой строке.

Я мог бы склоняться к использованию:

md5=$(md5 file1.jar | awk '{print $4}')
sed "/file1\.jar (MD5: [0-9A-Fa-f]*)/  s/(MD5: [^)]*)/(MD5: $md5)/"

, которая проясняет, что к чему, значительно (и не включает в себя горизонтальную полосу прокрутки на SO).Вы можете быть еще более точным в шаблоне сопоставления строк:

md5=$(md5 file1.jar | awk '{print $4}')
sed "/^file1\.jar (MD5: [0-9A-Fa-f]\{32\})\$/  s/(MD5: [^)]*)/(MD5: $md5)/"

Это требует ровно 32 шестнадцатеричных цифр и закрывающих скобок в конце строки.


Один изв комментариях спрашивается:

Может ли sed работать таким образом, чтобы замещающая строка заменяла только совпадающие группы в шаблоне поиска?Например, учитывая 's/A B \(D\)/C/', он выводит A B C.

Если я понимаю (разъяснение) вопроса, то вы можете делать то, что хотите, с соответствующим захватом - но запасная часть будетнеобходимо указать именно то, что вы хотите в качестве вывода (никаких ярлыков, как вы, кажется, после).Так, например, вы могли бы написать что-то вроде:

s/\(A B \)\(D\)/\1C/

(где для захвата \(D\) не требуется захватывать скобки, так как захваченный материал не используется при замене, и вы можете написать либоиз:

s/\(A B \)D/\1C/
s/\(A B\) D/\1 C/

Вы также можете сделать:

/A B / s/D/C/

. Здесь есть поиск (для последовательности A B), а затем заменитель ищет D и заменяет его наC. Это в основном то, что предлагает основной ответ. Возможно, вы также можете сделать:

/\(A B\) D/ s//\1 C/

«Пустой поиск» должен повторить совпадение, но замена должна быть записана полностью,и это фактически то же самое, что и одна из предыдущих команд:

s/\(A B\) D/\1 C/
0 голосов
/ 26 ноября 2011

Это должно сделать это (не проверено):

sed "s/(file1.jar \(MD5: )(..............................)/\1`md5 file1.jar | awk '{print $1}'`/"

Это 32 точки, заметьте.

...