如何使用sed/grep在两个单词之间提取文本?

use*_*650 110 string bash grep sed

我试图输出一个字符串,其中包含字符串的两个单词之间的所有内容:

输入:

"Here is a String"
Run Code Online (Sandbox Code Playgroud)

输出:

"is a"
Run Code Online (Sandbox Code Playgroud)

使用:

sed -n '/Here/,/String/p'
Run Code Online (Sandbox Code Playgroud)

包括端点,但我不想包含它们.

ani*_*ane 153

GNU grep还可以支持正面和负面的前瞻和回顾:对于您的情况,命令将是:

echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'
Run Code Online (Sandbox Code Playgroud)

如果有多次出现Herestring,您可以选择是要匹配第一个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 
Run Code Online (Sandbox Code Playgroud)

  • 请注意,GNU grep的`-P`选项不存在于*BSD中包含的`grep`中,也不存在于任何SVR4(Solaris等)附带的选项中.在FreeBSD中,你可以安装`devel/pcre`端口,它包含`pcregrep`,它支持PCRE(以及前瞻/后退).旧版本的OSX使用GNU grep,但在OSX Mavericks中,`-P`源自FreeBSD的版本,不包括该选项. (25认同)
  • 如果`这是一个字符串一个字符串`,**两个**`"是一个"`和`"是一个字符串a`是有效答案(忽略引号),根据问题要求.这取决于你这些**你想要哪一个然后回答可能会有所不同.无论如何,根据您的要求,这将起作用:`echo"这是一个字符串"| grep -o -P'(?<=这里).*?(?= string)'` (6认同)
  • 这不起作用,因为如果您的结束字符串"string"不止一次出现,它将获得*last*occurrence,而不是*next*occurrence. (4认同)
  • @BND,您需要启用[pcregrep的多行搜索功能](/sf/answers/501698081/)。`echo $'这里是\na 字符串' | grep -zoP '(?&lt;=这里)(?s).*(?=字符串)'` (3认同)

Bri*_*ell 92

sed -e 's/Here\(.*\)String/\1/'
Run Code Online (Sandbox Code Playgroud)

  • 当输入为"这是一个字符串这里是一个字符串"时,这会中断 (6认同)
  • @ user1190650如果你想看到"这里是一个",这将有用.你可以测试一下:`echo"这是一个字符串"| sed -e's/one是\(.*\)String /\1 /'`.如果你只想要"one is"和"String"之间的部分,那么你需要让正则表达式匹配整行:`sed -e's /.*one is \(.*\)String.*/\1 /'`.在sed中,`s/pattern/replacement /`说'替换'替换'为每行''pattern'".它只会改变任何匹配"pattern"的东西,所以如果你想要它替换整行,你需要让"pattern"匹配整行. (5认同)
  • 谢谢!如果我想在“这里是一个字符串”中找到“一个是”和“字符串”之间的所有内容怎么办?(sed -e's / one是\(。* \)String / \ 1 /'吗? (2认同)

whe*_*ler 49

接受的答案不会删除之前Here或之后的文本String.这将:

sed -e 's/.*Here\(.*\)String.*/\1/'
Run Code Online (Sandbox Code Playgroud)

主要的区别是增加了.*之前Here和之后String.


gho*_*oti 34

你可以单独在Bash中删除字符串:

$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ echo "$foo"
is a
$
Run Code Online (Sandbox Code Playgroud)

如果你有一个包含PCRE的GNU grep ,你可以使用零宽度断言:

$ echo "Here is a String" | grep -Po '(?<=(Here )).*(?= String)'
is a
Run Code Online (Sandbox Code Playgroud)


Avi*_*Raj 20

通过GNU awk,

$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
 is a 
Run Code Online (Sandbox Code Playgroud)

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 
Run Code Online (Sandbox Code Playgroud)

如果你想要输出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
Run Code Online (Sandbox Code Playgroud)


ale*_*mol 19

如果您有一个包含多行多行的长文件,首先打印数字行很有用:

cat -n file | sed -n '/Here/,/String/p'
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!这是我的唯一解决方案(多行文本文件,而不是没有换行符的单个字符串).显然,要使它没有行编号,必须省略`cat`中的`-n`选项. (3认同)
  • ...在这种情况下 `cat` 可以完全省略;`sed` 知道如何读取文件或标准输入。 (2认同)

pot*_*ong 8

这可能适合你(GNU sed):

sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file 
Run Code Online (Sandbox Code Playgroud)

这带来两个标志(在这种情况下之间的文本每个表示HereString上一个新行),并在文本中保留新行.


小智 8

要理解sed命令,我们必须一步一步地构建它。

这是你的原文

user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$ 
Run Code Online (Sandbox Code Playgroud)

让我们尝试Here使用substition 选项删除字符串sed

user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$ 
Run Code Online (Sandbox Code Playgroud)

在这一点上,我相信你将能够去除String以及

user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$ 
Run Code Online (Sandbox Code Playgroud)

但这不是您想要的输出。

要组合两个 sed 命令,请使用-e选项

user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$ 
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助


Gar*_*ean 7

上述所有解决方案都有缺陷,其中最后一个搜索字符串在字符串的其他位置重复。我发现最好编写一个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"
Run Code Online (Sandbox Code Playgroud)


Iva*_*van 7

您可以使用两个 s 命令

$ echo "Here is a String" | sed 's/.*Here//; s/String.*//'
 is a 
Run Code Online (Sandbox Code Playgroud)

也有效

$ 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 
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

398309 次

最近记录:

6 年,8 月 前