我需要从 shell 脚本中的一行中提取一个单词,我见过类似的例子,但没有一个起作用。
举个例句
word1 word2 word3/pattern/word4.word5 word6
鉴于pattern
它应该返回,word3/pattern/word4.word5
两边都没有空格。
此外,它应该限制该行不能以某些字符开始,#
。
我设法找到一个 grep 命令来隔离该行
grep "^[^#].*pattern" $FILE
将返回所有不以 开头#
且不包含 的行pattern
。那么我怎样才能从这一行中提取这个词呢?
编辑:使用ubuntu 20.04
另外,关于这个句子,这个例子或多或少与它应该是什么样子的有关。该模式每行最多出现一次,并通过空格与其他单词分隔开。给定一行,我想返回包含模式的单词,左右移动所有内容,直到遇到空格(不包括空格)。
答案1
只要模式不匹配任何空格,就grep -o '[^[:space:]]*pattern[^[:space:]]*'
应该这样做。 ([^[:space:]]*
匹配任意数量的非空白字符。)
正则表达式引擎通常从最左边的位置开始查找匹配,并且匹配是贪婪的,这意味着它们尽可能匹配字符串的一部分。因此,模式两侧的所有非空白都应该在这里被拾取。
要忽略以井号开头的行,您只需通过管道即可grep -v "^#"
。
所以例如如果hello.txt
包含
# my pattern
word1 word2 word3/pattern/word4.word5 word6
然后:
% < hello.txt grep -v "^#" | grep -o '[^[:space:]]*pattern[^[:space:]]*'
word3/pattern/word4.word5
答案2
另一种 GNUgrep
方法:
grep -oP '^[^#].*\K\S*pattern\S*" "$file"
该-o
标志grep
仅返回该行的匹配部分,并且-P
启用 Perl 兼容正则表达式 (PCRE),这让我们-K
“忘记到目前为止匹配的所有内容”。这允许我们使用^[^#]
“匹配除#
行开头的 a 之外的任何字符”,但不包括结果中从开头开始的所有字符。 PCRE 还\S
为我们提供了“非空白”。
总而言之,这将匹配不以 a 开头#
且包含 的行,pattern
然后将打印包含该模式的最长的非空白字符串。
请注意,如果在同一行上多次出现pattern
,则由于.*
之前的 ,这将返回最右侧的匹配项\K
。要返回最左边的匹配项,请使用:
grep -oP '^[^#].*?\K\S*pattern\S*' file
答案3
和GNU grep
:
grep -oP '^(?<!#).*?\K(\w+[/\.])+\w+' file
word3/pattern/word4.word5
正则表达式匹配如下:
节点 | 解释 |
---|---|
^ |
字符串的开头 |
(?<! |
向后看看看是否有: |
# |
# |
) |
后视结束 |
.*? |
除 \n 之外的任何字符(0 次或多次(匹配尽可能少的数量)) |
\K |
重置比赛的开始(什么是K ept)作为使用后视断言的更短替代方案:环顾四周和正则表达式中对 K 的支持 |
( |
分组并捕获到 \1(1 次或多次(匹配尽可能多的数量)): |
\w+ |
单词字符(az、AZ、0-9、_)(1 次或多次(匹配尽可能多的数量)) |
[/\.] |
任何字符:“/”、“.” |
)+ |
\1 的结尾(注意:因为您在此捕获上使用量词,所以只有捕获模式的最后一个重复才会存储在 \1 中) |
\w+ |
单词字符(az、AZ、0-9、_)(1 次或多次(匹配尽可能多的数量)) |