要在 macOS 上将包含空格的文件名传递给 shell 脚本,请在运行脚本时将路径用引号括起来作为一个参数,然后在脚本内部使用 "$1"。例如,./process-file.sh "/Users/sam/Documents/Quarterly Report.pdf" 会传递一个文件名;若不加引号,shell 会将其拆分为多个参数。正确使用引号时,此方法同样适用于包含其他 shell 敏感字符的路径。
将路径作为单个参数运行脚本
在终端中,用双引号将完整的文件名或路径(包括其目录)括起来,并与脚本名称保持分开:
./process-file.sh "/Users/sam/Documents/Quarterly Report.pdf"
对于简单的手动输入路径,在每个空格前加反斜杠也同样有效:./process-file.sh /Users/sam/Documents/Quarterly\ Report.pdf。给整个路径加上引号更易读且更不易出错,尤其是当路径包含多个空格时。引号是 shell 语法;它们将路径组合为一个参数,且不属于脚本接收到的文件名的一部分。Shell 在扩展后会执行单词分割(word splitting),因此未加引号的路径可能会在空格处被拆分。Bash 参考手册:引用 (Quoting)
如果文件位于当前目录中,相对路径也可以使用:
./process-file.sh "Quarterly Report.pdf"
该路径必须从你运行命令的目录指向一个确实存在的文件。如果脚本本身不可执行,可以改用 shell 来调用它,例如 bash process-file.sh "/Users/sam/Documents/Quarterly Report.pdf"。这两种形式都会将路径作为参数传递;脚本需要该文件的读取权限,并且必须处理任何其他所需的权限。
在脚本内部安全地使用参数
将其保存为 process-file.sh:
#!/bin/bash
if [ "$#" -ne 1 ]; then
printf 'Usage: %s FILE\n' "$0" >&2
exit 2
fi
file=$1
if [ ! -f "$file" ]; then
printf 'Not a regular file: %s\n' "$file" >&2
exit 1
fi
printf 'Received one file: %s\n' "$file"
该脚本会检查它是否刚好接收到一个参数,检查该路径指向的是否为常规文件,并打印接收到的路径。$# 是参数的数量;$1 是第一个参数。在将路径传递给命令或在条件测试中使用时,请保持变量扩展带有引号——即 "$file"。否则,shell 可能会将包含空格的值拆分为单独的单词,并将通配符视为文件名匹配模式。Bash 手册中记录了位置参数以及 shell 的单词拆分和文件名扩展步骤。Bash 参考手册:位置参数与 Shell 扩展
要处理多个文件名,请在调用脚本时为每个路径都加上引号,并对 "$@" 进行循环遍历,以确保每个参数保持独立:
for file in "$@"; do
printf 'Received: %s\n' "$file"
done
请勿为此目的使用 $* 或未加引号的 $@:这些可能会合并或拆分参数值。如果脚本预期刚好只有一个文件,请保留单参数检查并传递一个带引号的路径。
当通过 AppleScript 启动 Shell 命令时
AppleScript 的 do shell script 命令接受包含 shell 代码的文本字符串。如果你直接将路径拼接到该命令中,诸如 /Users/sam/Quarterly Reports/report.pdf 这样的路径将被解释为多个 shell 词。Apple 文档指出,使用 quoted form 可以生成适合 shell 安全解释的文本,包括包含空格和内嵌引号字符的字符串。Apple:调用命令行工具
对于已知路径,在拼接之前先使用 quoted form of 对其进行引用处理:
set filePath to "/Users/sam/Quarterly Reports/report.pdf"
set safePath to quoted form of filePath
do shell script "/path/to/process-file.sh " & safePath
生成的命令会为脚本提供一个路径参数。如果路径来自文件选取器,请先将所选项目转换为 POSIX 路径,然后再进行引用处理:
set filePath to POSIX path of (choose file)
do shell script "/path/to/process-file.sh " & quoted form of filePath
Apple 的 AppleScript 参考文档中针对所选文件夹演示了这种模式,并指出 quoted form 也能处理内嵌的单引号。AppleScript 语言指南:命令参考
解决常见问题
如果脚本报告接收到了多个参数,请检查启动它的命令:完整路径应位于同一对引号内。如果它接收到的路径包含字面引号标记,请检查文件名字符串本身是否包含了这些引号;shell 引号的作用应该是将参数归为一组,而不是变成参数值的一部分。
如果脚本正确接收了路径,但后续的某个命令失败了,请同时检查该命令的参数。仅在启动命令中加引号并不会自动保护脚本内部未加引号的变量:请使用形如 some-command "$file" 的写法。对于 AppleScript,不要手动在路径周围添加引号;请将路径的 quoted form of 拼接到 shell 命令中。这仅解决 shell 解析问题。它不会使无效的路径凭空存在、不会授予文件访问权限,也不能保证被调用的程序一定会接受该文件。
参考来源
Bash 参考手册:引用 (Quoting) — GNU 项目
Bash 参考手册 — GNU 项目
Mac 自动化脚本指南:调用命令行工具 — Apple
命令参考 — Apple