Вопрос или проблема
У меня есть скрипт оболочки bash change_filename.sh
, содержащий строку кода:
mv "dir\ 1/file1.txt" "dir\ 1/file2.txt"
который не меняет имя file1.txt
на file2.txt
как ожидалось, а выдает сообщение об ошибке:
mv: переименование dir\ 1/file1.txt в dir\ 1/file2.txt: Нет такого файла или каталога
Он работает, когда я ввожу ту же строку в терминале, но не в скрипте. Почему скрипт не работает?
первая возможность
кредит @glenn jackman
Экранирующая последовательность \
не определена в кавычках оболочкой Bash, поэтому она расширяется в \
(обратная косая черта сохраняется). Чтобы это увидеть:
echo "foo\ bar"
->foo\ bar
echo foo\ bar
->foo bar
Возможно, что какая-то странная особенность терминала MacOS приводит к различиям в поведении.
вторая возможность
При использовании скрипта необходимо учитывать текущую рабочую директорию. Пути в Bash-скриптах разрешаются относительно CWD (текущей рабочей директории) оболочки (процесса), который вызвал скрипт.
Например, скажем, у нас есть следующая иерархия файлов, и script.sh
содержит cat bar/qux.txt
.
foo
├── bar
│ └── qux.txt
└── script.sh
Тогда
- Вызов
script.sh
из директорииfoo
сработает (содержимоеqux.txt
будет выведено) - Вызов
script.sh
из любого другого места не сработает
Чтобы это исправить, вы можете использовать хитрое выражение Bash, чтобы определить путь к скрипту и искать bar/qux.txt
относительно него, или вы можете указать путь к qux.txt
с помощью абсолютного пути (например, /home/me/...
)
Ответ или решение
Скрипты на Bash могут иногда выдавать неожиданные ошибки, особенно когда дело доходит до путей к файлам и их синтаксиса. Давайте рассмотрим, почему ваш скрипт change_filename.sh
не работает в терминале macOS, даже несмотря на то, что команда работает, когда вы вводите её напрямую в терминале.
1. Экранирование пробелов
Первая потенциальная проблема заключается в использовании обратного слэша (\
) для экранирования пробелов в строках команды. Когда вы пишете mv "dir\ 1/file1.txt" "dir\ 1/file2.txt"
в скрипте, Bash не распознаёт экранирование в кавычках так, как вы ожидаете. На самом деле, ваша строка сохраняет обратный слэш и интерпретируется как:
"dir\ 1/file1.txt" вместо "dir 1/file1.txt"
Это приводит к тому, что Bash не может найти файл с указанным именем, и вы получаете ошибку No such file or directory
. Чтобы устранить эту проблему, попробуйте использовать одинарные или двойные кавычки без экранирования, так что имена папок будут выглядеть следующим образом:
mv "dir 1/file1.txt" "dir 1/file2.txt"
Или так:
mv dir\ 1/file1.txt dir\ 1/file2.txt
2. Текущая рабочая директория (CWD)
Вторая возможная причина проблемы связана с текущей рабочей директорией, откуда вы вызываете скрипт. Когда скрипт выполняется, он ищет файлы с указанными путями относительно своей текущей рабочей директории. Если вы находитесь не в той же директории, где находятся папка dir 1
и файл file1.txt
, Bash не сможет их найти, что также приведёт к ошибке No such file or directory
.
Для решения этой проблемы рекомендуется использовать абсолютные или относительные пути к файлам. Например:
mv /полный/путь/к/dir\ 1/file1.txt /полный/путь/к/dir\ 1/file2.txt
Или использовать метод, который позволяет получить путь до директории скрипта относительно его местоположения:
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
mv "$SCRIPT_DIR/dir 1/file1.txt" "$SCRIPT_DIR/dir 1/file2.txt"
Подведение итогов
Для решения проблемы с вашим скриптом, рассмотрите возможность удалить экранирование пробелов в именах файлов и убедитесь, что текущая рабочая директория соответствует той, где находятся файлы, с которыми вы работаете. Проверив эти аспекты, вы сможете избежать ошибок выполнения и добиться корректного выполнения скрипта change_filename.sh
в терминале macOS.