Цель этой статьи - продемонстрировать подход к синхронизации сред оболочки путем написания сценария сценария оболочки.

Цель состоит в том, чтобы поддерживать чистоту домашнего каталога нашего пользователя, открывая только стандартные файлы среды Bash и обеспечивая быстрый доступ к исходному коду из файлов .sources. Результат будет таким:

/.
/.. 
/.bash_logout -> ~/.dotfiles/src/bash_logout
/.bash_profile -> ~/.dotfiles/src/bash_profile
/.bashrc -> ~/.dotfiles/src/bashrc
/.profile -> ~/.dotfiles/src/profile
/.dotfiles
  /bash_script
  /src
   /scripts
    /custom aliases
    /custom functions, etc
    ....  
/.sources -> ~/.dotfiles/bash_<unix-timestamp>

Мы рассмотрим сценарий, который я использую для синхронизации моей среды Bash между моим домашним компьютером с Ubuntu, удаленной песочницей Linux и моим ноутбуком Mac для работы.

Этот скрипт должен удовлетворять некоторым основным требованиям:

  • Может использовать MacOs и Ubuntu (терминал iTerm / Gnome)
  • Может предоставить самоорганизующуюся структуру для организации моих точечных файлов
  • Может самостоятельно документировать себя и обеспечивает локальный контроль версий
  • Можно быстро модифицировать среду Linux

Ссылки на ресурсы и материалы будут перечислены в порядке цитирования внизу статьи. Давайте начнем!

Самоорганизующаяся структура каталогов

Перейдите в свой домашний каталог и создайте новый каталог вместе с новым файлом: «bash_script». Вы можете включить расширение .sh или .bash, но я предпочитаю устанавливать shebang # внутри сценария. (См. справку по StackOverflow)

[local@~] $ mkdir -p .dotfiles && cd .dotfiles 
[[email protected]] $ touch bash-script && ls -1
/.dotfiles 
  /bash-script

Откройте файл в любом редакторе кода и добавьте следующие строки кода. Это позволяет нам захватить путь к каталогу относительно корня пользователя из любого каталога, в котором запускается скрипт. Это позволяет нам динамически создавать методы и функции там, где требуется путь.

#!/usr/bin/env bash
DIR=”$(cd “$( dirname “${BASH_SOURCE[0]}”)” >/dev/null 2>&1 && pwd)”
cd $DIR

Предоставьте себе локальный доступ для выполнения сценария:

[[email protected]] $ chmod u+w bash_script && ls -l bash_script
-rwxr-xr-x  1 jon  staff  135 Dec  4 21:41 bash_script

Если вы еще этого не сделали, создайте репозиторий Git и инициализируйте наш каталог. Вы также можете получить имя репозитория, добавив в сценарий следующую строку.

REPO="`git rev-parse --show-toplevel`"

Создайте следующие каталоги:

[[email protected]] $ mkdir -p src && mkdir -p src/scripts

Скопируйте / переместите любые существующие файлы bash как обычные файлы без расширений в наш репозиторий, чтобы они соответствовали следующему. Обязательно сделайте резервную копию своих файлов на всякий случай.

[[email protected]] $ ls -1 src
/.
/..
/bash_logout 
/bash_profile
/bashrc
/profile
/scripts 
  /custom_file(s)
...

Создание простой локальной истории контроля версий

Наличие локального контроля версий полезно для конфигураций оболочки для песочницы.

Наш скрипт сгенерирует файл, который будет служить единым источником достоверных данных для пользовательских файлов в нашей среде Bash. Для этого мы создадим символическую ссылку на ~ / .sources из сгенерированного файла: ~ / .dotfiles / bash_1575527908.

[[email protected]] $ ls -a | grep .sources
/.sources -> /Users/example_usr/.dotfiles/bash_1575525908

Файл .sources связан символической ссылкой на сгенерированный файл, содержащий все строки кода, полученные при запуске сценария. Это позволяет нам эффективно хранить историю файла в одном файле, а также иметь возможность быстро ссылаться на него из домашнего каталога пользователя.

Я нашел это полезным для быстрого обращения или отладки в командной строке.

Добавьте следующую функцию #init в наш скрипт и создайте вызов функции.

function init() {
 BASH_DIR=$REPO/src
 SCRIPTS=$BASH_DIR/scripts
 BASH_SRC=bash_”$(date +%s)”
 # Create our generated file with timestamp
 touch -f $BASH_SRC
 # Create directory for history reference
 mkdir -p $REPO/history
 # Store file
 mv -v $REPO/bash_* $REPO/history
}
init

