Замените команду в Bash-скрипте из другого скрипта.

Вопрос или проблема

Я пытаюсь настроить скрипт, который будет получать изменения с 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, вам нужно учесть следующие моменты:

  1. Защита кавычек и специального синтаксиса: Используйте одиночные кавычки вокруг команды sed, чтобы избежать интерпретации переменных. Но при этом вам необходимо корректно экранировать некоторые символы (например, символ &).

  2. Построение правильной команды 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 требует внимания к деталям. Исходя из практических примеров, всегда учитывайте возможность экранирования специальных символов и выбирайте подходящий способ передачи аргументов. Не забывайте про проверку на совместимость с разными операционными системами, чтобы ваши скрипты работали без проблем на всех платформах.

Оцените материал
Добавить комментарий

Капча загружается...