sed :извлечь текст из шаблона, который встречается произвольное количество раз в строке

Редактировать/etc/pulse/default.pa

комментарий после:

#load-module module-switch-on-port-available
#load-module module-suspend-on-idle

и un -комментируют последние две строки:

set-default-sink output
set-default-source input

Теперь ваши разъемы Jack будут активны после загрузки.

1
21.05.2020, 22:45
8 ответов

На данный момент то, что я мог бы (надеюсь, )намного лучше, чем повторный вызов sed, заключалось в "цепочке" замен с заполнителями, которые, надеюсь, не появятся в файлах.

cat dborefs.txt | sed -E "
 s/\[dbo\]\.\[([^]]+)\]/_-\1-_/g;
 s/(^|-_)([^_]+|_[^-])*(\$|_-)/ /g;
 s/(^ +| +\$)//g"

Другими словами:

  • сначала я получаю все [dbo].[<extract>]и заменяю на _-<extract>-_;
  • затем заменить любой текст перед первым _-, между -_и _-и после последнего -_одним пробелом;
  • , а затем очистить символы пробела в начале и в конце каждой строки.

Это дает желаемый результат, и я могу объединить все это в массив, а затем отфильтровать уникальные записи с помощью sort. Но я все еще думаю, что должен быть лучший способ без цепочек sedкоманд.

0
18.03.2021, 23:33

Чтобы получить новую строку -список размеченных строк с разделителями:

$ grep -o '\[dbo\]\.\[[^]]*\]' file | cut -d. -f 2 | tr -d '[]'
something
something_else
something
something
something
something
anything
elsewhere
otherthing
ultra
references
pattern

Первый grepсоздает только строки с [dbo].[word]. cutдает нам бит [word], а trудаляет из него [и ].

Чтобы сгруппировать размеченные строки по строке, в которой они встречаются:

$ sed -e 's/\][^.[]*\[/] [/g' -e 's/^[^[]*//' -e 's/[^]]*$//' -e 's/\[dbo\]\.\[\([^]]*\)\]/\1/g' file
something something_else
something
something something
something anything elsewhere
otherthing
ultra references pattern

Здесь используются четыре замены:

  1. Удалите все между ]и [, что не является точкой или [(, замените пробелом; это пробелы в конечном выводе ).
  2. Удалить все до первого [.
  3. Удалить все после последнего ].
  4. Извлеките размеченные слова из того, что осталось.
1
18.03.2021, 23:33

Использование gnu sed в расширенном режиме регулярных выражений (для некоторой экономии экранирования с помощью обратной косой черты):

sed -re '
  /\n/q;G
  :a;s/\[dbo]\.\[([^]]+)](.*\n\1(\n|$))/\2/;ta
  :b;s/\[dbo]\.\[([^]]+)](.*)/\2\n\1/;tb
  s/^[^\n]*\n//;h
  $\!d;g;D
' dborefs.txt


awk -F'[][]' '
NF>2{
  for (i=1; i<=NF-2; i++)
    if ( $(i) $(i+1) == "dbo." )
      a[$(i+2)]
 }
 END { for (i in a) print i } 
' dborefs.txt

Выход;

something
something_else
anything
elsewhere
otherthing
ultra
references
pattern

perl -lne '
  $h{$1}++ while /\[dbo]\.\[([^]]+)]/g;
  }{print for keys %h;
' dborefs.txt
0
18.03.2021, 23:33

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

sed -Ee '
  /\n/{P;D;}
  s/\[dbo]\.\[([^]]+)]/\n\1\n/;D
' dborefs.txt | awk '!a[$0]++'
0
18.03.2021, 23:33

Еще один интересный пример с рекурсией. Однако это не однострочная команда sed...

$ sed -e ':loop;
          s/[^|\[]*\[dbo\]\.\[\([a-z_]*\)\][^[]*/\1|/;
          t loop;
          s/|$//;
          s/|/ /g' testfile
something something_else  
something  
something something  
something anything elsewhere  
otherthing  
ultra references pattern
  • s/... :заменить начало строки до [dbo].[myname] на myname|
  • цикл t :итерация, если была сделана замена
  • s/|... :избавиться от |, заменить пробелом или концом строки
0
18.03.2021, 23:33

Вы были на правильном пути, используя свой\[dbo\]\.\[[^]]+\]

  • добавление скобки захвата:\[dbo\]\.\[([^]]+)\]

  • добавление начального захвата [^[]*==>[^[]*\[dbo\]\.\[([^]]+)\]

  • окружающих его в группе замещения s/.../\1]/g

  • Удаление последней ]и последующие:s/\][^]]*$//

  • и преобразование всех оставшихся ]в пробелы:s/\]/ /g

Доставят тебя туда:

sed -Ee 's/[^[]*\[dbo\]\.\[([^]]+)\]/\1]/g' \
     -e 's/\][^]]*$//' \
     -e 's/\]/ /g' file

даст:

something something_else
something
something something
something anything elsewhere
otherthing
ultra references pattern
0
18.03.2021, 23:33

Мне не совсем понятно, каков был ваш ожидаемый результат. Иногда вы говорите о фильтрации дубликатов, иногда по одному на строку.

Это решение без цепочки, все sed использует наиболее безопасный заполнитель, а не-_

sed -Ee '
  s/\[dbo]\.\[([^]]+)]/\n\1\n\n/g
  s/(^|\n\n)[^\n]*//g
  y/\n/ /
' file
0
18.03.2021, 23:33

Вы можете сделать это проще в Perl, используя хэш (ассоциативный массив )для однозначного соответствия совпадений:

$ perl -nE 'while ($_ =~ /\[dbo\]\.\[(.*?)\]/g) {$h{$1}++} }{ for $k (keys %h) {say $k}' dborefs.txt 
otherthing
anything
elsewhere
something
pattern
something_else
ultra
references

Аналогичный подход возможен в GNU Awk путем многократного применения функции match:

$ gawk '{
    while (match($0,/\[dbo\]\.\[([^]]+)\]/,a)) {h[a[1]]++; $0 = substr($0,RSTART+RLENGTH)}
  } 
  END{
    for (k in h) print k
  }' dborefs.txt 
references
elsewhere
something
something_else
pattern
otherthing
anything
ultra

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

while (match($0,/\[dbo\]\.\[([^]]+)\]/)) {h[substr($0,RSTART+7,RLENGTH-8)]++; $0 = substr($0,RSTART+RLENGTH)}
0
18.03.2021, 23:33

Теги

Похожие вопросы