bash 去除文件后缀

262 阅读1分钟

image.png

去除文件后缀有多种方式。测试驱动开发,假设我们的测试用例如下:

  • 输入 index2.html 输出 index2
  • 输入 index 输出 index
  • 输入 index-foo.html 输出 index-foo
  • 输入 foo/bar/baz/fox.html 输出 fox

版本 1:使用内置方法 basename

最简单是使用内置方法 basename,如果知道要去除哪种文件扩展名:

remove_known_extension() {
    local name=$(basename "$1", '.html')  # 提取文件名(去除路径和后缀)
    echo name
}

如果无法预先知道,需分两步:

remove_extension() {
    local filename=$(basename "$1")  # 提取文件名(去除路径)
    echo "${filename%.*}"            # 去除后缀
}

如果你是前端开发者,我们还可以在 bash 中调用 node.js 来达到相同目的。

版本 2:调用 Node.js 内置模块 path

因为:

❯ node
Welcome to Node.js v16.20.2.
Type ".help" for more information.
> require('path').parse('foo/bar/baz/fox.html')
{
  root: '',
  dir: 'foo/bar/baz',
  base: 'fox.html',
  ext: '.html',
  name: 'fox'
}

故:

require('path').parse('foo/bar/baz/fox.html').name
// 输出 `fox`

故:

remove_extension_use_node() {
    local filename="$1"
    node -e "console.log(require('path').parse('$filename').name)"
}

测试下:

# 生成 bash 字符串数组
array=("index2.html" "index" "index-foo.html" "foo/bar/baz/fox.html")

for filename in "${array[@]}"; do
    echo $filename '=>' "$(remove_extension_use_node "$filename")"
done

结果:

index2.html => index2
index => index
index-foo.html => index-foo
foo/bar/baz/fox.html => fox

版本 3:调用 Node.js 使用 split

remove_extension_use_split() {
    local filename="$1"
    node -p "'$1'.split('/').at(-1).split('.').at(0)"
}
小技巧

node -e 可以换个 flag -p(e for evaluation and p for print)也就省去了 console.log

- node -e "console.log(require('path').parse('$filename').name)"
+ node -p "require('path').parse('$filename').name"

性能对比

# 使用 Linux 内置命令 basename 🚀
bash t.sh  0.03s user 0.17s system 60% cpu 0.328 total

# 使用 node.js path 模块 🐌
bash t.sh  0.03s user 0.62s system 76% cpu 0.854 total

# 使用 split 🐌
bash t.sh  0.00s user 0.61s system 71% cpu 0.843 total

可以看出使用 Node.js 效率最低,因为每次调用都需要新启动一个线程,当然并不意味 Node.js 一定比 shell 慢。