fish shell: 是否可以方便地剥离扩展名?

fish shell: Is it possible to conveniently strip extensions?

有什么方便的方法可以从文件名中删除任意扩展名,就像 bash ${i%%.*} 那样?我会坚持我的朋友 sed 吗?

没有。 fish 的特性集比 bash 小很多,依赖于外部命令:

$ set filename foo.bar.baz
$ set rootname (echo $filename | sed 's/\.[^.]*$//')
$ echo $rootname
foo.bar

如果您知道扩展名(例如 _bak,一个常见用例),这可能更方便:

for f in (ls *_bak)
    mv $f (basename $f _bak)
end

使用 fish 内置的 string match 功能,您可以做到

set rootname (string match -r "(.*)\.[^\.]*$" $filename)[2]

字符串匹配 returns 2 项列表。第一个是整个字符串,第二个是第一个正则表达式匹配项(正则表达式括号内的内容)。因此,我们使用 [2].

获取第二个

fish string 命令仍然是处理此问题的规范方法。它有一些非常好的子命令,尚未在其他答案中显示。

split 允许您从右侧拆分,最大为 1,这样您就可以得到最后一个扩展。

for f in *
    echo (string split -m1 -r '.' "$f")[1]
end

replace 允许您使用正则表达式删除扩展名,定义为字符串末尾的最后一个点

for f in *
    string replace -r '\.[^\.]*$' '' "$f"
end

man string 了解更多信息和一些很好的例子。

--更新--

如果您的系统有适当的 basenamedirname 实用程序,您可以使用这样的东西:

function stripext \
    --description "strip file extension"

    for arg in $argv
        echo (dirname $arg)/(string replace -r '\.[^\.]+$' '' (basename $arg))
    end
end

您可以使用 string 命令从文件名中删除扩展名:

echo (string split -r -m1 . $filename)[1]

这将在最右边的点拆分 filename 并打印结果列表的第一个元素。如果没有点,则该列表将包含带有 filename.

的单个元素

如果您还需要去除前导目录,请将其与基本名称组合:

echo (basename $filename | string split -r -m1 .)[1]

在此示例中,string 从标准输入读取其输入,而不是将文件名作为命令行参数传递。

我也需要一个函数来拆分随机文件的根目录和扩展名。我没有冒着遇到警告的风险天真地重新实现该功能(例如:分隔符前的点),而是将任务转发给 Python 的内置 POSIX path 库并继承他们的专业知识。

这里有一个可能更喜欢的简单例子:

function splitext --description "Print filepath(s) root, stem or extension"

    argparse 'e/ext' 's/stem' -- $argv

    for arg in $argv
        if set -q _flag_ext
            set cmd 'import os' \
                    "_, ext = os.path.splitext('$arg')" \
                    'print(ext)'
        else if set -q _flag_stem
            set cmd 'from pathlib import Path' \
                    "p = Path('$arg')" \
                    'print(p.stem)'
        else
            set cmd 'import os' \
                    "root, _ = os.path.splitext('$arg')" \
                    'print(root)'
        end
        python3 -c (string join ';' $cmd)
    end

end

示例:

$ splitext /this/is.a/test.path
/this/is.a/test
$ splitext --ext /this/is.a/test.path
.path
$ splitext --stem /this/is.a/test.path
test
$ splitext /this/is.another/test
/this/is.another/test