печать нескольких совпадений в 1 строке с помощью sed - PullRequest
2 голосов
/ 26 декабря 2011

У меня есть Makefile, в котором есть переменные version и build (это не единственные переменные, и они могут быть определены в другом порядке).Используя только sed, я хотел бы объединить значения в одну строку версии.

Пока что у меня есть:

sed -n -e '/=/{s/version.*=\(.*\)/\1\./p;s/build.*=\(\d*\)*/\1/p}' Makefile

, но оба значения разделены новой строкой.Выше приведено следующее:

0.8.2.
1

Я бы хотел:

0.8.2.1

Я пытался N, но не могу понять, как использовать его в этой ситуации.

Почему ограничение «только для седа»?Я хотел бы изучить это, и это лучший способ для меня.

Автономный образец:

sed -n -e '/=/ {s/version.*=\(.*\)/\1\./p;s/build.*=\(\d*\)*/\1/p}' <<EOF
foo=1
version=0.8.2
bar=2
build=1
bam=bug-AWWK
EOF

Ответы [ 4 ]

4 голосов
/ 26 декабря 2011

Следующие принципы основаны на одной и той же идее: сохраните номера версий и сборок, затем напечатайте их в конце ввода.

Когда дело доходит до хранилища, у sed есть пространство шаблонов, которое начинается сзначение текущей строки и пробел, который можно использовать для сохранения значений в течение всего процесса.Версия должна быть предварительно добавлена ​​к значению в области удержания, что может быть достигнуто путем добавления пространства удержания к пространству образца с помощью G.Сборка должна быть добавлена ​​к пространству удержания, что можно сделать с помощью H.Чтобы удалить новую строку, которую создает H, пространство удержания перемещается обратно в пространство образца.В обоих случаях новая строка, созданная G и H, удаляется с помощью s///, затем возвращается в область удержания с помощью h.Конец ввода обозначается адресом $, по которому пространство удержания перемещается обратно в пространство шаблона и печатается.Короче, чтобы увидеть:

sed -n -e '/^version.*=/ {s/[^=]*=//; G; s/\n//; h; } ' \
       -e '/^build.*=/ { s/[^=]*=//; H; g; s/\n/./; h; } ' \
       -e '$ { g; P; }'

Это создает новую строку в конце строки, но, надеюсь, это не будет проблемой.

Утилита семейства awk поддерживает переменные, делаязадача более простая.У них есть специальные переменные OFS, разделитель выходного поля и ORS, разделитель выходной записи.print в awk выводит OFS между каждым аргументом и ORS в конце.Специальный шаблон END совпадает после окончания ввода.

awk -v OFS=. -v ORS='' \
    '/^version.*=/ {sub(/^[^=]*=/, "");  version=$0;} \
     /^build.*=/ {sub(/^[^=]*=/, ""); build=$0;} \
     END {print version, build;}'

Если вас не волнует конечная точка, и вы можете быть уверены в порядке версии и строк сборки в make-файле:

awk -v ORS=. '/(version|build).*=/ { sub(/^[^=]*=/, ""); print; } '

Продолжение вверх по выразительности языка - perl.* Perl END имеет функцию, аналогичную awk, отмечая блок для запуска в конце процесса.Хеш может использоваться для хранения частей полного номера версии, позволяя линиям совпадать и хранить версию и сборку в одну строку.

perl -n -e '$ver{$1} = $2 if /^(version|build)[^=]*=(.*)/; \
            END {$,="."; print @ver{"version","build"}};'

При использовании sed делает интереснымВ упражнениях ценность упражнений состоит в том, чтобы укреплять себя, выполняя их.Если вам нужно обратиться к другим, лучше не сосредотачиваться на том, как вы пытаетесь решить проблему , а вместо этого искать рекомендуемые подходы.Вы узнаете больше.

1 голос
/ 26 декабря 2011

попробуйте это с вашим make-файлом:

 sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' makefile

тест с вашим примером текста:

kent$  sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' <<<"foo=1
dquote> version=0.8.2
dquote> bar=2
dquote> build=1
dquote> bam=bug-AWWK
dquote> EOF"
0.8.2.1

в случае, если сборка отображается до версии:

kent$  sed -rn -e '/^(version|build)/{s#^.*=##;H;}' -e'${x;s#\n##;s#\n#\.#;p}' <<<"foo=1
bar=2
build=1
bam=bug-AWWK
version=100.8.2"
1.100.8.2
0 голосов
/ 26 декабря 2011

Если вы открыты для awk, то вот другое решение. Предотвращает судороги пальцев, вызванные вводом кода sed. No offence to the brilliant solutions offered by potong and kent;)

awk -F"=" '
BEGIN{i=1}
(/version|build/){a[i]=$NF;i++}
END{for(i=1;i<=2;i++) if(i==1) {printf a[i]"."} else printf a[i]}' Makefile
0 голосов
/ 26 декабря 2011

Это может работать для вас:

cat makefile | 
sed '/^\(version\|build\)/H;${x;s/^\(\nbuild.*\)\(\n.*\)/\2\1/;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1
tac makefile | 
sed '/^\(version\|build\)/H;${x;s/^\(\nbuild.*\)\(\n.*\)/\2\1/;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1

Если вы не беспокоились, если версия до или после сборки, то:

sed '/^\(version\|build\)/H;${x;s/^.*=\(.*\)\n.*=\(.*\)/\1.\2/p};d'
0.8.2.1

Прочитав @outis решение, вот улучшенная версия его решения для более простого просмотра:

 sed '/^version=/{s///;G;h};/^build=/{s//./;H};${g;s/\n//gp};d' makefile
...