Я пытаюсь вывести строку, содержащую все, что находится между двумя словами строки:
вход:
"Here is a String"
вывод:
"is a"
С помощью:
sed -n '/Here/,/String/p'
включает конечные точки, но я не хочу их включать.
sed -e 's/Here\(.*\)String/\1/'
echo "Here is a one is a String" | sed -e 's/one is\(.*\)String/\1/'
. Если вы просто хотите часть между «один» и «String», то вам нужно сделать регулярное выражение соответствует всей линии: sed -e 's/.*one is\(.*\)String.*/\1/'
. В sed s/pattern/replacement/
скажите «заменить« замену »на« шаблон »в каждой строке». Он изменит только то, что соответствует «шаблону», поэтому, если вы хотите, чтобы он заменял всю строку, вам нужно сделать так, чтобы «шаблон» соответствовал всей строке.
Here is a String Here is a String
GNU grep также может поддерживать позитивный и негативный прогноз и ретроспективный анализ: в вашем случае команда будет выглядеть так:
echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'
Если есть несколько вхождений Here
и string
, вы можете выбрать, хотите ли вы сопоставить с первого Here
и последнего string
или сопоставить их по отдельности. В терминах регулярного выражения это называется жадным совпадением (первый случай) или нежадным совпадением (второй случай)
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*(?=string)' # Greedy match
is a string, and Here is another
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*?(?=string)' # Non-greedy match (Notice the '?' after '*' in .*)
is a
is another
-P
опция GNU grep не существует во grep
включенном в * BSD или в тех, которые идут с любым SVR4 (Solaris и т. Д.). Во FreeBSD вы можете установить devel/pcre
порт, который включает pcregrep
, который поддерживает PCRE (и упреждающий / отстающий). В более старых версиях OSX используется GNU grep, но в OSX Mavericks он -P
является производным от версии FreeBSD, которая не включает эту опцию.
Here is a string a string
, оба " is a "
и " is a string a "
являются действительными ответами (не обращайте внимания на кавычки) в соответствии с требованиями к вопросу. Это зависит от вас, какой из них вы хотите, и тогда ответ может быть соответствующим. В любом случае, для вашего требования это сработает:echo "Here is a string a string" | grep -o -P '(?<=Here).*?(?=string)'
echo $'Here is \na string' | grep -zoP '(?<=Here)(?s).*(?=string)'
Принятый ответ не удаляет текст, который мог быть до Here
или после String
. Это будет:
sed -e 's/.*Here\(.*\)String.*/\1/'
Основное отличие - добавление .*
сразу до Here
и после String
.
*
квантификатор между Here
и String
не жадным (или ленивым). Однако тип регулярного выражения, используемый sed, не поддерживает ленивые квантификаторы ( ?
сразу после .*
) в соответствии с этим вопросом Stackoverflow. Обычно для реализации ленивого квантификатора вы просто сопоставляете все, кроме токена, который вы не хотите сопоставить, но в этом случае нет только одного токена, а целой строки String
.
.
не соответствует разрывам строки. Если вы хотите сопоставить разрывы строк, вы можете заменить .
что-то вроде [\s\s]
.
Вы можете удалить строки только в Bash :
$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ echo "$foo"
is a
$
И если у вас есть GNU grep, который включает PCRE , вы можете использовать утверждение нулевой ширины:
$ echo "Here is a String" | grep -Po '(?<=(Here )).*(?= String)'
is a
Через GNU awk,
$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
is a
grep with -P
( perl-regexp ) поддерживает параметр \K
, который помогает отбросить ранее сопоставленные символы. В нашем случае ранее согласованная строка была Here
исключена из окончательного вывода.
$ echo "Here is a string" | grep -oP 'Here\K.*(?=string)'
is a
$ echo "Here is a string" | grep -oP 'Here\K(?:(?!string).)*'
is a
Если вы хотите, чтобы результат был, is a
вы можете попробовать следующее:
$ echo "Here is a string" | grep -oP 'Here\s*\K.*(?=\s+string)'
is a
$ echo "Here is a string" | grep -oP 'Here\s*\K(?:(?!\s+string).)*'
is a
echo "Here is a string dfdsf Here is a string" | awk -v FS="(Here|string)" '{print $2}'
он только возвращается is a
вместо того, чтобы быть is a is a
@Avinash Raj
Если у вас длинный файл с множеством многострочных вхождений, полезно сначала вывести числовые строки:
cat -n file | sed -n '/Here/,/String/p'
-n
опцию в cat
.
cat
можно полностью опустить; sed
умеет читать файл или стандартный ввод.
Это может сработать для вас (GNU sed):
sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file
Это представляет каждое представление текста между двумя маркерами (в данном случае Here
и String
) на новой строке и сохраняет новые строки в тексте.
У всех вышеперечисленных решений есть недостатки, когда последняя строка поиска повторяется в другом месте строки. Я решил, что лучше написать функцию bash.
function str_str {
local str
str="${1#*${2}}"
str="${str%%$3*}"
echo -n "$str"
}
# test it ...
mystr="this is a string"
str_str "$mystr" "this " " string"
Вы можете использовать две команды s
$ echo "Here is a String" | sed 's/.*Here//; s/String.*//'
is a
Также работает
$ echo "Here is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
is a
$ echo "Here is a StringHere is a StringHere is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
is a
Чтобы понять sed
команду, мы должны построить ее шаг за шагом.
Вот ваш исходный текст
user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$
Попробуем удалить Here
строку с s
опцией ubstition вsed
user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$
На данный момент, я полагаю , вы могли бы удалить String
, а
user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$
Но это не ваш желаемый результат.
Чтобы объединить две команды sed, используйте -e
опцию
user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$
Надеюсь это поможет
Вы можете использовать \1
(см. Http://www.grymoire.com/Unix/Sed.html#uh-4 ):
echo "Hello is a String" | sed 's/Hello\(.*\)String/\1/g'
Содержимое, заключенное в скобки, будет сохранено как \1
.
Проблема. Мои сохраненные сообщения Claws Mail упакованы следующим образом, и я пытаюсь извлечь строки темы:
Subject: [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular
link in major cell growth pathway: Findings point to new potential
therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is
Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as
a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway
identified [Lysosomal amino acid transporter SLC38A9 signals arginine
sufficiency to mTORC1]]
Message-ID: <20171019190902.18741771@VictoriasJourney.com>
Согласно A2 в этой теме, как использовать sed / grep для извлечения текста между двумя словами? первое выражение, приведенное ниже, «работает» до тех пор, пока совпадающий текст не содержит новой строки:
grep -o -P '(?<=Subject: ).*(?=molecular)' corpus/01
[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key
Однако, несмотря на то, что я попробовал множество вариантов ( .+?; /s; ...
), я не смог заставить их работать:
grep -o -P '(?<=Subject: ).*(?=link)' corpus/01
grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01
etc.
Решение 1.
За извлечение текста между двумя строками в разных строках
sed -n '/Subject: /{:a;N;/Message-ID:/!ba; s/\n/ /g; s/\s\s*/ /g; s/.*Subject: \|Message-ID:.*//g;p}' corpus/01
который дает
[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]
Решение 2. *
Per Как я могу заменить новую строку (\ n) с помощью sed?
sed ':a;N;$!ba;s/\n/ /g' corpus/01
заменит новые строки пробелом.
Связать это с A2 в Как использовать sed / grep для извлечения текста между двумя словами? , мы получили:
sed ':a;N;$!ba;s/\n/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'
который дает
[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]
Этот вариант удаляет двойные пробелы:
sed ':a;N;$!ba;s/\n/ /g; s/\s\s*/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'
дающий
[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]
Here is a Here String
? ИлиI Hereby Dub Thee Sir Stringy
?sed
задаваемый вопрос - «как выделить текст между отдельными строками»; это stackoverflow.com/questions/16643288/…