При переносе из другой команды ограничить пространство исходного шаблона совпавшей строкой

Есть несколько способов сделать это.

ИМХО, лучше всего использовать awk, что полезно при работе с полями.

Если вам нужно решение на основе grep, я бы сделал:

grep -w '^5'

-wуказывает grepна соответствие точному слову, поэтому это не будет соответствовать «52». «^» указывает grep искать 5 в начале строки, что не удастся, если есть, например. ведущие пробелы.

Решение awkбудет выглядеть так:

awk '$1 == 5'

Если вам нужно только имя пользователя, которое находится во втором столбце:

awk '$1 == 5 {print $2}'

Если вы ищете строку, а не числовое значение, заключите строку в двойные кавычки:

awk '$1 == "abc" {print $2}'
3
02.02.2021, 19:54
3 ответа

Я не думаю, что есть способ ограничить то, что передается оболочке с помощью модификатора e; однако вы можете сделать что-то вроде этого:

$ sed -E ':a;s@(.*\[\[)([^][]* [^][]*)(\]\].*)@printf "%s%s%s" "\1" "$(printf "\2" | sed "s/ /-/g")" "\3"@e;ta' test.txt
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

Обратите внимание, что обработка множественных замен выполняется с помощью цикла -, и из-за жадности совпадения замены выполняются в обратном порядке.

Также обратите внимание, что eиспользует /bin/sh, который, скорее всего, не будет поддерживать <<<перенаправление ввода (, следовательно, используется конвейерный эквивалентprintf "\2" | sed "s/ /-/g").


Если вы можете использовать perl, вы можете сделать что-то более близкое к вашему первоначальному замыслу, например.:

$ perl -pe 's/(?<=\[\[)(.*?)(?=\]\])/$1 =~ s: :-:rg/ge' test.txt
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

Так как perl предоставляет модификатор non -greedy ?, он может обрабатывать несколько замен в строке более традиционным способом, используя флаг gдля внешней замены.

7
18.03.2021, 22:32
cat - <<\! > file
Abc [[ \ ]] def and a cup of 
Ghi [[]] jkl 
Mno [[ ]] pqr 
abc [[" \' \\\"]] xyz
abc [[foo$$]] xyz [[a b c]] deal
abc [[foo bar]] xyz
abc [[foo bar baz]] xyz
abc [[foo $bar baz]] xyz [[FOO BAR VAZ]] $#
!
  1. GNU sedбез использования модификатора /e
sed -Ee '
  :loop
    s/([[]{2}[^][]*) ([^]]*]])/\1-\2/
  t loop
' file

Хотя это тривиально написать Posixly, но чтобы свести к минимуму обратную косую черту, которую мы используем с включенным расширенным режимом регулярных выражений, -E. Цикл постепенно преобразует символ пробела/итерацию между парой `[[...]] ``. Цикл останавливается, когда он не может найти такие пробелы ни в одной паре. Затем печатается пространство шаблона и считывается следующая строка в пространство шаблона... полоскание... повторение, пока мы не увидим eof.


  1. С помощью утилиты awkразбивая каждую строку на строки [[| ]]. Мы можем себе это позволить, потому что симметрия ([[n]] )идет парами и в таком порядке. Никаких болтающихся [[ или ]]. Тогда каждое четное поле будет внутри [[ n ]] и должно быть обработано.
awk -F '[[]{2}|]]' '
  {
    for (i=2; i<=NF; i+=2) {
      gsub(/ /, "-", $i)
      $i = "[[" $i "]]"
    }
  }1
' OFS= file

3. GNU sedс использованием модификатора /e.

sed -Ee "
  s/'/&\"&\"&/g;tloop
  :loop
    s|(.*[[]{2})([^][]* [^]]*)(]].*)|v='\2';v=\${v// /-};printf '%s' '\1' \"\$v\" '\3'|e
  t loop
" file

  1. Использование perl по той же схеме, что и awk выше.
perl -F'(\[\[|]])' -lane 'my $i;
  print map { ++$i%4 == 3 ? tr/ /-/r : $_ } @F;
' file

  1. GNU sed с помощью отсечения [[...]] пары, выполняет преобразование изолированной пары и объединяет ее обратно. Продолжайте до тех пор, пока не будет просмотрена каждая пара.
m='[^\n]'
sed -Ee "
  s/[[]{2}|]]/&\n/g;T;h
  :loop
    s/^$m*\n($m*)\n.*/\1/
    y/ /-/;G
    s/^($m*)\n($m*)\n$m*\n/\2\1/
    h
  /\n/b loop
" file

Выход:

Abc [[-\--]] def 
Ghi [[]] jkl 
Mno [[-]] pqr 
abc [["-\'-\\\"]] xyz
abc [[foo$$]] xyz [[a-b-c]] deal
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz
abc [[foo-$bar-baz]] xyz [[FOO-BAR-VAZ]] $#
1
18.03.2021, 22:32

Использование стандартаsed:

$ sed -e ':again' -e 's/\(\[\[[^]]*\) \([^]]*\]\]\)/\1-\2/g' -e 't again' file
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

Это заменяет каждый символ пробела между [[и ]]тире. Это делается путем сопоставления [[и ]], а в -между ними сопоставляется символ пробела, который может быть окружен какой-либо другой строкой. Совпадающая подстрока заменяется как есть, а пробел заменяется дефисом.

Если замена выполнена, команда tвозвращает сценарий к метке againдля другой замены. Это позаботится о пробелах, пропущенных в первый раз из-за перекрывающихся совпадений.

Так как указано, что каждый [[всегда связан с]](предположительно в одной строке ), мы можем немного сократить команду:

sed -e ':again' -e 's/\(\[\[[^]]*\) /\1-/g' -e 't again' file

Это не ищет закрытия ]].

2
18.03.2021, 22:32

Теги

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