Обратите внимание, что область действия переменной в сценариях оболочки динамически ограничена. Это означает, что область видимости объявленной переменной будет существовать, пока функция все еще выполняется. Это важно отметить и не путать с такими понятиями, как замыкания в JS или локальная область в языках ООП.

Дважды запустите скрипт, чтобы убедиться, что он работает правильно:

Бег №1

[[email protected]] $ ./bash_script
[[email protected]] $ ls -l
/.
/..
/history
/bash_1575525908

Прогон №2

[[email protected]] $ ./bash_script
[[email protected]] $ ls -l
/.
/..
/history
  /bash_1575525908
/bash_1575525909

Создать файл единого источника истины в качестве источника

Поскольку область видимости переменной будет существовать до конца процесса функции, мы можем использовать их определения в следующей функции с плохим названием «generate_stuff».

Добавьте вызов функции в #generate_stuff конец функции # init, определенной на предыдущем шаге.

function init() {
  ...
  generate_stuff
  echo "Done."
}

Давайте применим текущую структуру каталогов на практике. Между моими средами Ubuntu и Mac я храню пользовательские определения псевдонимов и функций в каталоге. / src / scripts репозитория.

Добавьте в наш скрипт следующую функцию. Этот метод довольно прост и выполняет итерацию по файлам в папке и добавляет содержимое в наш сгенерированный файл временных меток Unix.

function generate_stuff() { 
  for f in $SCRIPTS/*
  do
    echo $f
    cat $f >> $BASH_SRC
  done
}

Это хорошее место для программного добавления псевдонимов или исполняемых файлов, которым может потребоваться путь к каталогу. Например, вам может понадобиться псевдоним оболочки для перехода в этот каталог, а другой - для вызова сценария из любого места.

echo "alias dotfiles='cd $DIR'" >> $REPO/$BASH_SRC
echo "alias srcbash='. $DIR/install'" >> $REPO/$BASH_SRC

Затем сделайте этот файл доступным из домашнего каталога. Создайте символическую ссылку на созданный исходный файл в домашний каталог (~).

Добавьте следующие строки в #generate_stuff.

function generate_stuff() {
  ...
  #Remove existing source file during subsequent runs 
  rm -rf ~/.sources || true
  # Link generated file source file: ~/.sources"
  ln -fsn -v $REPO/$BASH_SRC ~/.sources
}

Давайте снова запустим сценарий и выведем список скрытых файлов из домашнего каталога. Должно получиться так:

[[email protected]] $ ./bash_script
[local@dotfiles] $ ls -l
/.
/..
/history
  /bash_1575525909
  /bash_1575525908
/bash_1575530763
[local@dotfiles] $ ls -la ~
/.sources -> /User/example_usr/.dotfiles/bash_1575530763

Окружение Bash и совместимость

Ранее мы переместили наши bash-файлы в наш новый репозиторий dotfiles. Добавьте следующую функцию в скрипт для символьной ссылки на файлы конфигурации bash. Это необходимо, потому что интерпретатор Linux будет искать файлы конфигурации bash в домашнем каталоге пользователя перед поиском файлов конфигурации bash на системном уровне.

function link_bash() {
  for f in $BASH_DIR/*
  do
    FILENAME=$(basename $f)
    [[ -f $f ]] && ln -fsn -v $f $HOME/.$FILENAME
  done
}
init
link_bash

Снова запустите скрипт и выведите список файлов из дома:

[[email protected]] $ ls -a ~
/.
/.. 
/.bash_logout -> /Users/example_usr/.dotfiles/src/bash_logout
/.bash_profile -> /Users/example_usr/.dotfiles/src/bash_profile
/.bashrc -> /Users/example_usr/.dotfiles/src/bashrc
/.profile -> /Users/example_usr/.dotfiles/src/profile

Наконец, загрузите скрипт в Github. Обязательно .gitignore папку history и сгенерированный файл. Их следует игнорировать, чтобы избежать проблем с совместимостью в разных средах.

Для решения проблем совместимости я использую в своих скриптах следующий метод.

function os_patch() {
  OS="`uname -s`"
  case $OS in
    'Linux')
      OS='Linux'
      echo "alias ls='ls --color=auto'" >> $BASH_SRC
      ;;
    'Darwin')
      OS='Mac'
      ;;
    *) ;;
  esac
}

Надеюсь, это поможет тем, кто пишет свои собственные сценарии. Ниже я привел суть, содержащую готовый сценарий, который я использую для синхронизации сред Ubuntu и Mac Bash. Спасибо за прочтение.

Источники