在 Ubuntu 中,“双击脚本”至少跨越四层:脚本内容和解释器、Unix 执行权限、挂载选项,以及文件管理器或桌面的启动策略。当前 GNOME Files 仍可提供“运行、查看或每次询问”的可执行文本选项,但 Ubuntu 版本、桌面环境和文件管理器不同,菜单与默认行为也会不同。最可诊断的入口始终是终端;需要稳定 GUI 入口时,再为已经审查的本地脚本创建标准桌面启动器。
本文维护层于 2026 年重写。2014 年原文只有旧版 Nautilus 的首选项路径和两张截图,完整正文保存在文末惰性归档中,不作为当前界面保证。
Table of Contents
1. 先决定是否应该运行
Shell 脚本是程序,不是“只读文档”。双击前先确认来源、用途、预期输入输出、网络访问、写入路径和回退方式。下载、聊天附件、邮件或共享盘中的脚本,不应因为图标看起来正常就执行。
先做只读检查;路径只是占位符:
file -- script.sh
stat -- script.sh
sed -n '1,80p' -- script.sh
sed -n '1l' -- script.sh
sha256sum -- script.sh
阅读完整文件,而不只是前 80 行。哈希只能标识字节;必须与可信发布方通过独立渠道公布的值比较,才有来源意义。不要使用 curl ... | sh,也不要把未知脚本交给 sudo 试运行。
2. 解释器、shebang 与换行符
直接执行脚本时,第一行 shebang 决定解释器。按脚本实际语法选择,例如 Bash 脚本可写:
#!/usr/bin/env bash
set -u
printf 'script=%s\n' "$0"
printf 'working_directory=%s\n' "$PWD"
printf 'argument_count=%s\n' "$#"
#!/bin/sh 只适用于确实符合目标系统 sh 的脚本。/usr/bin/env bash 从启动环境的 PATH 找 Bash,便于不同安装位置,但也意味着 PATH 必须可信;固定受管主机可按部署规范使用绝对解释器路径。
bad interpreter 后出现 ^M 通常说明文件带 CRLF。先用 file 和 sed -n '1l' 证明,再在副本中用可信编辑器转换;不要在未检查完整内容前批量改写。调用 bash script.sh 会绕过 shebang,因此只能在确认它确实是 Bash 脚本时用于诊断,不能证明直接执行路径正确。
3. 只给所有者执行权限
把已审查脚本保存到本地、由自己控制且不被其他用户写入的位置,例如 $HOME/.local/bin/double-click-demo。然后只增加所有者执行位:
install -d -m 700 -- "$HOME/.local/bin"
chmod u+x -- "$HOME/.local/bin/double-click-demo"
ls -l -- "$HOME/.local/bin/double-click-demo"
"$HOME/.local/bin/double-click-demo"
printf 'exit_status=%s\n' "$?"
不要用 chmod 777,也不要仅为增加自己的执行位使用 sudo。脚本文件有 x 仍不够:父目录需要搜索权限,文件系统可能以 noexec 挂载,ACL 或安全策略也可能拒绝执行。FAT、NTFS、网络盘和压缩包中的权限语义可能不同;把脚本安装到本地原生文件系统比反复放宽权限更可控。
若只想在审查后测试一个尚未加执行位的 Bash 文件,可显式调用解释器:
bash --noprofile --norc -- "$HOME/.local/bin/double-click-demo"
这会跳过用户 Bash 启动文件,但不会隔离脚本的文件、网络或进程权限。它不是沙箱。
4. 终端执行是诊断基线
从终端运行能保留标准输出、错误输出和退出码。先切换到脚本预期的工作目录,或让脚本使用绝对路径;不要假定双击时的 PWD 与交互终端相同。
如果脚本会改文件,先提供 --dry-run 或只读模式,并把输出限定在新的测试目录。若没有预演、备份或明确回退,先不要运行。需要密码、管理员权限、磁盘分区、账户、网络规则或生产数据的脚本,不适合作为无提示双击入口。
5. GNOME Files 的直接双击选项
GNOME 的当前帮助仍描述可执行文本文件的三种策略:打开时运行、打开时查看、每次询问。文件还必须在“属性 → 权限”中允许作为程序执行。实际 Ubuntu 版本可能把选项放在 Files 菜单的“首选项 → 常规/行为”,也可能使用没有该选项的其他文件管理器。
若界面提供这些策略,优先选择“每次询问”,先查看再运行。直接运行的缺点是工作目录、环境变量和错误输出不明显,终端程序可能瞬间关闭。若选项不存在,不要修改隐藏设置或安装旧版文件管理器来复刻截图;使用终端或下一节的标准启动器。
6. 为已审查脚本创建应用启动器
需要可重复的 GUI 入口时,把脚本保留在不可被其他用户写入的固定路径,再用 Desktop Entry 规范创建 $HOME/.local/share/applications/lazying-shell-demo.desktop。下面三个 USERNAME 必须替换为真实本地用户名;Exec 不会展开 $HOME,也不会像 shell 一样解释管道、重定向或 &&。
[Desktop Entry]
Type=Application
Name=Shell Script Demo
Comment=Run the reviewed local demo in a terminal
TryExec=/home/USERNAME/.local/bin/double-click-demo
Exec=/home/USERNAME/.local/bin/double-click-demo
Path=/home/USERNAME
Terminal=true
Icon=utilities-terminal
TryExec 让桌面在目标不存在或不可执行时隐藏/忽略入口;Path 明确工作目录;Terminal=true 保留终端界面。若路径含空格,必须按 Desktop Entry 规范引用,而不是复制 shell 的任意转义。更简单的做法是使用无空格的受控路径。
用文本编辑器保存后,逐行检查 Exec、TryExec 和 Path。若已安装 desktop-file-utils,可只读验证并从应用菜单测试:
desktop-file-validate -- "$HOME/.local/share/applications/lazying-shell-demo.desktop"
gtk-launch lazying-shell-demo
desktop-file-validate 没有输出通常表示语法通过,不代表脚本安全。GNOME Shell 可能需要重新索引或重新登录后才显示新应用。把启动器复制到桌面时,桌面扩展还可能要求在 UI 中“允许启动”;只对自己刚审查的文件授权,不要用元数据命令批量信任下载内容。
7. GUI 与终端环境为什么不同
应用启动器通常不读取交互 shell 的 aliases、函数或全部启动文件,PATH、locale、代理、显示会话和密钥代理也可能不同。脚本应:
- 为外部工具使用已验证的绝对路径或设置最小可信
PATH; - 显式处理工作目录,不把启动位置当作脚本所在目录;
- 引用每个可能含空格或通配字符的参数;
- 把预期错误写到终端或受控日志,并返回非零状态;
- 不把密钥写进脚本、启动器、命令行参数或公开日志。
不要在 Exec 中拼接未信任文本,也不要为了获得 shell 语法而使用 sh -c 包裹用户输入。若必须传文件参数,应阅读 Desktop Entry 的字段代码规则,并在脚本中验证数量、类型、所有权和允许目录。
8. 故障证据矩阵
| 症状 | 先查什么 | 不应做什么 |
|---|---|---|
| 双击只打开编辑器 | 文件管理器策略、执行位、当前桌面版本 | 不要假定 2014 截图仍对应当前菜单 |
Permission denied |
文件/父目录权限、ACL、noexec、文件系统类型 |
不要 chmod 777 或用 root 绕过 |
bad interpreter |
shebang 路径、CRLF、解释器是否安装 | 不要随意改成 Bash 掩盖语言差异 |
| 终端可用、GUI 失败 | PWD、PATH、locale、会话总线、显示环境 |
不要把交互配置全量复制进启动器 |
| 窗口瞬间关闭 | Terminal=true、终端直接运行、退出码与 stderr |
不要加入无限 sleep 掩盖错误 |
| 应用菜单无入口 | Desktop Entry 语法、文件名/应用 ID、会话索引 | 不要批量信任所有 .desktop 文件 |
| 外置盘可读但不能执行 | 挂载选项、权限模型、组织策略 | 不要重新挂载为可执行而忽略边界 |
只读诊断可从以下命令开始;输出可能含用户名和路径,公开前脱敏:
namei -l -- "$HOME/.local/bin/double-click-demo"
findmnt -T -- "$HOME/.local/bin/double-click-demo"
head -n 1 -- "$HOME/.local/bin/double-click-demo"
journalctl --user -b --since "10 min ago" --no-pager
某些精简系统没有 namei、findmnt 或用户日志;命令不存在也是环境证据,不要安装随机包只为让清单全绿。
9. 可逆停用与回退
先停用启动器,再撤销脚本执行位,不需要删除文件:
ScriptPath="$HOME/.local/bin/double-click-demo"
LauncherPath="$HOME/.local/share/applications/lazying-shell-demo.desktop"
test ! -e "$LauncherPath.disabled" || exit 1
mv -- "$LauncherPath" "$LauncherPath.disabled"
chmod u-x -- "$ScriptPath"
重新登录或刷新应用菜单后确认入口消失。若脚本曾经修改数据、账户或系统配置,仅撤销执行位不会回滚那些影响;必须使用脚本事先定义并测试的应用级恢复方案。
10. 停止条件
- 无法说明脚本来源、完整内容、解释器或预期副作用。
- 脚本要求
sudo、密码、令牌、关闭安全控制或修改生产数据,却没有审批和回退。 - 只能通过全局放宽权限、启用可执行外置盘或批量信任启动器才能运行。
- 终端运行报错,GUI 却隐藏错误;先修复终端路径。
- 文件由其他用户写入、来自同步/共享位置,或运行期间可能被替换。
- 桌面、文件管理器或企业策略与本文不同,且没有当前官方文档支持该做法。
这些情况应交给脚本维护者或系统管理员。便捷入口不应扩大脚本本身的权限或信任边界。
11. 官方资料
- GNOME:文件管理器行为首选项
- GNOME:设置文件权限
- GNU Bash:Shell Scripts
- freedesktop.org:Desktop Entry Specification
- freedesktop.org:XDG Base Directory Specification
- POSIX.1-2024:chmod
资料核验于 2026-09-01。Ubuntu、GNOME Files、桌面扩展与组织策略会变化;执行前以已安装版本的帮助和当前官方文档为准。
12. 2014 年原文档案(仅供溯源)
以下围栏逐字保留 source_export 的完整可见正文;没有尾随空白规范化、链接删除或私密值遮盖。旧版 Nautilus 菜单和截图仅作为惰性历史证据,不是当前界面保证。
~~~~markdown
打开一个文件夹,单击左上角的Home Folder(主目录)->单击Preferences(首选项)
按照下图所示设置:
