如何用sed/awk提取首个Sources/Tests匹配后的所有内容?
问题根源
你的sed命令失效是因为正则中的.*是贪婪匹配——它会尽可能匹配最长的字符序列。当路径里存在多个含Tests的片段(比如Tests和StoreTests)时,^.*\(Tests\)会匹配到最后一个Tests之前的所有内容,最终只保留了最后一段Tests及后缀部分。
sed 解决方案
方法1:非贪婪匹配(推荐,支持匹配Tests/Sources)
通过-E启用扩展正则,用.*?实现非贪婪匹配,精准匹配到第一个Tests或Sources,替换掉前面的所有内容:
# 测试Tests路径 echo '/Users/random/354765478/Tests/StoreTests/Base64Tests.swift' | sed -E 's/^.*?(Tests|Sources)/\1/' # 输出:Tests/StoreTests/Base64Tests.swift # 测试Sources路径 echo '/Users/random/741672469/Sources/Store/StoreDataSource.swift' | sed -E 's/^.*?(Tests|Sources)/\1/' # 输出:Sources/Store/StoreDataSource.swift
方法2:基础正则写法(仅适用于目标目录为独立分段时)
如果不想启用扩展正则,可以匹配到第一个目标目录前的所有内容(通过匹配到目标目录前的最后一个/),然后替换为空:
echo '/Users/random/354765478/Tests/StoreTests/Base64Tests.swift' | sed 's/^.*\/\(Tests\)/\1/'
注:此方法仅当Tests是独立的目录名时有效,若路径中存在类似StoreTests的复合名称,需用方法1。
awk 解决方案
方法1:遍历路径分段
按/分割路径,找到第一个Tests或Sources的位置,拼接后面所有分段:
echo '/Users/random/354765478/Tests/StoreTests/Base64Tests.swift' | awk -F '/' '{ for(i=1; i<=NF; i++) { if($i == "Tests" || $i == "Sources") { result = $i for(j=i+1; j<=NF; j++) { result = result "/" $j } print result exit } } }'
方法2:正则匹配截取
利用match函数定位第一个目标关键词,直接截取后面的所有内容:
echo '/Users/random/354765478/Tests/StoreTests/Base64Tests.swift' | awk 'match($0, /Tests|Sources/) {print substr($0, RSTART)}'
内容的提问来源于stack exchange,提问作者chroman
相关产品推荐
相关产品推荐

