dirname 去掉路径末尾斜杠及之后内容,故 /path/to/dir/ 输出 /path/to;对无斜杠路径(如 file.txt)返回 .;不检查路径存在性,仅字符串处理;多参数时逐行输出;获取脚本目录应配合 readlink -f 转绝对路径。

dirname 会把路径末尾的斜杠自动忽略
很多新手第一次用 dirname 时,发现对 /path/to/dir/ 执行后输出 /path/to,而不是预期的 /path/to/dir,以为命令出错了。其实这是正常行为——dirname 的设计逻辑是“去掉最后一个斜杠及其后的所有内容”,所以末尾的 / 被当作“最后一级目录名”处理并被裁掉。
常见错误现象:
-
dirname /home/user/→ 输出/home(不是/home/user) -
dirname ./logs/→ 输出.(不是./logs)
如果你真想保留末尾斜杠语义(比如后续要拼接文件名),得自己补上:dir=$(dirname "$path")/,但注意这会多一个斜杠,可能影响后续 cd 或 cp 行为。
处理相对路径和无斜杠路径时返回 "."
dirname 不检查路径是否存在,也不区分它是文件还是目录,只做字符串切分。只要输入里没有 /,它就统一返回 .。
使用场景举例:
-
dirname file.txt→. -
dirname ../script.sh→.. -
dirname .bashrc→. -
dirname /→/(根目录是唯一例外)
这个行为在脚本中很关键:如果你用 dirname "$0" 获取脚本所在目录,而脚本是通过相对路径调用的(如 ./bin/run.sh),结果就是 . 或 ./bin,不是绝对路径。需要配合 readlink -f 才能转成绝对路径。
批量处理多个路径时每行一个输出
dirname 支持一次传入多个路径参数,它会逐个处理,每行输出一个结果。这对 find 或循环处理特别有用。
实操建议:
- 直接传参:
dirname /a/b/c.txt /x/y/z.log→ 两行输出/a/b和/x/y - 配合
find使用:find . -name "*.conf" -print0 | xargs -0 dirname | sort -u,这里必须用-print0+-0配合,否则含空格的路径会崩 - 如果路径里可能含换行符(极少见),加
-z选项:dirname -z path1 path2,输出用\0分隔,再用xargs -0消费
不加引号或未用 -z 处理含空格路径,会导致参数被 shell 错误拆分,dirname 收到的就不是完整路径了。
在脚本中获取自身所在目录的正确写法
很多人写 SCRIPT_DIR=$(dirname "$0") 就完事,但这只适用于绝对路径调用或当前目录下执行。一旦从别处用相对路径调用(如 /tmp/run.sh),$0 是 /tmp/run.sh,dirname 返回 /tmp;但如果用 ./run.sh,$0 是 ./run.sh,dirname 返回 .,后续 cd $SCRIPT_DIR 就可能进错目录。
可靠做法是先转成绝对路径再取目录:
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
注意点:
-
readlink -f不是 POSIX 标准,BusyBox 或某些精简系统可能不支持,可改用realpath(需安装)或手写兼容逻辑 - 如果脚本被
source进来(而非执行),$0是调用者的 shell 名,不是脚本路径,此时应改用${BASH_SOURCE[0]}(Bash)或$0在 sourced 场景下不可靠
最易被忽略的是:dirname 的输出本身不带尾部斜杠,但很多后续操作(如 cd "$dir"、cp file "$dir/")隐含依赖斜杠存在。要不要加、什么时候加,得看下游命令是否接受无尾斜杠路径。


















