【发布时间】:2019-12-06 08:01:28
【问题描述】:
我有一些文件的名称如下例所示:
2000_A_tim110_may112_AATT_V22_P001_R1_001_V23_P007_R2_001_comb.ext
2000_BB_tim110_may112_AAMM_V14_P002_R1_001_V45_P008_R2_001_comb.ext
2000_C_tim110_DDFF_V18_P006_R1_001.ext
2000_DD_may112_EEJJ_V88_P004_R1_001.ext
从这些文件名中,我想提取前导 2000_[A-Z]{1,2} 和 V[0-9]{2} 正则表达式模式的所有实例。
也就是说,
来自
2000_A_tim110_may112_AATT_V22_P001_R1_001_V23_P007_R2_001_comb.ext
我想要
2000_A_V22_V23
从
2000_DD_may112_EEJJ_V88_P004_R1_001.ext
我想要
2000_DD_V88
我一直在尝试通过 sed 实现这一目标,但到目前为止我还没有取得任何成功。
起初——相当天真——我尝试过
find *.ext | sed -r 's/^(2000_[A-Z]{1,2}).*(V{1}[0-9]{2,3}).*(V{1}[0-9]{2,3}).*\.ext/\1_\2_\3/'
结果如下:
2000_A_V22_V23
2000_BB_V14_V45
2000_C_tim110_DDFF_V18_P006_R1_001.ext
2000_DD_may112_EEJJ_V88_P004_R1_001.ext
这不是我想要的,因为这里有两个文件名未经编辑返回。
然后,在阅读了this post 之后,我尝试将在中间捕获的组设为可选,如下所示:
find *.ext | sed -r 's/^(2000_[A-Z]{1,2}).*(V{1}[0-9]{2})?.*(V{1}[0-9]{2}).*\.ext/\1_\2_\3/'
但这似乎也没有用,因为它返回了
2000_A__V23
2000_BB__V45
2000_C__V18
2000_DD__V88
(即中间的捕获组似乎已被完全跳过。)
我的问题是,我如何得到以下结果?
2000_A_V22_V23
2000_BB_V14_V45
2000_C_V18
2000_DD_V88
我哪里错了?或者相反,我错过了什么?我对sed 和regex 很陌生--我想学习如何很好地使用这两种方法--因此非常感谢您的指点和指导。
【问题讨论】:
-
在
sed中至少很难做到——我几乎已经准备好说“不可能”,但这可能不太正确。您可能不得不反复删除您不想要的位,sed可以这样做(标签、测试和分支,尽管负面模式使生活变得复杂;这些模式可能会在前后利用下划线),但是这既不简单也不明显。 -
如果您想学习 sed,我们可以为您提供 sed 解决方案。如果您想要一个可行的简单解决方案,您应该选择不同的工具。
-
@Beta,我不介意接受上述教育(只要对您/教育者来说不会太麻烦)。作为一个新手,很难确定哪种工具适合手头的任务——例如,Ed Morton 发布了一个简洁的答案,它使用了我以前从未真正使用过的
awk,但遇到过各种被吹捧的情况作为与sed相当的工具。我觉得您在此处提供给我的任何信息都将帮助我更好地了解这些工具及其相对优势/劣势。 -
@JonathanLeffler 不需要 sed 中的硬工具,只需替换
|操作员就可以完成这项工作。看我的回答。
标签: regex string bash sed regex-group