Как я могу определить прематч и постматч с помощью egrep или ksh под Linux

Я работаю над проблемой в офисе, работающем в системе Linux. Я хотел бы иметь возможность использовать сопоставление шаблонов egrep или ksh для определения не только совпавшей строки, но мне также необходимо иметь возможность определять строки предварительного и постматчного соответствия.

Я знаю, что могу сделать это в Perl, но мне также хотелось бы иметь возможность делать это, используя сопоставление шаблонов egrep или ksh.

Я поискал в Google и нашел команду egrep, в которой вы можете указать количество символов предварительного и постматчного соответствия, но этого недостаточно. Мне нужны все строки до и после матча.

1 ответ

С

вы можете использовать Perl\K(включение регулярных выражений, совместимых с Perl, с помощью опции -P) и такой шаблон просмотра :

      $ echo -e "pre1 line1 post1\npre2 line2 post2" |
grep -Po "pre2.*\Kline.(?=.*post2)"
line2

...где узорыpre2.*и.*post2ищутся и оцениваются, но не включаются в соответствующие выходные данные, а шаблонline.выводится на выходе при успешном совпадении всех трех шаблонов в одной и той же последовательности во входной строке.

В оболочке

Вbashа также вksh,zshи другие подобные Bourne-подобные оболочки, вы можете сделать что-то похожее на это:

      pat="line."
pre="pre2.*"
post=".*post2"

echo -e "pre1 line1 post1\npre2 line2 post2" |
while IFS= read -r line
  do
    [[ "$line" =~ $pre$pat$post ]] && echo "$line"
    done
### Outputs "pre2 line2 post2"
### You can echo "$pat" as well

Или имитировать вышеописанноеgrep -Poвывод в файл, такая функция:

      mygrep () {

pre="${1}.*"
pat="$2"
post=".*${3}"
file="$4"
help="Usage: mygrep \"prematch\" \"match\" \"postmatch\" \"filename\""

if [[ $# -lt 4 ]]
  then
    echo "$help"
    return
    fi

while IFS= read -r line
  do
    if [[ "$line" =~ $pre$pat$post ]]
      then
        for word in $line;
          do
            [[ "$word" =~ $pat ]] && echo "$word" && break
            done
      fi
    done < "$file"
    
}

... и это будет работать так:

      $ cat file
pre1 line1 post2
pre2 someword line2 otherword post2
pre3 line3 nomatch post3
pre2 match match line4 will match post2
pre2 post2
pre2 nomatch post2
$
$
$ mygrep --help
Usage: mygrep "prematch" "match" "postmatch" "filename"
$
$
$ mygrep "pre2" "line." "post2" "./file"
line2
line4

Обратите внимание , что параметр без кавычек$lineв головеforцикл создан намеренно и предназначен для того, чтобы позволить оболочке разделить слова, чтобы отдельные слова в этой входной строке могли быть зациклены, но знайте, что это также позволит оболочке выполнить подстановку имен файлов в текущем рабочем каталоге, если одно из слов в этой строке оказались какие-либо символы, и поэтому в этом случае вы можете сначала прочитать слова (разделенные на пробелы ) в этой строке в массив и вместо этого перебирать их как элементы массива, цитируя расширение элементов этого массива. .. Что в данном случае было бы безопаснее ( включено и то, и другое по образовательным причинам )... Вот так:

      mygrep () {

pre="${1}.*"
pat="$2"
post=".*${3}"
file="$4"
help="Usage: mygrep \"prematch\" \"match\" \"postmatch\" \"filename\""

if [[ $# -lt 4 ]]
  then
    echo "$help"
    return
    fi

while IFS=' ' read -r -a line
  do
    if [[ "${line[*]}" =~ $pre$pat$post ]]
      then
        for word in "${line[@]}";
          do
            [[ "$word" =~ $pat ]] && echo "$word" && break
            done
      fi
    done < "$file"
    
}

Обратите также внимание, что оболочка, хотя и может сопоставлять текст с использованием либо шаблонов glob, либо шаблонов регулярных выражений, не является лучшим выбором для этого... Используйтеgrepили что-то подобное... Однако вы, возможно, захотите прочитать Можно ли использовать подстановку для поиска содержимого файла?

Другие вопросы по тегам