我想跳过第一次出现的模式(在此示例中为_
),然后将包含模式的字符串的其余部分替换为tab。例如:
T004_7_entry_00007_conf_01
所需的输出:
T004_7
我在sed中尝试了以下方法:
sed 's/_.*\t/\t/'
答案 0 :(得分:3)
对于给定的样本,有多种解决方法
$ echo 'T004_7_entry_00007_conf_01' | sed 's/\(_[^_]*\).*/\1\t/'
T004_7
\(_[^_]*\)
是用于保存第一次出现的捕获组
\(
和\)
是用于指定捕获组的元字符,如果使用ERE,则不需要\
[^_]*
表示零个或多个非_
字符,因此该解决方案仅适用于单个字符定界符\1
是对第一个捕获组的反向引用其他方式:
$ echo 'T004_7_entry_00007_conf_01' | perl -pe 's/_[^_]*\K.*/\t/'
T004_7
$ echo 'T004_7_entry_00007_conf_01' | awk -F_ '{print $1 FS $2 "\t" }'
T004_7
如果分隔符不是单个字符,则基于字段的解决方案更合适
$ echo 'foo_:_baz_:_123_:_456' | awk -F_:_ '{print $1 FS $2 "\t" }'
foo_:_baz
答案 1 :(得分:0)
请您尝试以下。
sed 's/\([^_]*\)\(_[^_]*\)\(.*\)/\1\2\t/' Input_file
如果要将输出保存到Input_file本身,请使用i
或i.bak
(备份以前的Input_file)。
使用awk
:
awk 'match($0,/^[[:alnum:]]+_[0-9]+/){print substr($0,RSTART,RLENGTH)\t}' Input_file
答案 2 :(得分:0)
非常仔细地编写了 sed 基于后向引用的答案-接近@ Sundeep 的答案,但这可以确保您实际上第二次出现{{1 }}:
_
借助 awk ,我们可以提供更多富有创意的解决方案。这是使用正则表达式的直接 awk 实现:
sed 's/\(_[^_]*\)_.*/\1\t/'
在此示例中,充分利用(滥用)字段分隔符功能,完全避开了正则表达式模式匹配以执行所需的操作:
awk 'match($0, /[^_]*_[^_]*_/) { $0 = substr($0, 1, RLENGTH - 1) "\t" } 1'
请注意,以上所有内容都认真遵循了您的示例,以模拟sed会产生的默认行为-即通过并打印所有行,包括不匹配的行。所有这些都小心地替换了第二次出现的awk -F_ 'NF > 2 { $0 = $1 FS $2 "\t" } 1'
以及后面带有_
的文本-所有不超过一个\t
的行都以未经编辑的方式通过。
如果我们希望将输出限制为仅打印匹配的行,则可以将两个示例中的_
替换为$0 =
,然后删除结尾的print
。