你有没有遇到过这种破事:在 Finder 里整理资料,半路想补一个 TODO.md,或者想在某个项目目录里塞一个空的 index.js 占位,结果必须老老实实打开编辑器,再在“存储为”对话框里一层层点路径。更别说有些人刚从 Windows 过来,还习惯右键直接“新建文本文档”,macOS 桌面端偏偏没给这个入口。
我用 Automator 折腾了一套方案:在 Finder 的当前目录下,一条快捷键或一次右键,就能直接创建文件。不需要安装第三方右键菜单工具,不需要先去某个 App 里新建再保存,轻量、免费、可随意改成自己想要的样子。
文章面向两类人:一类是刚接触 Mac、想找回“右键新建文件”体验的普通用户;另一类是每天在 Finder 里整理素材、写文档、摆项目结构的开发者。我会把 Automator 里最容易踩的坑也一并写出来,尤其是“到底怎么定位 Finder 当前目录”这个问题,很多教程都含糊带过,实际操作时最容易翻车。
1. 先用 30 秒判断:你要的是右键菜单、工具栏按钮还是文件夹监视
Automator 打开之后会让我们选工作流类型,很多人看到“快速操作”“应用程序”“文件夹操作”三个选项就懵了。这三个都能执行 Shell 脚本,但触发逻辑完全不同。
- 快速操作:绑定到 Finder 的右键菜单,或者菜单栏的“服务/快速操作”里。它的特点是必须选中一个文件或文件夹之后才能触发。好处是能和 Finder 原生交互深度结合,缺点也明显:你在某个目录的空白处点右键,看不到它。
- 应用程序:生成一个独立
xx.app,你可以把它拖到 Finder 窗口顶部工具栏上,双击也可以运行,还能像“文件拖把”一样把文件或文件夹拖到它的图标上。这个方案最接近“在窗口空白处新建”,是我现在的主力用法。 - 文件夹操作:可以指定某个目录,只要这个目录内容发生变化就自动执行脚本。它适合“监视固定上传目录”“自动整理下载文件夹”这种场景,和标题里“当前目录”的通用诉求并不匹配,因为你需要预先给每个目录都绑定一次。
三类工作流的差异,我用一张表简单总结:
| 类型 | 触发方式 | 能获取的“当前目录” | 适合本需求吗 |
|---|---|---|---|
| 快速操作 | 右键选中文件/文件夹后触发 | 选中项所在目录 | 适合,绑定快捷键后很顺手 |
| 应用程序 | 双击、拖拽到 Finder 工具栏、拖文件到图标 | 需要通过 Finder 获取,或者读传入路径 | 最适合,可以做到“在空白处新建” |
| 文件夹操作 | 目录内容变化时自动触发 | 固定绑定的目标目录 | 不适合作为通用方案 |
我的最终配置里其实同时用了两种:一个快速操作拿来绑快捷键,一个应用程序放到 Finder 工具栏上。因为只做一个时,遇到“当前目录里没有选中任何文件”的情况总会有那么一点别扭。读完下文你也会发现,核心逻辑其实一模一样,复制就能用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 拿到真正的“当前目录”:为什么不能信 pwd,而要用 insertion location
很多人第一次写 Automator 脚本,第一反应是在“运行 Shell 脚本”里放一句:
bash复制pwd
结果运行完发现输出不是 Finder 当前窗口的路径,有时甚至是 /。这不是你写错了,而是 Automator 运行 Shell 脚本时,工作目录根本不继承 Finder 的上下文。Shell 进程的工作目录和“你眼睛看到的 Finder 当前目录”完全可能是两回事。
正确做法是让 AppleScript 去问 Finder:你现在显示的是哪个文件夹?Finder 有一个叫 insertion location 的概念,翻译过来是“插入位置”,大概意思就是:如果我现在往当前窗口里粘贴一个文件,它会落到哪个目录。
单命令就能获取:
bash复制osascript -e 'tell application "Finder" to get POSIX path of (insertion location as alias)'
比如你在 Finder 里打开 ~/Documents/工作项目,执行这条命令会得到类似 /Users/你的用户名/Documents/工作项目/ 的结果,末尾带一个斜杠。
这个 insertion location 比“选中文件再取目录”更可靠。为什么?因为如果你只是把光标停在目录里、并没有选中任何文件,它也会正确返回当前窗口的目录。你不用额外判断“到底有没有选中项”。
但有一类情况不能只用它,那就是“拖文件到 App 图标”。当你把一个文件夹拖到应用程序图标上时,操作系统的语义是:把这个文件夹路径作为参数传给 App。这时候用户的真实意图很可能是“我要在这个传进来的文件夹里新建文件”,而不一定是 Finder 当前窗口。为了兼顾客两种输入方式,我最后把脚本开头抽象成了一个定位函数:
bash复制resolve_dir() {
if [ -d "$1" ]; then
# 传入的是文件夹,直接把它当作目标目录
echo "$1"
elif [ -f "$1" ]; then
# 传入的是文件,取文件所在目录
dirname "$1"
else
# 没有可用的传入参数,问 Finder
osascript -e 'tell application "Finder" to get POSIX path of (insertion location as alias)'
fi
}
简单说:如果能拿到“文件夹参数”,优先用这个参数;如果拿到的是“文件参数”,就用文件所在目录;如果什么都没拿到,就找 Finder 要当前目录。这样同一个脚本既能给“快速操作”用,也能给“应用程序”用。
还要补充一个很多人忽略的小问题:insertion location 返回的路径结尾有斜杠,你在拼路径时如果直接写 $dir/文件名,可能会出现双斜杠,比如 /Users/me/Desktop//未命名.md。macOS 对双斜杠一般能正常处理,但为了输出干净、避免个别命令行为怪异,建议统一写成:
bash复制dir="${dir%/}"
意思是把末尾的斜杠删掉再拼路径。
3. 第一个成品:右键快速操作,一键在当前文件夹生成 Markdown
先做一个最基础的版本,目标是:在 Finder 里选中任意文件或文件夹,右键执行“在这里新建 Markdown”,马上生成一个 未命名.md,并且刚创建完,系统会在 Finder 里高亮这个文件,方便你立刻改名字。
打开 Automator,新建文稿,选“快速操作”。顶部两行关键配置:
- 工作流程收到当前:
文件或文件夹 - 位于:
Finder
在左侧搜索“运行 Shell Shell 脚本”并拖到右侧工作区,然后把 Shell 改成 /bin/bash,传递输入选“作为参数”。这一步不要选“输入到 stdin”,不然多个文件会被拼成一大段文本,不如直接用参数数组方便。
脚本内容:
bash复制#!/bin/bash
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
target="$1"
# 定位目标目录
if [ -d "$target" ]; then
dir_path="$target"
elif [ -f "$target" ]; then
dir_path="$(dirname "$target")"
else
dir_path="$(osascript -e 'tell application "Finder" to get POSIX path of (insertion location as alias)')"
fi
if [ -z "$dir_path" ]; then
echo "无法获取 Finder 当前目录" >&2
exit 1
fi
dir_path="${dir_path%/}"
# 默认文件名,冲突时自动加数字
filename="未命名.md"
base="${filename%.md}"
i=1
while [ -e "$dir_path/$filename" ]; do
filename="${base} ${i}.md"
i=$((i + 1))
done
# 生成文件
cat > "$dir_path/$filename" <<'EOF'
# 新文档
EOF
# 在 Finder 中高亮新文件
open -R "$dir_path/$filename"
保存时给它起一个直白的名字,例如“在这里新建 Markdown”。保存完成后,不用重启系统,在 Finder 中选中任意一个文件或文件夹,右键,打开“快速操作”子菜单,就能看到刚才这项操作。
运行一次之后,系统大概率会弹出一个权限框,问是否允许 Automator 控制 Finder。这是因为脚本里用到了 AppleScript 去访问 Finder。第一次点允许就好,之后不会再频繁打扰。
脚本里那个 while [ -e ... ] 循环是防止重名的。如果你连续执行两次,第一次生成 未命名.md,第二次会自动生成 未命名 1.md,第三次是 未命名 2.md,不会再出现系统弹窗问“这个文件已存在”,也没有覆盖风险。
我还特别喜欢最后那句 open -R。Mac 用户都知道,把一个文件在 Finder 里“显示原文件”可以用 open -R。新建文件后高亮它,意味着你手指不用离开键盘就能立刻输入新文件名,整个流程从“右键 -> 执行 -> 改名”一气呵成。
4. 升级成模板引擎:日期占位、固定文件扩展名、批量铺 README
天天创建空文件不够爽,真正好用还得带模板。比如我在写新博客时,希望新 Markdown 文件自带 YAML front matter 和日期;建临时 Python 脚本时,希望开头就有 #!/usr/bin/env python3 和编码注释;给一组新项目文件夹铺文件时,希望每个目录里都自动生成一个 README.md。
不要每次都去网上复制粘贴模板,把它们集中放在一个固定目录里就行。我习惯放在 ~/.config/finder-create/ 下,用文本编辑器维护。
先做一个简单模板:
markdown复制---
title:
tags: []
created: %DATE%
---
#
然后在“运行 Shell 脚本”里把上一章的创建命令改成模板复制加占位符替换:
bash复制#!/bin/bash
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
ext="md"
template_dir="$HOME/.config/finder-create"
template="$template_dir/template.${ext}"
# 模板不存在时给一个默认值
if [ ! -f "$template" ]; then
mkdir -p "$template_dir"
cat > "$template" <<'EOF'
---
title:
tags: []
created: %DATE%
---
EOF
fi
# 定位目录,逻辑和上一章完全一样
target="$1"
if [ -d "$target" ]; then
dir_path="$target"
elif [ -f "$target" ]; then
dir_path="$(dirname "$target")"
else
dir_path="$(osascript -e 'tell application "Finder" to get POSIX path of (insertion location as alias)')"
fi
[ -z "$dir_path" ] && { echo "定位目录失败" >&2; exit 1; }
dir_path="${dir_path%/}"
filename="未命名.${ext}"
base="${filename%.${ext}}"
i=1
while [ -e "$dir_path/$filename" ]; do
filename="${base} ${i}.${ext}"
i=$((i + 1))
done
# 把模板里的 %DATE% 替换成当前时间
sed "s/%DATE%/$(date '+%Y-%m-%d %H:%M:%S')/" "$template" > "$dir_path/$filename"
open -R "$dir_path/$filename"
如果你改了模板文件,脚本会自动读取最新内容,下次创建时生效。这个方案有个很实用的点:模板目录里可以有多套模板,比如 template.md、template.py、template.txt。想建哪种文件,就把脚本顶部的 ext 变量改成什么,然后多保存几个快速操作即可。
我实际就保存了三个操作:“在这里新建 Markdown”“在这里新建 Python 文件”“在这里新建 TXT”。其实它们的脚本 95% 相同,只是 ext 不同,复制三次并不丢人。
再聊一个稍微进阶的批量用法。有时候我拿到一堆项目目录,想给每个目录灌一个 README.md,里面只写项目名和日期。如果一个个进目录右键,效率太低了。脚本改成循环处理多个传入参数就能解决:
bash复制for target in "$@"; do
if [ -d "$target" ]; then
dir_path="$target"
elif [ -f "$target" ]; then
dir_path="$(dirname "$target")"
else
continue
fi
dir_path="${dir_path%/}"
filename="README.md"
if [ -e "$dir_path/$filename" ]; then
echo "跳过 $dir_path,README.md 已存在"
continue
fi
cat > "$dir_path/$filename" <<EOF
# $(basename "$dir_path")
> 自动生成于 $(date '+%Y-%m-%d %H:%M')
EOF
done
osascript -e 'tell application "Finder" to activate'
注意这个批量版本里我用了双引号 EOF,而不是 'EOF'。因为我想让 $(basename ...) 和 $(date ...) 在脚本运行时被展开。上一章的普通模板用的是单引号 EOF,目的是让模板内容保持原样,不要把 Markdown 里的特殊符号误判成变量。这两者的区分,值得你实际操作时留意。
因为输出的内容不依赖于“当前目录”,所以我在循环里只在必要的时候才用 insertion location。在“批量铺 README”的场景中,每个传入的文件夹本身就是目标,不需要再多问 Finder 一句。
这里也提醒一句:macOS 自带的 /bin/bash 是 3.2 老版本,很多新语法不认。比如 ${var,,} 这种把字符串转小写的写法,会直接报错。如果你是大括号重度依赖用户,建议把 Automator 里的 Shell 改成 /bin/zsh,再把我给的脚本复制进去,逻辑基本兼容。macOS 默认的 /bin/zsh 版本新得多,脚本兼容性更好。
5. 不选文件也能建:把 Automator 应用拖进 Finder 工具栏
快速操作虽然好用,但有一条硬限制:它总要你先选中文件或文件夹,否则右键菜单里看不到入口。可是很多场景里,我就是想站在一个空目录里新建一个文件,当前目录里根本没有可选项。这时候最适合的不是“快速操作”,而是一个工具按钮:能一直待在 Finder 工具栏上,点击就创建。
Automator 完全可以做出来,而且不需要写 Swift。
新建文稿时选“应用程序”,然后在左边拖一个“运行 Shell 脚本”进来。这次因为没有文件输入,脚本开头不再依赖 $1,直接让 Finder 说当前目录:
bash复制#!/bin/bash
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
dir_path="$(osascript -e 'tell application "Finder" to get POSIX path of (insertion location as alias)')"
if [ -z "$dir_path" ]; then
echo "无法获取 Finder 当前目录" >&2
exit 1
fi
dir_path="${dir_path%/}"
filename="未命名.md"
base="${filename%.md}"
i=1
while [ -e "$dir_path/$filename" ]; do
filename="${base} ${i}.md"
i=$((i + 1))
done
cat > "$dir_path/$filename" <<'EOF'
# 新文档
EOF
open -R "$dir_path/$filename"
把它保存到任何你喜欢的位置,名字就叫做“新建文件.app”。
接下来的操作是重点:这个 App 不需要双击启动。你在 Finder 窗口里按住 Command 键,然后用鼠标把这个 新建文件.app 图标拖到窗口顶部的工具栏区域。看到工具栏出现绿色 + 号时松手,图标就直接固定在工具栏上了。
之后每当你站在某个目录里想新建文件,点一下这个按钮,文件立刻出现,并且自动打开 Finder 的高亮状态等你改名。这个体验,说句公道话,比不少第三方右键菜单工具都顺。
使用过程中还有两个小细节值得说一下。
第一,如果你连文件都不想手动输入名字,可以让 App 每次创建后直接在当前目录把这个文件打开。把脚本最后一行改成:
bash复制open "$dir_path/$filename"
它会按文件扩展名的默认 App 打开。如果你想强制用某个编辑器,可以写:
bash复制open -a "Visual Studio Code" "$dir_path/$filename"
我个人没有把“打开编辑器”做成默认。因为新建临时文件时,我的习惯是先想好文件名,再决定要不要编辑。如果文件一创建就触发编辑器,反而会打断心流。
第二,工具栏上的 App 每次被点击时,Dock 栏会出现一个图标闪一下。如果不喜欢这个效果,可以修改 App 的 Info.plist,让它不显示在 Dock 上。终端里执行:
bash复制/usr/libexec/PlistBuddy -c "Add :LSUIElement bool true" "$HOME/Applications/新建文件.app/Contents/Info.plist" 2>/dev/null
路径请改成你的实际保存位置。这个操作会改动 App 签名,偶尔会导致部分 Mac 提示“已损坏”。如果你怕麻烦,不修改也完全能用,顶多是 Dock 图标闪一下,不影响功能。
6. 跑不起来怎么办:权限授权、快捷键失效、图标过时
如果你照着上面做完,遇到了问题,不要急,最常用的修复方法基本都集中在这几个地方。
第一类问题:第一次运行后就再也没反应,或者脚本报“not authorized”。这是 macOS 的自动化权限在起作用。去“系统设置”里找到“隐私与安全性”,点“自动化”,检查列表里有没有 Automator。如果 Automator 控制 Finder 的开关是关的,打开它。有时候列表里压根没有 Automator,那是因为你在弹窗时点了“不允许”,macOS 就不再把这项显示出来。这个情况比较隐蔽,比较粗暴的解决办法是把 Automator 相关条目从 TCC 数据库里清掉,或者换一个账号测试,普通用户建议先试着重装一下工作流/重置 Automator 历史记录。实在不行就删除这个快速操作,重新做一个名字不同的,让系统重新触发权限弹窗。
第二类问题:右键菜单里找不到新建操作。保存完快速操作后,Finder 可能没有立刻刷新。最简单的方式是运行:
bash复制killall Finder
Finder 重启后菜单一般就会刷新出来。如果你的 macOS 版本较老,还可以去“系统设置 -> 键盘 -> 键盘快捷键 -> 服务”里检查这项操作是否被勾选,有些版本默认不会把新服务显示在右键菜单里,但在服务菜单里能看到。
第三类问题:想给快速操作绑定快捷键,但一直不生效。到“系统设置 -> 键盘 -> 键盘快捷键”,往下找“服务”,在“文件和文件夹”分类里能看到你保存的快速操作名称。点它右侧的“添加快捷键”,按下组合键。注意不要和系统已有的快捷键冲突,比如 Shift + Command + N,Finder 里默认是“新建文件夹”,你再拿去绑定快速操作就会打架。你可以用 Control + Option + Command + N 这类系统很少占用的组合。
还有一个更隐蔽的坑:快速操作在绑定快捷键后,如果你当时在 Finder 里没有选中任何文件,部分 macOS 版本下快捷键仍然不会触发。因为“服务”功能认为它没有可作用的目标。如果你经常对着空白目录按快捷键,那就用回工具栏 App 方案吧,这是我最终放弃“只依赖一个快捷键”的原因。
第四类问题:图标不好看,或者想区分“新建 Markdown”和“新建 Python”。Automator 在 Automator 窗口的左上角会显示一个图标,你可以直接把 .icns 文件拖进去,或者用一段生成图标的代码。我偷懒的办法是准备好几个 PNG 文件,然后用系统自带的“预览”转成 .icns,再在 Automator 窗口里替换。效果上,右键菜单中的服务本身不会显示定制图标,但工具栏 App 会。
我现在每天的使用节奏是这样的:大部分时间用 Finder 工具栏上的“新建文件 App”,点一下建一个临时 Markdown;写代码时用快捷键 Control + Option + Command + P 创建 Python 文件,这个快捷键绑在一个独立的快速操作上。模板目录放在 ~/.config/finder-create/,哪天想给模板加个 description 字段,直接用文本编辑器改掉,
