Как я могу определить прематч и постматч с помощью 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или что-то подобное... Однако вы, возможно, захотите прочитать Можно ли использовать подстановку для поиска содержимого файла?