编写 shell 脚本以通过运行脚本来撤消对系统所做的更改

编写 shell 脚本以通过运行脚本来撤消对系统所做的更改

问题:

我是否应该编写一个脚本来撤消通过运行脚本所做的更改?

如果不是,那么我如何清理/撤消对系统所做的更改,以便我可以在运行脚本之前的系统状态下再次运行脚本(进行更改)

如果是,那么编写好的撤消脚本应该采用什么方法?


脚本:链接到 github 上的脚本

#!bin/bash

repos_dir="$HOME/repos"
if [ ! -d "$repos_dir" ]; then
  mkdir -p "$repos_dir"
fi

git clone https://github.com/bashonregardless/dotfiles.git "$repos_dir/dotfiles"

software_dir="$HOME/software"
# Create a directory to download nvim software.
if test ! -d "$software_dir"; then
  mkdir "$software_dir"
fi

(
cd "$software_dir"
# Download Neovim on Linux
if test $? = 0 && "$(command -v curl)" &> dev/null; then
  curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
  chmod u+x nvim.appimage
else
  echo "Error: curl is not installed"
  echo
  exit 64
fi
)

# Create "$HOME/bin" dir if it does not exist
if test ! -d "$HOME/bin"
then
    mkdir "$HOME/bin"
fi

# Create a symbolic link in "$HOME/bin" dir to "$HOME/software/nvim"
ln "$software_dir/nvim.appimage" "$HOME/bin/nvim"

# Update vimrc at "$HOME/.vim/vimrc"
[ ! -d "$HOME/.vim" ] && mkdir "$HOME/.vim"
if [ ! -e "$HOME/.vim/vimrc" ]; then
    # create a new file by copying dotfile vimrc
    cp "$repos_dir/dotfiles/vimrc.template" "$HOME/.vim/vimrc"
else
    cat "$repos_dir/dotfiles/vimrc.template" >> "$HOME/.vim/vimrc" 
fi

# Update init.vim at "$HOME/.config/nvim/" (VIMCONFIG="$HOME/.config/nvim")
[ ! -d "$HOME/.config/nvim" ] && mkdir -p "$HOME/.config/nvim"
if [ ! -e "$HOME/.config/nvim/init.vim" ]; then
    # create a new file by copying dotfile vimrc
    cp "$repos_dir/dotfiles/init.vim.template" "$HOME/.config/nvim/init.vim"
else
    cat "$repos_dir/dotfiles/init.vim.template" >> "$HOME/.config/nvim/init.vim" 
fi

# add minpac vim plugin manager (See Modern vim craft)
[ ! -d "$HOME/.config/nvim/pack/minpac/opt" ] && mkdir -p "$HOME/.config/nvim/pack/minpac/opt"
cd "$HOME/.config/nvim/pack/minpac/opt"
git clone https://github.com/k-takata/minpac.git
cd -

# Update dotfiles (create, if non-existent)
if [ ! -e "$HOME/.bash_profile" ]; then
    # Copy and rename in the same time
    cp "$repos_dir/dotfiles/bash_profile" "$HOME/.bash_profile"
else
    cat "$repos_dir/dotfiles/bash_profile" >> "$HOME/.bash_profile" 
fi

if [ ! -e "$HOME/.bashrc" ]; then
    cp "$repos_dir/dotfiles/bashrc" "$HOME/.bashrc"
else
    cat "$repos_dir/dotfiles/bashrc" >> "$HOME/.bashrc" 
fi

该脚本设置 vim 开发环境。我编写了脚本并认为正确设置就足够了,所以我第一次运行它并且它起作用了。然后我对脚本做了一些更改,并想测试它是否正确运行。这次运行时,我遇到了一些警告/错误/日志,例如:

ln: 无法创建硬链接 '/home/user/bin/nvim': 文件存在

致命:目标路径“/home/user/repos/dotfiles”已存在,并且不是空目录。

我用过几个cat file >> another-file,那个another-file每次运行脚本时都会将重复的内容附加到。我绝对想撤消这一点


通过运行脚本对系统进行的更改:

  1. 创建 ~/repos 目录。
  2. 在存储库中克隆 dotfiles 存储库。
  3. 在存储库中克隆 compSc 存储库。
  4. 在家里创建软件目录。
  5. 在软件目录中下载nvim。
  6. 更改下载文件 nvim.appimage 的权限。
  7. 在家里创建 bin 目录。
  8. 使用 ~/bin/nvim 创建 nvim.appimage 的符号链接
  9. 创建 ~/.vim/vimrc (mkdir -p)。
  10. 复制/创建或附加到 ~/.vim/vimrc。
  11. mkdir -p "$HOME/.config/nvim/pack/minpac/opt"
  12. 克隆 k-takata/minpac indside "$HOME/.config/nvim/pack/minpac/opt"
  13. 复制/创建或附加到“$HOME/.bash_profile”

这些是在获取 ~/.bash_profile 文件之前我的系统发生的更改。 Sourcing 对我的系统进行了进一步的更改,例如更新 PATH 和其他环境变量等。

我也想撤消这些更改。


我如何复制运行脚本之前的系统状态(出于测试目的)?

我用多次通过为每一个小变化启动一个 Ubuntu VM。运行脚本后,我删除了该虚拟机并启动了一个新虚拟机。这为我提供了一台处于可以首次运行脚本状态的机器。我对每一个小变化都会这样做。很快就会变得乏味。

答案1

一般来说,您无法可靠地撤消脚本的效果。例如,脚本开头的代码片段:

if [ ! -d "$repos_dir" ]; then
  mkdir -p "$repos_dir"
fi

无法可靠地撤消,因为事后您无法确定之前已经存在的目录路径有多少"$repos_dir"

如果您希望脚本完全可撤消,那么您需要在触摸之前记录您触摸的所有内容的原始状态,以便您可以在需要时恢复它。这就是包管理器尝试做的事情,并取得了不同程度的成功。

另一种方法是让你的脚本幂等的。这意味着运行两次与运行一次的效果完全相同。这是 Ansible 或 Puppet 等期望状态配置管理工具的方法。

上面的代码片段是幂等代码的典型示例:如果目录"$repos_dir"在上次运行中已经存在,那么它什么也不做。

代码示例是不是幂等将是您每次运行脚本时cat file >> another-file都会附加重复内容的情况。another-file使其幂等需要检查 的内容file(或者可能是其不同版本)是否已存在于 中another-file,然后要么首先删除它,要么不再添加它。或者,您可以保留another-file不带内容的基本版本file,并使用它来连接,如下所示:

if [ ! -e another-file.base ]; then
  mv another-file another-file.base
fi
cat another-file.base file > another-file

相关内容