Вопрос или проблема
Я пытаюсь настроить скрипт, который будет получать изменения с github, где в скрипте есть команда, которая не запускается в Mac OS X.
Я стремлюсь использовать sed
и другие инструменты для замены команды в этом скрипте.
Вот команды:
Исходная команда (которая будет заменена в скрипте):
DIR=$(dirname "$(readlink -f $0)")
Новая команда (которую я хочу заменить на):
DIR="$(cd "$(dirname "$0")" && pwd -P)"
Вот что я пытался сделать до сих пор:
StartStopScript="/path/to/script.sh"
DIRnew=""$(cd "$(dirname "$0")" && pwd -P)""
DIRold=""$(dirname "$(readlink -f $0)")""
echo "$StartStopScript" | sed -e 's/"$DIRold"https://unix.stackexchange.com/"$DIRnew"/g'
Это не работает, и команды, похоже, выполняются вместо того, чтобы интерпретироваться как строка.
Похоже, дело сводится к кавычкам в sed
.
Благодарен за любую помощь, которую я могу получить с этим.
OrigScript="/path/to/script.sh"
echo $OrigScript
/path/to/script.sh
#заметьте: без кавычек
OrigScript=""/path/to/script.sh""
echo $OrigScript
"/path/to/script.sh"
#заметьте: с кавычками, но не подходит для имен файлов, лучше использовать "$filename" в аргументе команды
DIRnew='"$(cd "$(dirname "$0")" \&\& pwd -P)"'
echo $DIRnew
"$(cd "$(dirname "$0")" \&\& pwd -P)"
#заметьте: с кавычками, экранирование & необходимо для подавления интерпретации sed
DIRold='"$(dirname "$(readlink -f $0)")"'
echo $DIRold
"$(dirname "$(readlink -f $0)")"
#заметьте: в вашем вопросе исходный DIR=.. не имел двойных кавычек,
#я предполагаю, это опечатка
sed -e "s/$DIRold/$DIRnew/g" "$OrigScript"
#заметьте: $OrigScript НЕ должен иметь двойные кавычки!
#заметьте: я предполагаю, что $OrigScript == $StartStopScript
#тест:
echo $DIRold | sed "s/$DIRold/$DIRnew/"
"$(cd "$(dirname "$0")" && pwd -P)"
#результат включает двойные кавычки!
1) для объявления переменной с (двойными) кавычками необходимо экранировать кавычки, чтобы они были в строке; лучше использовать одинарные кавычки, чтобы убедиться, что строка внутри — это именно строка и никакие переменные не интерпретируются. Это также упрощает использование &
и $()
, так как они не интерпретируются оболочкой.
2) для echo
с (двойными) кавычками необходимо их экранировать.
3) чтобы разрешить sed
интерпретировать переменную оболочки, вы ДОЛЖНЫ использовать двойные кавычки вокруг команды sed
(с одинарными кавычками команда sed 's/$a/$b/'
попытается заменить фактическую строку ‘$a’ на строку ‘$b’, также обратите внимание на специальное значение $
в sed
), двойные кавычки вокруг переменной внутри команды sed
не нужны, поскольку sed
предназначен для обработки строк с любым символом (с ограничениями по специальным управляющим символам sed
).
4) echo "$StartStopScript" | sed -e 's/"$DIRold"https://unix.stackexchange.com/"$DIRnew"/g'
выведет переменную $StartStopScript
(которая, я предполагаю, просто является именем файла скрипта) и попытается заменить переменные в этой строке (т.е. имя файла). Чтобы применить sed
к файлу, используйте sed 's/a/b/g' file
(вывод записывается в stout
), для перезаписи файла используйте -i
(используйте с осторожностью, т.е. сначала проверьте правильность замен).
5) &
имеет специальное значение в sed
, оно повторно печатает начальный (совпадающий) шаблон:
echo ABC | sed 's/A/&12/'
A12BC
Вам нужно будет экранировать его в шаблоне замены, чтобы подавить интерпретацию:
echo ABC | sed 's/A/\&12/'
&12BC
Таким образом, переменная $DIRnew
должна содержать экранированные обратные слэши в своей строке.
6) Кроме того, я бы предложил использовать цикл if
, чтобы определить ОС и адаптировать команды соответственно. Таким образом, вам нужен только один скрипт для обеих ОС. Например:
if [ OS = Mac ] ; then
dir=MacDir
else
dir=LinuxDir
fi
Ответ или решение
Вопрос о замене команд в Bash-скрипте, особенно когда дело касается совместимости с различными операционными системами, является актуальной темой для многих разработчиков. Давайте детально разберем процесс замены команды в вашем сценарии на примере использования sed
, а также предложим дополнительные рекомендации для улучшения переносимости ваших скриптов.
Проблема
Вы столкнулись с необходимостью заменить команду в Bash-скрипте следующим образом:
-
Оригинальная команда:
DIR=$(dirname "$(readlink -f $0)")
-
Новая команда:
DIR="$(cd "$(dirname "$0")" && pwd -P)"
При этом вы заметили, что при использовании команды sed
для замены происходит интерпретация переменных, что приводит к неправильным результатам.
Решение
Для корректной замены с помощью sed
, вам нужно учесть следующие моменты:
-
Защита кавычек и специального синтаксиса: Используйте одиночные кавычки вокруг команды
sed
, чтобы избежать интерпретации переменных. Но при этом вам необходимо корректно экранировать некоторые символы (например, символ&
). -
Построение правильной команды
sed
: Вместо передачи вывода черезecho
, лучше всего передать файл непосредственно вsed
или перенаправить вывод в файл.
Вот пример исправленного кода:
OrigScript="/path/to/script.sh"
# Определим новые и старые команды
DIRnew='$(cd "$(dirname "$0")" && pwd -P)'
DIRold='$(dirname "$(readlink -f $0)")'
# Заменяем старую команду на новую
sed -i.bak "s|$DIRold|$DIRnew|g" "$OrigScript"
Объяснение кода:
OrigScript
— это путь к вашему исходному скрипту, где будет происходить замена.DIRnew
иDIRold
содержат старую и новую команды, с использованием одинарных кавычек для защиты от интерпретации переменных.- Опция
-i.bak
создаёт резервную копию вашего скрипта с расширением.bak
, что позволяет избежать потери данных в случае ошибки.
Рекомендации по переносимости
Для повышения совместимости вашего скрипта с различными операционными системами, рассмотрите возможность использования условной логики:
if [[ "$OSTYPE" == "darwin"* ]]; then
# Команды для Mac
DIR="$(cd "$(dirname "$0")" && pwd -P)"
else
# Команды для Linux и других систем
DIR=$(dirname "$(readlink -f $0)")
fi
Заключение
Замена команды в bash-скрипте с использованием sed
требует внимания к деталям. Исходя из практических примеров, всегда учитывайте возможность экранирования специальных символов и выбирайте подходящий способ передачи аргументов. Не забывайте про проверку на совместимость с разными операционными системами, чтобы ваши скрипты работали без проблем на всех платформах.