You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 12:55:25