Я пытаюсь вывести строку, содержащую все между двумя словами строки:
ввод:
"Here is a String"
выход:
"is a"
Использование:
sed -n '/Here/,/String/p'
включает конечные точки, но я не хочу их включать.
Я пытаюсь вывести строку, содержащую все между двумя словами строки:
ввод:
"Here is a String"
выход:
"is a"
Использование:
sed -n '/Here/,/String/p'
включает конечные точки, но я не хочу их включать.
sed -e 's/Here\(.*\)String/\1/'
Простой grep может также поддерживать положительный и отрицательный внешний вид и обратную сторону: Для вашего случая команда будет следующей:
echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'
Вы можете разделить строки в 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
Принятый ответ не удаляет текст, который может быть до Here
или после String
. Это будет:
sed -e 's/.*Here\(.*\)String.*/\1/'
Основное различие заключается в добавлении .*
непосредственно перед Here
и после String
.
Если у вас длинный файл со многими многострочными ошибками, полезно сначала напечатать числовые строки:
cat -n file | sed -n '/Here/,/String/p'
Через GNU awk,
$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
is a
grep с параметром -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
Это может сработать для вас (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"
Вы можете использовать \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:
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: <[email protected]>
Per 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.
Per Извлечь текст между двумя строками в разных строках
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]]