У меня есть строка, из которой мне нужно извлечь подстроку, но конец моего регулярного выражения повторяется. Я бы хотел, чтобы sed остановился на первом экземпляре конца моего регулярного выражения, подобно тому, как функции instr() во многих языках возвращают первый экземпляр. Пример:
echo "This is a test some stuff I want string junk string end" | sed -n 's/.*\(.te.*ng\).*/\1/p'
returns: test some stuff I want string junk string
I want to return: test some stuff I want string
решение1
грэпподход (требуетПКРЕподдерживать):
s="This is a test some stuff I want string junk string end"
grep -Po 'te.*?ng' <<< $s
Альтернативаперлподход:
perl -ne 'print "$&\n" if /te.*?ng/' <<< $s
Вывод (для обоих подходов):
test some stuff I want string
.*?
-?
вотнежадныймодификатор, указывает на соответствиеминимальная мода
решение2
Сделайте это в два шага: сначала удалите префикс (если в префиксе присутствовал терминатор), затем удалите все после префикса. Используйте команду, T
чтобы пропустить строку, если она не совпадает:
echo "This is a test some stuff I want string junk string end" |
sed -n 's/.*\(.te.*ng\)/\1/; T; s/\(ng\).*/\1/p'
Либо сначала удалите несоответствующие строки, а затем выполните замену в удобное для вас время.
echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/!d; s/.*\(.te.*ng\)/\1/; s/\(ng\).*/\1/'
В качестве альтернативы выполните замену и окончательную печать только на совпадающих строках.
echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/ { s/.*\(.te.*ng\)/\1/; s/\(ng\).*/\1/p; }'
решение3
Я бы посоветовал использовать команду cut в вашем случае.
echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1
Это разрежет строку на три части (до первой, после второй и между «строкой») с помощью -d"" вы можете выбрать, какой шаблон вы хотите использовать в качестве резака, а с помощью -fNumber вы выбираете, какую часть взять. Проблема: «строка» будет удалена Решение:
String=`echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1`
String="$(String) string"
echo $String
Он добавляет разделитель «string», который был удален, в конец переменной $String, которая была определена с помощью выходных данных.
решение4
# Как выполнить жадное сопоставление: "test .*? string" с использованием POSIX sed
sed -e '
/test.*string/!d; # non-interesting line
/^test/s/string/&\
/; # append marker after the first substring "string"
/\n/{P;d;} # initial portion of pattern space is our result
s/test/\
&/;D; # remove portion before the substring "test"
' yourfile
ДругойPOSIX-lyМетод заключается в том, чтобы удалять подстроку "string" по одной за раз с конца пространства шаблона, пока не останется только одна (после подстроки "test"). Затем остается вывести подстроку "test" на передний план:
sed -e '
:loop
s/\(test.*string\).*string.*/\1/
tloop
/^test/!s/test/\
&/;/\n/D
' yourfile