Чтобы передать имя файла с пробелами в скрипт оболочки в macOS, заключите путь в кавычки как один аргумент при запуске скрипта, а затем используйте "$1" внутри скрипта. Например, ./process-file.sh "/Users/sam/Documents/Quarterly Report.pdf" передает одно имя файла; без кавычек оболочка разделит его на несколько аргументов. Этот метод также работает с путями, содержащими другие специальные символы оболочки, если они правильно заключены в кавычки.
Запуск скрипта с путем в качестве одного аргумента
В Терминале заключите полное имя файла или путь в двойные кавычки, включая содержащие его каталоги, и укажите имя скрипта отдельно:
./process-file.sh "/Users/sam/Documents/Quarterly Report.pdf"
Обратная косая черта перед каждым пробелом также подходит для простого ввода пути вручную: ./process-file.sh /Users/sam/Documents/Quarterly\ Report.pdf. Заключение всего пути в кавычки более читабельно и менее подвержено ошибкам, особенно если путь содержит несколько пробелов. Кавычки являются синтаксисом оболочки; они объединяют путь в один аргумент и не становятся частью имени файла, получаемого скриптом. Оболочка выполняет разбиение на слова после подстановок (expansions), поэтому путь без кавычек может быть разделен по пробелам. Bash Reference Manual: Quoting
Если файл находится в текущем каталоге, относительный путь также сработает:
./process-file.sh "Quarterly Report.pdf"
Путь должен указывать на существующий файл относительно каталога, из которого вы запускаете команду. Если сам скрипт не является исполняемым, вызовите его с помощью оболочки, например: 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" — при передаче пути в команду или при использовании его в условиях проверки. В противном случае оболочка может разбить значение, содержащее пробелы, на отдельные слова и воспринять символы подстановки как маски имен файлов. В руководстве по Bash описаны позиционные параметры, а также этапы разбиения на слова и подстановки имен файлов в оболочке. Bash Reference Manual: Positional Parameters and Shell Expansions
Для обработки нескольких имен файлов заключайте каждый путь в кавычки при вызове скрипта и перебирайте аргументы через "$@", чтобы каждый аргумент оставался отдельным:
for file in "$@"; do
printf 'Received: %s\n' "$file"
done
Не используйте для этих целей $* или не заключенный в кавычки $@: они могут объединить или непреднамеренно разбить значения аргументов. Если скрипт ожидает ровно один файл, оставьте проверку на один аргумент и передавайте один путь в кавычках.
Когда команду оболочки запускает AppleScript
Команда AppleScript do shell script принимает текстовую строку, содержащую код оболочки. Если объединить путь непосредственно в эту команду, путь вида /Users/sam/Quarterly Reports/report.pdf будет интерпретирован как несколько отдельных слов оболочки. Apple рекомендует использовать quoted form как способ формирования текста, безопасного для интерпретации оболочкой, включая строки с пробелами и встроенными символами кавычек. Apple: Calling Command-Line Tools
Если путь известен заранее, заключите его в кавычки с помощью 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
В справочнике AppleScript от Apple этот шаблон демонстрируется для выбранной папки, а также отмечается, что quoted form корректно обрабатывает и встроенные одинарные кавычки. AppleScript Language Guide: Commands Reference
Устранение распространенных ошибок
Если скрипт сообщает, что он получил несколько аргументов, проверьте команду запуска: полный путь должен находиться внутри одной пары кавычек. Если скрипт получает путь с буквальными символами кавычек, проверьте, не были ли эти символы включены в саму строку имени файла; кавычки оболочки должны группировать аргумент, а не становиться частью его значения.
Если скрипт получает путь правильно, но последующая команда внутри него завершается ошибкой, проверьте аргументы и этой команды. Заключение в кавычки в команде запуска не защищает автоматически переменную без кавычек внутри скрипта: используйте конструкции вида some-command "$file". В AppleScript не добавляйте кавычки вокруг пути вручную; объединяйте quoted form of пути с командой оболочки. Это относится только к синтаксическому разбору оболочки. Это не делает несуществующий путь действительным, не предоставляет права доступа к файлу и не гарантирует, что вызываемая программа сможет обработать данный файл.
Источники
Bash Reference Manual: Quoting — GNU Project
Bash Reference Manual — GNU Project
Mac Automation Scripting Guide: Calling Command-Line Tools — Apple
Commands Reference — Apple