Заменить строку в файле частями этой строки

Заменить строку в файле частями этой строки

Я получил список установленных программ на моем компьютере с Ubuntu с помощьюapt list --installed

Вот фрагмент списка

wdiff/xenial,now 1.2.2-1build1 amd64 [installed,automatic]
wget/xenial-updates,xenial-security,now 1.17.1-1ubuntu1.5 amd64 [installed]
whiptail/xenial,now 0.52.18-1ubuntu2 amd64 [installed]
xauth/xenial,now 1:1.0.9-1ubuntu2 amd64 [installed]
xdg-user-dirs/xenial-updates,now 0.15-2ubuntu6.16.04.1 amd64 [installed]
xfsprogs/xenial-updates,now 4.3.0+nmu1ubuntu1.1 amd64 [installed]
xkb-data/xenial,now 2.16-1ubuntu1 all [installed]

Мне нужно название программы и версия. Например:
wdiff/xenial,now 1.2.2-1build1 amd64 [installed,automatic] становится
wdiff 1.2.2-1build1

Я придумал эту команду, которая работает.

apt list --installed  | sed -r 's@/@ @g' | awk '{print $1 "\t" $3}'  | sort -u

Я хотел бы узнать, как использовать только sed для создания нового файла с частями строки входного файла.

Это регулярное выражение: ^([^\/]+)\/[^\s]+\s([^\s]+)

  • Захват от начала строки до первого /
  • Игнорировать до первого пробела
  • Захват после первого пробела до второго пробела

И я должен иметь возможность использовать обратные ссылки sed на группы захвата и создавать новый вывод.

apt list --installed | sed -r 's/^([^\/]+)\/[^\s]+\s([^\s]+)/\1 \2/'

Однако, похоже, результат не соответствует моим ожиданиям.

wdiff   [installed,automatic]
wget/xenial-updates,xenial-security,now 1.17.1-1ubuntu1.5 amd64 [installed]
whiptail    [installed]
xauth   [installed]
xdg-user-dirs/xenial-updates,now 0.15-2ubuntu6.16.04.1 amd64 [installed]
xfsprogs/xenial-updates,now 4.3.0+nmu1ubuntu1.1 amd64 [installed]
xkb-data    [installed]

Что не так?

решение1

Что не так? Вы захватили не ту группу и не сбросили до конца входной строки после последнего совпадения, которое вы хотели сохранить, а только до следующего непробельного символа

sed -r 's/^([^\/]+)\/[^\s]+\s([^\s]+)/\1    \2/'

([^/]+)   #capture everything up to /, OK
/         #discard the /. OK
[^\s]     #discard the next non white-space group, this is the bit you actually want
\s        #discard the whitespace
([^\s]+)  #capture the next non-whitespace group
#leave anything after the last non-whitespace found

Вы, вероятно, сделали это из-за плохой читаемости со всеми этими экранами. Если вы это почистите, это поможет вам отладить

sed -E 's|([^/]*)[^ ]* +([^ ]*).*|\1 \2|' infile | column -t

([^/]*)    #capture up to the /
[^ ]* +    #discard until the space and any spaces
([^ ])     #capture the next character group until a space
.*         #discard to the end of the string

Если вы не указали глобальное соответствие ( s///g), то якорь вам не нужен ^.

Используйте |в качестве разделителя, чтобы избежать ненужных экранированных символов в совпадающей строке.

Выполняет column -tлучшую работу по выравниванию, чем несколько пробелов

решение2

Попробуйте следующее (неоптимизированное) регулярное выражение:

$ sed 's/\(^.*\)\(\/[^ ]* \)\([^ ]* \)\([^ ]* \)\([^ ]*\)/\1 \3/' infile
wdiff 1.2.2-1build1 
wget 1.17.1-1ubuntu1.5 
whiptail 0.52.18-1ubuntu2 
xauth 1:1.0.9-1ubuntu2 
xdg-user-dirs 0.15-2ubuntu6.16.04.1 
xfsprogs 4.3.0+nmu1ubuntu1.1 
xkb-data 2.16-1ubuntu1 

Связанный контент