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

如何在Bash脚本中用Awk移除文本文件最后一个.后的内容

问题描述

我有一个名为filename.txt的文件,内容如下:

MOR22A2.S4000011.h23v22.061.2023063111017.hdf
MOR22A2.S4000011.h23v44.061.2023061111033.hdf
AST006_S003.zip
AST003_S066.zip

我需要移除文件名的扩展名——也就是删除最后一个.之后的所有内容。我尝试了这条awk命令:

awk '{print substr($0, 1, index($0, ".") - 1)}' filename.txt

但它只会删除第一个.之后的内容,得到的结果不符合预期:

MOR22A2
MOR22A2
AST006_S003
AST003_S066

我的期望结果是:

MOR22A2.S4000011.h23v22.061.2023063111017
MOR22A2.S4000011.h23v44.061.2023061111033
AST006_S003
AST003_S066

请问在Bash脚本中,应该使用什么正确的awk命令来处理这个文件?

解决方法

之前的命令失效是因为index($0, ".")只会返回第一个.的位置,要实现需求,需要定位到最后一个.,以下是几种可行的awk方案:

方案1:正则替换(最简洁)

利用awk的sub函数,用正则匹配最后一个.及其后续内容并替换为空:

awk '{sub(/\.[^.]*$/, ""); print}' filename.txt

正则\.[^.]*$的含义:匹配行尾前的最后一个.,以及后面所有非.的字符,替换为空即可保留扩展名之前的部分。

如果需要直接修改原文件,可以借助临时文件:

awk '{sub(/\.[^.]*$/, ""); print}' filename.txt > temp.txt && mv temp.txt filename.txt

或者安装moreutils包后使用sponge命令(避免临时文件):

awk '{sub(/\.[^.]*$/, ""); print}' filename.txt | sponge filename.txt

方案2:遍历字符找最后一个.的位置

通过循环遍历每行的每个字符,记录最后一个.的索引,再截取前面的内容:

awk '{
    last_dot = 0
    for (i=1; i<=length($0); i++) {
        if (substr($0,i,1) == ".") {
            last_dot = i
        }
    }
    print (last_dot > 0) ? substr($0,1,last_dot-1) : $0
}' filename.txt

方案3:分割数组后重组

用split函数把每行按.分割成数组,再将除最后一个元素外的所有部分用.拼接起来:

awk '{
    n = split($0, arr, ".")
    if (n > 1) {
        res = arr[1]
        for (i=2; i<n; i++) {
            res = res "." arr[i]
        }
        print res
    } else {
        print $0
    }
}' filename.txt

方案4:结合rev命令反向处理

先把每行反转,找到第一个.(对应原行的最后一个.),截取后再反转回来:

rev filename.txt | awk -F. '{print substr($0, index($0,".")+1)}' | rev

内容的提问来源于stack exchange,提问作者sjadhav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:54:56