Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

2.2. basename - 提取文件名部分

basename 命令用于提取文件路径中的文件名部分,即去掉目录路径和可选的后缀。

基本语法

basename 名称 [后缀]
basename 选项... 名称...
			

常用选项:

  • -s, --suffix=SUFFIX - 删除指定的后缀

  • -a, --multiple - 支持多个参数

  • -z, --zero - 输出以 NUL 结尾而非换行符

  • --help - 显示帮助信息

  • --version - 显示版本信息

基本用法示例

提取文件名:

$ basename /usr/bin/find
find

$ basename /etc/nginx/nginx.conf
nginx.conf

$ basename /var/log/syslog
syslog

$ basename ./script.sh
script.sh
			

删除指定后缀:

$ basename /etc/nginx/nginx.conf .conf
nginx

$ basename /path/to/file.tar.gz .gz
file.tar

$ basename document.pdf .pdf
document
			

使用 -s 选项删除后缀:

$ basename -s .txt readme.txt
readme

$ basename -s .sh script.sh
script
			

处理多个文件(使用 -a):

$ basename -a /path/to/file1.txt /path/to/file2.txt
file1.txt
file2.txt

$ basename -s .txt -a /path/to/file1.txt /path/to/file2.txt
file1
file2
			

2.2.1. 排除扩展名

使用 basename 命令删除扩展名:

$ basename test.txt .txt
test

$ basename archive.tar.gz .tar.gz
archive
			

使用 Shell 参数展开删除扩展名:

file=test.txt
b=${file%.*}
echo $b
			

批量重命名文件(删除扩展名或更改扩展名):

$ for file in *.JPG;do mv $file ${file%.*}.jpg;done

# 或者使用 rename 命令
$ rename 's/\.JPG$/.jpg/' *.JPG
			

2.2.2. 取扩展名

使用 Shell 参数展开提取文件扩展名:

file=test.txt
b=${file##*.}
echo $b
			

更多扩展名处理示例:

# 单扩展名
file=document.pdf
echo "${file##*.}"  # 输出: pdf

# 多扩展名(取最后一个)
file=archive.tar.gz
echo "${file##*.}"  # 输出: gz

# 取所有扩展名
file=archive.tar.gz
echo "${file#*.}"   # 输出: tar.gz

# 没有扩展名
file=Makefile
echo "${file##*.}"  # 输出: Makefile(与文件名相同)

# 隐藏文件
file=.gitignore
echo "${file##*.}"  # 输出: gitignore
			

实际应用

在脚本中获取文件名(不含路径):

#!/bin/bash
for filepath in /var/log/*.log; do
    filename=$(basename "$filepath")
    echo "处理文件: $filename"
done
			

备份文件时保留原始文件名:

src="/etc/nginx/nginx.conf"
filename=$(basename "$src")
cp "$src" "/backup/${filename}.bak"
			

批量转换文件格式:

# 将所有 .txt 文件转换为 .md
for file in *.txt; do
    name=$(basename "$file" .txt)
    mv "$file" "${name}.md"
done
			

创建日志文件:

script_name=$(basename "$0" .sh)
log_file="/var/log/${script_name}.log"
echo "$(date): 脚本开始" >> "$log_file"
			

与 dirname 配合使用

dirname 和 basename 可以完整分解文件路径:

filepath="/usr/local/bin/script.sh"

dir=$(dirname "$filepath")    # /usr/local/bin
file=$(basename "$filepath")  # script.sh

echo "目录: $dir"
echo "文件: $file"

# 重新组合
echo "${dir}/${file}"  # /usr/local/bin/script.sh
			

移动文件到另一个目录但保持文件名:

src="/tmp/data.csv"
dest_dir="/var/data"
filename=$(basename "$src")
mv "$src" "${dest_dir}/${filename}"
			

Shell 参数展开替代

在 Bash 中可以使用参数展开实现 basename 的功能:

filepath="/usr/local/bin/script.sh"

# basename 等价于
echo "${filepath##*/}"  # 输出: script.sh

# basename 删除后缀等价于
echo "${filepath##*/}" | sed 's/\.[^.]*$//'  # 输出: script
# 或使用两层展开
base="${filepath##*/}"
echo "${base%.*}"  # 输出: script

# 特殊情况
filepath="script.sh"
echo "${filepath##*/}"  # 输出: script.sh
basename "$filepath"    # 输出: script.sh
			

参数展开比调用 basename 命令更快(无需创建子进程),适合在循环中使用。

常见陷阱

处理包含空格的文件名时必须加引号:

# 错误 - 空格会导致问题
basename /path/with spaces/file.txt
# 输出: file.txt(但可能在其他命令中出错)

# 正确 - 使用引号
basename "/path/with spaces/file.txt"
# 输出: file.txt
			

后缀匹配是精确的字符串匹配:

# .gz 只匹配 .gz,不匹配 .tar.gz
$ basename archive.tar.gz .gz
archive.tar

$ basename archive.tar.gz .tar.gz
archive

# 如果要删除多层后缀,需要多次处理或使用 ${file%.*}
file=archive.tar.gz
echo "${file%.*}"  # archive.tar
echo "${file%%.*}"  # archive(删除所有后缀)
			

路径末尾的斜杠会被忽略:

$ basename /usr/bin/
bin

$ basename /usr/bin
bin
			

高级技巧

提取文件名(不含扩展名)的多种方法:

file="/path/to/document.pdf"

# 方法 1: basename + sed
basename "$file" | sed 's/\.[^.]*$//'

# 方法 2: 参数展开(推荐)
base=$(basename "$file")
echo "${base%.*}"

# 方法 3: 纯参数展开
base="${file##*/}"
echo "${base%.*}"
			

批量重命名文件:

# 将所有 .jpeg 重命名为 .jpg
for file in *.jpeg; do
    newname=$(basename "$file" .jpeg).jpg
    mv "$file" "$newname"
done

# 为所有文件添加时间戳前缀
timestamp=$(date +%Y%m%d)
for file in *.txt; do
    mv "$file" "${timestamp}_${file}"
done