目标
我想使用一个文件安装多个 APT 包。
apt_install_from_file "packages" # assumes 'packages' is a readable file in the $PWD
笔记:我知道还有其他方法可以做到这一点,而且我正在重新发明轮子来说话,但我希望这种方法可以让其他人的生活更轻松。
文件结构
packages
:
# ppa
ppa "deadsnakes/ppa"
# packages
apt "tree"
# deb
deb "fzy" [args: "https://github.com/jhawthorn/fzy/releases/download/0.9/fzy_0.9-1_amd64.deb", "$HOME", "fzy_0.9-1_amd64.deb"]
要求
- 忽略以 开头的任何行,
#
因为这是注释 - 如果该行以 开头,
ppa
则使用引号括起来的文本运行以下命令。例如ppa "deadsnakes/ppa"
=>sudo add-apt-repository -y ppa:deadsnakes/ppa &> /dev/null
- 如果该行以 开头,
apt
则使用引号括起来的文本运行以下命令。例如apt "tree"
=>sudo apt install --allow-unauthenticated -qqy tree
- 如果该行以 开头,
deb
则抓取引号内包含的文本以及抓取args
引号内包含的后面的文本。
当前职能:
apt_install_from_file() {
declare -r FILE_PATH="$1"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Install package(s)
if [ -e "$FILE_PATH" ]; then
cat < "$FILE_PATH" | while read -r LINE; do
if [[ "$LINE" == *"#"* || -z "$LINE" ]]; then
continue
elif [[ "$LINE" == *"ppa"* || -z "$LINE" ]]; then
# ppa= Grab text enclosed by quotes following "ppa"
sudo add-apt-repository -y ppa:"$ppa" &> /dev/null \
&& sudo apt update
elif [[ "$LINE" == *"apt"* || -z "$LINE" ]]; then
package="$LINE" # Grab text enclosed by quotes following "apt"
sudo apt install --allow-unauthenticated -qqy "$package"
elif [[ "$LINE" == *"deb"* || -z "$LINE" ]]; then
#package_name= Grab text enclosed by quotes following "deb"
#url= Grab text enclosed by quotes following "args"
#target_path= Grab text enclosed by quotes following "args"
#file_name= Grab text enclosed by quotes following "args"
#file_path="$target_path" + "/" + "$file_name"
wget $url -O $file_path && \
sudo dpkg -i $file_path && sudo apt-get install -f && \
sudo rm -rf $file_path && sudo apt autoremove -qqy
fi
done
fi
}
问题
我需要帮助根据我的需求列表填写功能的空白。
答案1
已经有格式了用于使用文件控制 apt。这是一个普通的 shell 脚本。
/bin/sh #!/bin/sh 复制代码 # 说明:使用 sudo 运行我:$ sudo install_script.sh # 警告:所有错误均已消除或删除。我想我不想知道…… # 电力供应局 添加 apt-repository -y ppa:deadsnakes/ppa &> /dev/null 添加 apt-repository -y ppa:font-manager/staging &> /dev/null 添加 apt-repository -y ppa:fish-shell/release-2 &> /dev/null 添加 apt-repository -y ppa:zanchey/asciinema &> /dev/null # 软件包 apt install --allow-unauthenticated -qqy 树符号链接 # deb wget https://github.com/jhawthorn/fzy/releases/download/0.9/fzy_0.9-1_amd64.deb -O /tmp/fzy_0.9-1_amd64.deb apt-安装/tmp/fzy_0.9-1_amd64.deb-qqy rm /tmp/fzy_0.9-1_amd64.deb
有很多方法可以使脚本变得更复杂并且更有趣。
还有许多方法可以清理脚本并使其更具可读性和可维护性。
答案2
这里使用的语法对 shell 脚本没有任何帮助,但是如果使用正则表达式,解析该文件会稍微容易一些。Bash 的正则表达式比较会将组保存(...)
在数组中BASH_REMATCH
,因此您可以一次性测试有效行并解析它。例如:
#! /bin/bash
declare -A regex
regex["comment"]='^#(.*)'
regex["ppa"]='ppa "(.*)"'
regex["apt"]='apt "(.*)"'
regex["deb"]='deb "(.*)" \[args: "(.*)", "(.*)", "(.*)"\]'
while read LINE
do
if [[ $LINE =~ ${regex[comment]} ]]
then
printf "Comment: %s\n" "${BASH_REMATCH[1]}"
continue
elif [[ $LINE =~ ${regex[ppa]} ]]
then
ppa=${BASH_REMATCH[1]}
printf "PPA: %s\n" "$ppa"
elif [[ $LINE =~ ${regex[apt]} ]]
then
package=${BASH_REMATCH[1]}
printf "APT: %s\n" "$package"
elif [[ $LINE =~ ${regex[deb]} ]]
then
package_name=${BASH_REMATCH[1]}
url=${BASH_REMATCH[2]}
target_path=${BASH_REMATCH[3]}
file_name=${BASH_REMATCH[4]}
file_path="$target_path/$file_name"
printf "package_name: %s\n" "$package_name"
printf "url: %s\n" "$url"
printf "file_path: %s\n" "$file_path"
fi
done < "$1"
使用您的示例文件:
$ ./foo.sh foo.txt
Comment: ppa
PPA: deadsnakes/ppa
Comment: packages
APT: tree
Comment: deb
package_name: fzy
url: https://github.com/jhawthorn/fzy/releases/download/0.9/fzy_0.9-1_amd64.deb
file_path: $HOME/fzy_0.9-1_amd64.deb
答案3
背景:
经过一些研究和反复试验后,我发现我可以将该工具cut
与结合使用echo
。
例子:
为了实现所需的输出,请参考以下示例。
packages
:
# packages
apt "tree"
test.sh
:
apt_install_from_file() {
declare -r FILE_PATH="$1"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Install package(s)
if [ -e "$FILE_PATH" ]; then
cat < "$FILE_PATH" | while read -r LINE; do
if [[ "$LINE" == *"#"* || -z "$LINE" ]]; then
continue
elif [[ "$LINE" == *"apt"* || -z "$LINE" ]]; then
package="$(echo $LINE | cut -d \" -f2)"
echo "$package"
fi
done
fi
}
用法:
./test.sh packages
分解:
给定这条线package="$(echo $LINE | cut -d \" -f2)"
,让我们把它分解一下。
- 首先,我们来看看
echo
该行的内容。 - 然后,我们将结果 pip 到 ,根据给定的分隔符
cut
将 的内容拆分$LINE
为多个字段。本例中的分隔符是"
。我们必须\
在 前面放置"
,因为必须对引号字符进行转义。 - 接下来,我们抓取该分割的第二个字段,它包含
tree
。 $()
最后,我们将返回的内容存储到package
哪种情况下tree
(例如$()
=>tree
)。
修改功能:
apt_install_from_file() {
declare -r FILE_PATH="$1"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Install package(s)
if [ -e "$FILE_PATH" ]; then
cat < "$FILE_PATH" | while read -r LINE; do
if [[ "$LINE" == *"#"* || -z "$LINE" ]]; then
continue
elif [[ "$LINE" == *"ppa"* || -z "$LINE" ]]; then
ppa="$(echo $LINE | cut -d \" -f2)"
sudo add-apt-repository -y ppa:"$ppa" &> /dev/null \
&& sudo apt update
elif [[ "$LINE" == *"apt"* || -z "$LINE" ]]; then
package="$(echo $LINE | cut -d \" -f2)"
sudo apt install --allow-unauthenticated -qqy "$package"
elif [[ "$LINE" == *"deb"* || -z "$LINE" ]]; then
package_name="$(echo $LINE | cut -d \" -f2)"
url="$(echo $LINE | cut -d \" -f4)"
target_path="$(echo $LINE | cut -d \" -f6)"
file_name="$(echo $LINE | cut -d \" -f8)"
file_path="$target_path/$file_name"
wget $url -O $file_path && \
sudo dpkg -i $file_path && sudo apt-get install -f && \
sudo rm -rf $file_path && sudo apt autoremove -qqy
fi
done
fi
}
结论:
这可能不是我上面列出的问题的最佳解决方案,而且它确实是一个黑客解决方案,所以如果有更好的解决方案,请不要犹豫,写一个更新的答案!
答案4
最近我刚写了一个工具,系统信息,就是为了这个目的。它是一个简单的工具(独立二进制文件),它从 toml 文件而不是纯文本文件读取。无需处理纯文本文件的格式和 shell 脚本中的自定义逻辑。欢迎提出建议和反馈!
下载
curl -L https://github.com/Benjamin-Tan/sysdep/releases/latest/download/sysdep-$(arch)-unknown-linux-gnu.tar.gz | tar -xz -C ~/.local/bin
创建一个
system_dependencies.toml
,文件名可以根据您的喜好修改。[dependencies] apt = ["libpackage", "libpackage2"]
sysdep list
列出依赖项,应该显示“libpackage”、“libpackage2”。sysdep install
安装它们sysdep
显示更多选项的帮助页面。