Skip to content

Instantly share code, notes, and snippets.

@ChenyangGao
Last active July 15, 2024 07:05
Show Gist options
  • Save ChenyangGao/e8e520de651e6375dad552b5a761902f to your computer and use it in GitHub Desktop.
Save ChenyangGao/e8e520de651e6375dad552b5a761902f to your computer and use it in GitHub Desktop.
在服务器部署alist和clouddrive(原来只支持openwrt,现在已通用)
#!/usr/bin/env bash
# current_shell_rcfile() {
# if [ -n "$BASH_VERSION" ]; then
# printf "%s\n" ~/.bashrc
# elif [ -n "$ZSH_VERSION" ]; then
# printf "%s\n" ~/.zshrc
# elif [ -n "$FISH_VERSION" ]; then
# printf "%s\n" ~/.config/fish/config.fish
# elif [ -n "$XONSH_VERSION" ]; then
# printf "%s\n" ~/.xonshrc
# else
# echo '目前只支持 bash、zsh、fish 和 xonsh' >&2
# exit 1
# fi
# }
default_shell_rcfile() {
case "$(basename $SHELL)" in
bash)
printf "%s\n" ~/.bashrc
;;
zsh)
printf "%s\n" ~/.zshrc
;;
fish)
printf "%s\n" ~/.config/fish/config.fish
;;
xonsh)
printf "%s\n" ~/.xonshrc
;;
*)
echo '目前只支持 bash、zsh、fish 和 xonsh,你的默认 shell 是:'"$SHELL" >&2
exit 1
;;
esac
}
if command -v alist >&-; then
cmd=(alist server --debug)
elif [ -f ~/alist.d/alist ]; then
cmd=(~/alist.d/alist server --debug)
else
echo '未能找到 alist 可执行文件:
1. 在 $PATH 中未找到 alist
2. 没有可执行文件 ~/alist.d/alist
' >&2
exit 1
fi
file=$0
if ! [ -x "$file" ]; then
chmod +x "$file"
fi
#:------------------------------:#
run() {
while true; do
"${cmd[@]}"
if [ $? -eq 0 ]; then
break
fi
done
}
start() {
if [ $# -eq 0 ]; then
pgrep -f "${cmd[*]}" >&- || run
else
start &
fi
}
stop() {
pgrep -f "${cmd[*]}" | xargs -r kill
}
restart() {
stop
start "$@"
}
status() {
local pids=($(pgrep -f "${cmd[*]}"))
if [ ${#pids[@]} -gt 0 ]; then
local args=()
for pid in "${pids[@]}"; do
args+=("-p" $pid)
done
top "${args[@]}"
fi
}
log() {
tail -f ~/alist.log
}
enable() {
local rcfile=$1
if [ -z "$rcfile" ]; then
rcfile=$(default_shell_rcfile)
fi
grep -q '# startup:alist\.sh$' "$rcfile" || echo "'$file' start -d &>>~/alist.log # startup:alist.sh" >> "$rcfile"
}
disable() {
local rcfile=$1
if [ -z "$rcfile" ]; then
rcfile=$(default_shell_rcfile)
fi
sed -i "/# startup:alist\.sh\$/d" "$rcfile"
}
#:------------------------------:#
cd ~
case "$1" in
start | stop | restart | status | log | enable | disable)
"$1" "${@:2}"
;;
startup)
enable "${@:2}"
;;
unstartup)
disable "${@:2}"
;;
*)
echo '>>> 帮助信息
start 启动 alist。可指定 -d 后台运行。
————————————————————
stop 停止 alist。
————————————————————
restart 重启 alist。可指定 -d 后台运行。
————————————————————
status 显示 alist 的进程信息。
————————————————————
log 显示 alist 的日志信息。
————————————————————
enable 打开终端后自动启动 alist,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。
通过在默认 SHELL 的 rcfile 文件中写入启动命令来实现,日志在 ~/alist.log。
————————————————————
disable 去除 enable 注册的启动,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。
————————————————————
startup 等同于 enable。
————————————————————
unstartup 等同于 disable。
'
;;
esac
#!/usr/bin/env bash
# current_shell_rcfile() {
# if [ -n "$BASH_VERSION" ]; then
# printf "%s\n" ~/.bashrc
# elif [ -n "$ZSH_VERSION" ]; then
# printf "%s\n" ~/.zshrc
# elif [ -n "$FISH_VERSION" ]; then
# printf "%s\n" ~/.config/fish/config.fish
# elif [ -n "$XONSH_VERSION" ]; then
# printf "%s\n" ~/.xonshrc
# else
# echo '目前只支持 bash、zsh、fish 和 xonsh' >&2
# exit 1
# fi
# }
default_shell_rcfile() {
case "$(basename $SHELL)" in
bash)
printf "%s\n" ~/.bashrc
;;
zsh)
printf "%s\n" ~/.zshrc
;;
fish)
printf "%s\n" ~/.config/fish/config.fish
;;
xonsh)
printf "%s\n" ~/.xonshrc
;;
*)
echo '目前只支持 bash、zsh、fish 和 xonsh,你的默认 shell 是:'"$SHELL" >&2
exit 1
;;
esac
}
if command -v clouddrive >&-; then
cmd=(clouddrive)
elif [ -f ~/clouddrive.d/clouddrive ]; then
cmd=(~/clouddrive.d/clouddrive)
else
echo '未能找到 clouddrive 可执行文件:
1. 在 $PATH 中未找到 clouddrive
2. 没有可执行文件 ~/clouddrive.d/clouddrive
' >&2
exit 1
fi
file=$0
if ! [ -x "$file" ]; then
chmod +x "$file"
fi
#:------------------------------:#
run() {
while true; do
"${cmd[@]}"
if [ $? -eq 0 ]; then
break
fi
done
}
start() {
if [ $# -eq 0 ]; then
pgrep -f "${cmd[*]}" >&- || run
else
start &
fi
}
stop() {
pgrep -f "${cmd[*]}" | xargs -r kill
}
restart() {
stop
start "$@"
}
status() {
local pids=($(pgrep -f "${cmd[*]}"))
if [ ${#pids[@]} -gt 0 ]; then
local args=()
for pid in "${pids[@]}"; do
args+=("-p" $pid)
done
top "${args[@]}"
fi
}
log() {
tail -f ~/clouddrive.log
}
enable() {
local rcfile=$1
if [ -z "$rcfile" ]; then
rcfile=$(default_shell_rcfile)
fi
grep -q '# startup:clouddrive\.sh$' "$rcfile" || echo "'$file' start -d &>>~/clouddrive.log # startup:clouddrive.sh" >> "$rcfile"
}
disable() {
local rcfile=$1
if [ -z "$rcfile" ]; then
rcfile=$(default_shell_rcfile)
fi
sed -i "/# startup:clouddrive\.sh\$/d" "$rcfile"
}
#:------------------------------:#
cd ~
case "$1" in
start | stop | restart | status | log | enable | disable)
"$1" "${@:2}"
;;
startup)
enable "${@:2}"
;;
unstartup)
disable "${@:2}"
;;
*)
echo '>>> 帮助信息
start 启动 clouddrive。可指定 -d 后台运行。
————————————————————
stop 停止 clouddrive。
————————————————————
restart 重启 clouddrive。可指定 -d 后台运行。
————————————————————
status 显示 clouddrive 的进程信息。
————————————————————
log 显示 clouddrive 的日志信息。
————————————————————
enable 打开终端后自动启动 clouddrive,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。
通过在默认 SHELL 的 rcfile 文件中写入启动命令来实现,日志在 ~/clouddrive.log。
————————————————————
disable 去除 enable 注册的启动,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。
————————————————————
startup 等同于 enable。
————————————————————
unstartup 等同于 disable。
'
;;
esac
#!/usr/bin/env bash
# NOTE 这个脚本可以用 bash 或 zsh 运行,在 Linux 下请用 root 权限运行,否则不会尝试设置开机自启动服务
# NOTE 可用环境变量 VERSION 指定要下载的版本号
# NOTE 可用环境变量 NOSTARTUP 禁用自动设置开机启动
# NOTE 操作系统中必须安装有 wget (我不用 curl,因为 curl 访问 github 好像有 bug,经常返回空页面)
if ! command -v wget >&-; then
echo '请安装 wget' >&2
exit 1
fi
# inetutils (apt)
# net-tools (yum)
get-local-ipv4-using-hostname() {
hostname -I 2>&- | awk '{print $1}'
}
# iproute2
get-local-ipv4-using-iproute2() {
# OR ip route get 1.2.3.4 | awk '{print $7}'
ip -4 route 2>&- | awk '{print $NF}' | grep -Eo --color=never '[0-9]+(\.[0-9]+){3}'
}
# net-tools
get-local-ipv4-using-ifconfig() {
( ifconfig 2>&- || ip addr show 2>&- ) | grep -Eo '^\s+inet\s+\S+' | grep -Eo '[0-9]+(\.[0-9]+){3}' | grep -Ev '127\.0\.0\.1|0\.0\.0\.0'
}
# 获取本机 IPv4 地址
get-local-ipv4() {
set -o pipefail
get-local-ipv4-using-hostname || get-local-ipv4-using-iproute2 || get-local-ipv4-using-ifconfig
}
# 获取本机 IPv4 地址(只取第一个)
get-local-ipv4-select() {
local ips=$(get-local-ipv4)
local retcode=$?
if [ $retcode -ne 0 ]; then
return $retcode
fi
grep -m 1 "^192\." <<<"$ips" || \
grep -m 1 "^172\." <<<"$ips" || \
grep -m 1 "^10\." <<<"$ips" || \
head -n 1 <<<"$ips"
}
# 操作系统的名称
PLATFORM=$(uname -s)
# 操作系统的 CPU 架构
ARCH=$(uname -m)
# alist 项目的 github 主页链接
ALIST_GITHUB_URL=https://github.com/alist-org/alist
# 默认的 alist 软件包,会根据系统信息自动确定,不能确定的留空
ALIST_DEFAULT_ASSET=
# 已选择的 alist 软件包,此参数被 download-asset 函数设置
ALIST_SELECTED_ASSET=
if [ "$PLATFORM" = 'Darwin' ]; then
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then
ALIST_DEFAULT_ASSET=alist-darwin-arm64.tar.gz
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then
ALIST_DEFAULT_ASSET=alist-darwin-amd64.tar.gz
fi
elif [ "$PLATFORM" = 'Linux' ]; then
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-arm64.tar.gz
elif [ "$arch" = 'armv7l' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musleabihf-armv7l.tar.gz
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-amd64.tar.gz
elif [ "$ARCH" = 'mips' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-mips.tar.gz
elif [ "$ARCH" = 'mipsle' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-mipsle.tar.gz
elif [ "$ARCH" = 'mips64' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-mips64.tar.gz
elif [ "$ARCH" = 'mips64le' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-mipsle.tar.gz
elif [ "$ARCH" = 'ppc64le' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-ppc64le.tar.gz
elif [ "$ARCH" = 'riscv64' ]; then
ALIST_DEFAULT_ASSET=alist-linux-riscv64.tar.gz
elif [ "$ARCH" = 's390x' ]; then
ALIST_DEFAULT_ASSET=alist-linux-musl-s390x.tar.gz
fi
# NOTE 暂时不管 Windows
# elif [ "$PLATFORM" = 'Windows' ]; then
fi
# 当前系统所用的进程启动器
SYSTEM_INIT=
if [ -n "${NOSTARTUP+x}" ]; then
SYSTEM_INIT=unset
elif [ "$PLATFORM" = 'Darwin' ]; then
SYSTEM_INIT=$(ps -p 1 -o comm=)
elif [ "$PLATFORM" = 'Linux' ]; then
# ps -p 1 -o comm= # NOTE 也可以用这个命令,但是但有些嵌入式系统,ps 没有 -p 选项
# SYSTEM_INIT=$(cat /proc/1/cmdline)
SYSTEM_INIT=$(cat /proc/1/comm)
# NOTE 暂时不管 Windows
# elif [ "$PLATFORM" = 'Windows' ]; then
# # services.exe 和 lsass.exe 进程通常是由 Windows 的启动器(服务控制管理器)启动的
# # tasklist | findstr /i "services.exe lsass.exe"
fi
# 获取某个 github 页面的响应。$1: github 链接。
request-github-url() {
local url=$1
if [ -z "$url" ]; then
echo '不能是空链接' >&2
return 1
elif [[ $url == /* ]]; then
url=https://github.com$url
elif [ "$url" = https://github.com ]; then
true
elif [[ $url != https://github.com/* ]]; then
url=https://github.com/$url
fi
local page=$(wget -q -O - "$url")
local retcode=$?
# NOTE 我发现,如果使用 curl,可能会因为访问失败,而返回空页面,虽然目前使用 wget,但为了以防万一
while [ -z "$page" ]; do
echo $'\x1b[38;5;1m\x1b[1mRETRYING\x1b[0m:' "$url" >&2
page=$(wget -q -O - "$url")
retcode=$?
done
if [ $retcode -ne 0 ]; then
echo -n "$page" >&2
return $retcode
fi
echo -n "$page"
}
# 下载软件包,如果软件包已存在,则跳过。$1: 版本号。
download-asset() {
local version=$1
local release_link=
if [ -z "$version" ] || ! [[ "$version" =~ ^v?[0-9.]+$ ]] ; then
release_link=$ALIST_GITHUB_URL/releases/latest
release_link=$(wget -q --server-response --max-redirect=0 - $release_link 2>&1 | grep -i location | grep -o 'http.*')
version=$(basename "$release_link")
else
if [[ "$version" != v* ]]; then
version=v$version
fi
release_link=$ALIST_GITHUB_URL/releases/tag/$version
fi
local assets_link="${release_link/\/tag\///expanded_assets/}"
local assets_page=$(request-github-url "$assets_link")
local ifs=$IFS
local var
IFS=$'\n'
local links=()
for var in $(echo "$assets_page" | grep -o 'href="[^"]\+'); do
links+=("${var/href=\"/https://github.com}")
done
IFS=$ifs
local length=${#links[@]}
local flag=0
IFS=$'\n'
local names=()
for var in $(echo "$assets_page" | grep '^ <span' | grep -o '>[^<]*<'); do
if [ $flag -eq 0 ]; then
names+=("${var:1:-1}")
flag=1
else
names[-1]="${names[-1]}""${var:1:-1}"
flag=0
fi
done
IFS=$ifs
local default_index
if [ -n "$ZSH_VERSION" ]; then
for ((i=1; i<=$length; i++)); do
if [ "${names[$i]}" = "$ALIST_DEFAULT_ASSET" ]; then
default_index=$i
fi
printf '%2s | ' $i
echo "${names[$i]} |" "${links[$i]}"
done
else
for ((i=0; i<$length; i++)); do
if [ "${names[$i]}" = "$ALIST_DEFAULT_ASSET" ]; then
default_index=$i
fi
printf '%2s | ' $i
echo "${names[$i]} |" "${links[$i]}"
done
fi
local link name chosen_index
if [ -z "$default_index" ]; then
while true; do
echo -n "请选择一个数字:"
read chosen_index
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index")
if [ -z "$chosen_index" ]; then
continue
fi
link="${links[$chosen_index]}"
if [ -z "$link" ]; then
continue
fi
name="${names[$chosen_index]}"
break
done
else
while true; do
echo -n "请选择一个数字(默认值 $default_index):"
read chosen_index
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index")
if [ -z "$chosen_index" ]; then
chosen_index=default_index
fi
link="${links[$chosen_index]}"
if [ -z "$link" ]; then
continue
fi
name="${names[$chosen_index]}"
break
done
fi
ALIST_SELECTED_ASSET=${version}_$name
if ! [ -f "$ALIST_SELECTED_ASSET" ]; then
wget -O "$ALIST_SELECTED_ASSET" "$link"
fi
}
################################################################
cd ~
download-asset "$VERSION"
if [ $? -ne 0 ]; then
echo '获取软件包失败' >&2
exit 1
fi
mkdir -p ~/alist.d/data
tar --overwrite -xzf "$ALIST_SELECTED_ASSET" -C alist.d
# NOTE 因为在我的 openwrt 上 pgrep 没有 -u 选项 😂
if pgrep -u a $USER &>/dev/null; then
pgrep_arr=(pgrep -u $USER)
else
pgrep_arr=(pgrep)
fi
echo
if [ $EUID -eq 0 ]; then
prep=()
else
prep=(sudo)
fi
case $(basename "$SYSTEM_INIT") in
'launchd')
if [ $EUID -eq 0 ]; then
service=alist
else
service=alist-$USER
fi
service_file="$HOME/Library/LaunchAgents/$service.plist"
mkdir -p "$HOME/Library/LaunchAgents"
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
tee "$service_file" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Description</key>
<string>ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.</string>
<key>Documentation</key>
<string>https://alist.nn.ci/guide/</string>
<key>Label</key>
<string>com.alist</string>
<key>UserName</key>
<string>$USER</string>
<key>KeepAlive</key>
<true />
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>'$HOME/alist.d/alist' server --data '$HOME/alist.d/data'</string>
</array>
<key>RunAtLoad</key>
<true />
<key>OnDemand</key>
<false />
<key>LaunchOnlyOnce</key>
<true />
<key>StandardErrorPath</key>
<string>/tmp/$service.err</string>
<key>StandardOutPath</key>
<string>/tmp/$service.out</string>
</dict>
</plist>
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "launchctl load -w '$service_file'"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "launchctl unload '$service_file'"
launchctl unload "$service_file" 2>&-
launchctl load -w "$service_file"
fi
;;
'systemd')
if [ $EUID -eq 0 ]; then
service=alist
else
service=alist-$USER
fi
service_file=/etc/systemd/system/$service.service
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
[Unit]
Description='ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.'
Documentation='https://alist.nn.ci/guide/'
After=network.target
[Service]
Type=simple
User=$USER
Restart=on-failure
ExecStart='$HOME/alist.d/alist' server --data '$HOME/alist.d/data'
[Install]
WantedBy=default.target
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl start $service"
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service stop"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl stop $service"
"${prep[@]}" systemctl enable "$service"
"${prep[@]}" systemctl stop "$service"
"${prep[@]}" systemctl start "$service"
fi
;;
'init')
if [ $EUID -eq 0 ]; then
service=alist
else
service=alist-$USER
fi
service_file=/etc/init/$service.conf
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
description "ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs."
documentation "https://alist.nn.ci/guide/"
start on filesystem or runlevel [2345]
stop on runlevel [!2345]
respawn
exec '$HOME/alist.d/alist' server --data '$HOME/alist.d/data'
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop"
"${prep[@]}" service "$service" enable
"${prep[@]}" service "$service" stop
"${prep[@]}" service "$service" start
fi
;;
'procd')
if [ $EUID -eq 0 ]; then
service=alist
else
service=alist-$USER
fi
service_file=/etc/init.d/$service
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=99
Description='ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.'
Documentation='https://alist.nn.ci/guide/'
start_service() {
procd_open_instance
procd_set_param command '$HOME/alist.d/alist' server --data '$HOME/alist.d/data'
procd_set_param respawn
procd_set_param user $USER
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile /var/run/alist-$USER.pid
procd_close_instance
}
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
"${prep[@]}" chmod +x "$service_file"
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop"
"${prep[@]}" service "$service" enable
"${prep[@]}" service "$service" stop
"${prep[@]}" service "$service" start
fi
;;
*) # 默认情况
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "'$HOME/alist.d/alist' start --data '$HOME/alist.d/data'"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "'$HOME/alist.d/alist' stop"
# NOTE 如果有已经运行的实例,终结之
"${pgrep_arr[@]}" alist | xargs kill -9
"$HOME/alist.d/alist" start --data "$HOME/alist.d/data"
;;
esac
~/alist.d/alist admin --data ~/alist.d/data
echo
echo -e '\x1b[38;5;3mDocumentation\x1b[0m: https://alist.nn.ci/guide/'
echo -e "\x1b[38;5;3mServer on\x1b[0m: http://$(get-local-ipv4-select):5244"
#!/usr/bin/env bash
# NOTE 这个脚本可以用 bash 或 zsh 运行,在 Linux 下请用 root 权限运行,否则不会尝试设置开机自启动服务
# NOTE 可用环境变量 VERSION 指定要下载的版本号
# NOTE 可用环境变量 NOSTARTUP 禁用自动设置开机启动
# NOTE 操作系统中必须安装有 wget (我不用 curl,因为 curl 访问 github 好像有 bug,经常返回空页面)
if ! command -v wget >&-; then
echo '请安装 wget' >&2
exit 1
fi
# inetutils (apt)
# net-tools (yum)
get-local-ipv4-using-hostname() {
hostname -I 2>&- | awk '{print $1}'
}
# iproute2
get-local-ipv4-using-iproute2() {
# OR ip route get 1.2.3.4 | awk '{print $7}'
ip -4 route 2>&- | awk '{print $NF}' | grep -Eo --color=never '[0-9]+(\.[0-9]+){3}'
}
# net-tools
get-local-ipv4-using-ifconfig() {
( ifconfig 2>&- || ip addr show 2>&- ) | grep -Eo '^\s+inet\s+\S+' | grep -Eo '[0-9]+(\.[0-9]+){3}' | grep -Ev '127\.0\.0\.1|0\.0\.0\.0'
}
# 获取本机 IPv4 地址
get-local-ipv4() {
set -o pipefail
get-local-ipv4-using-hostname || get-local-ipv4-using-iproute2 || get-local-ipv4-using-ifconfig
}
# 获取本机 IPv4 地址(只取第一个)
get-local-ipv4-select() {
local ips=$(get-local-ipv4)
local retcode=$?
if [ $retcode -ne 0 ]; then
return $retcode
fi
grep -m 1 "^192\." <<<"$ips" || \
grep -m 1 "^172\." <<<"$ips" || \
grep -m 1 "^10\." <<<"$ips" || \
head -n 1 <<<"$ips"
}
# 操作系统的名称
PLATFORM=$(uname -s)
# 操作系统的 CPU 架构
ARCH=$(uname -m)
# clouddrive 项目的 github 主页链接
CLOUDDRIVE_GITHUB_URL=https://github.com/cloud-fs/cloud-fs.github.io
# 默认的 clouddrive 软件包,会根据系统信息自动确定,不能确定的留空
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=
# 已选择的 clouddrive 软件包,此参数被 download-asset 函数设置
CLOUDDRIVE_SELECTED_ASSET=
if [ "$PLATFORM" = 'Darwin' ]; then
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-macos-aarch64
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-macos-x86_64
fi
elif [ "$PLATFORM" = 'Linux' ]; then
if [ "$(uname -o)" = 'Android' ]; then
os=android
else
os=linux
fi
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-aarch64
elif [ "$arch" = 'armv7l' ] || [ "$arch" = 'armv7' ]; then
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-armv7
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-x86_64
else
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-$ARCH
fi
# NOTE 暂时不管 Windows
# elif [ "$PLATFORM" = 'Windows' ]; then
fi
# 当前系统所用的进程启动器
SYSTEM_INIT=
if [ -n "${NOSTARTUP+x}" ]; then
SYSTEM_INIT=unset
elif [ "$PLATFORM" = 'Darwin' ]; then
SYSTEM_INIT=$(ps -p 1 -o comm=)
elif [ "$PLATFORM" = 'Linux' ]; then
# ps -p 1 -o comm= # NOTE 也可以用这个命令,但是但有些嵌入式系统,ps 没有 -p 选项
# SYSTEM_INIT=$(cat /proc/1/cmdline)
SYSTEM_INIT=$(cat /proc/1/comm)
# NOTE 暂时不管 Windows
# elif [ "$PLATFORM" = 'Windows' ]; then
# # services.exe 和 lsass.exe 进程通常是由 Windows 的启动器(服务控制管理器)启动的
# # tasklist | findstr /i "services.exe lsass.exe"
fi
# 获取某个 github 页面的响应。$1: github 链接。
request-github-url() {
local url=$1
if [ -z "$url" ]; then
echo '不能是空链接' >&2
return 1
elif [[ $url == /* ]]; then
url=https://github.com$url
elif [ "$url" = https://github.com ]; then
true
elif [[ $url != https://github.com/* ]]; then
url=https://github.com/$url
fi
local page=$(wget -q -O - "$url")
local retcode=$?
# NOTE 我发现,如果使用 curl,可能会因为访问失败,而返回空页面,虽然目前使用 wget,但为了以防万一
while [ -z "$page" ]; do
echo $'\x1b[38;5;1m\x1b[1mRETRYING\x1b[0m:' "$url" >&2
page=$(wget -q -O - "$url")
retcode=$?
done
if [ $retcode -ne 0 ]; then
echo -n "$page" >&2
return $retcode
fi
echo -n "$page"
}
# 下载软件包,如果软件包已存在,则跳过。$1: 版本号。
download-asset() {
local version=$1
local release_link=
if [ -z "$version" ] || ! [[ "$version" =~ ^v?[0-9.]+$ ]] ; then
release_link=$CLOUDDRIVE_GITHUB_URL/releases/latest
release_link=$(wget -q --server-response --max-redirect=0 - $release_link 2>&1 | grep -i location | grep -o 'http.*')
version=$(basename "$release_link")
else
if ! [[ "$version" == v* ]]; then
version=v$version
fi
release_link=$CLOUDDRIVE_GITHUB_URL/releases/tag/$version
fi
local assets_link="${release_link/\/tag\///expanded_assets/}"
local assets_page=$(request-github-url "$assets_link")
local ifs=$IFS
local var
IFS=$'\n'
local links=()
for var in $(echo "$assets_page" | grep -o 'href="[^"]\+'); do
links+=("${var/href=\"/https://github.com}")
done
IFS=$ifs
local length=${#links[@]}
local flag=0
IFS=$'\n'
local names=()
for var in $(echo "$assets_page" | grep '^ <span' | grep -o '>[^<]*<'); do
if [ $flag -eq 0 ]; then
names+=("${var:1:-1}")
flag=1
else
names[-1]="${names[-1]}""${var:1:-1}"
flag=0
fi
done
IFS=$ifs
local default_index
if [ -n "$ZSH_VERSION" ]; then
for ((i=1; i<=$length; i++)); do
if [[ "${names[$i]}" == "$CLOUDDRIVE_DEFAULT_ASSET_PREFIX"* ]]; then
default_index=$i
fi
printf '%2s | ' $i
echo "${names[$i]} |" "${links[$i]}"
done
else
for ((i=0; i<$length; i++)); do
if [[ "${names[$i]}" == "$CLOUDDRIVE_DEFAULT_ASSET_PREFIX"* ]]; then
default_index=$i
fi
printf '%2s | ' $i
echo "${names[$i]} |" "${links[$i]}"
done
fi
local link name chosen_index
if [ -z "$default_index" ]; then
while true; do
echo -n "请选择一个数字:"
read chosen_index
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index")
if [ -z "$chosen_index" ]; then
continue
fi
link="${links[$chosen_index]}"
if [ -z "$link" ]; then
continue
fi
name="${names[$chosen_index]}"
break
done
else
while true; do
echo -n "请选择一个数字(默认值 $default_index):"
read chosen_index
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index")
if [ -z "$chosen_index" ]; then
chosen_index=default_index
fi
link="${links[$chosen_index]}"
if [ -z "$link" ]; then
continue
fi
name="${names[$chosen_index]}"
break
done
fi
CLOUDDRIVE_SELECTED_ASSET=$name
if ! [ -f "$CLOUDDRIVE_SELECTED_ASSET" ]; then
wget "$link"
fi
}
################################################################
cd ~
download-asset "$VERSION"
if [ $? -ne 0 ]; then
echo '获取软件包失败' >&2
exit 1
fi
tar --overwrite -xzf "$CLOUDDRIVE_SELECTED_ASSET"
ln -sf "$(pwd)/${CLOUDDRIVE_SELECTED_ASSET%.*}" clouddrive.d
# NOTE 因为在我的 openwrt 上 pgrep 没有 -u 选项 😂
if pgrep -u $USER a &>/dev/null; then
pgrep_arr=(pgrep -u $USER)
else
pgrep_arr=(pgrep)
fi
echo
if [ $EUID -eq 0 ]; then
prep=()
else
prep=(sudo)
fi
case $(basename "$SYSTEM_INIT") in
'launchd')
if [ $EUID -eq 0 ]; then
service=clouddrive
else
service=clouddrive-$USER
fi
service_file="$HOME/Library/LaunchAgents/$service.plist"
mkdir -p "$HOME/Library/LaunchAgents"
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
tee "$service_file" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Description</key>
<string>CloudDrive - 解锁云存储的无限可能</string>
<key>Documentation</key>
<string>http://www.clouddrive2.com/help.html</string>
<key>Label</key>
<string>com.clouddrive</string>
<key>UserName</key>
<string>$USER</string>
<key>KeepAlive</key>
<true />
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>'$HOME/clouddrive.d/clouddrive'</string>
</array>
<key>RunAtLoad</key>
<true />
<key>OnDemand</key>
<false />
<key>LaunchOnlyOnce</key>
<true />
<key>StandardErrorPath</key>
<string>/tmp/$service.err</string>
<key>StandardOutPath</key>
<string>/tmp/$service.out</string>
</dict>
</plist>
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "launchctl load -w '$service_file'"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "launchctl unload '$service_file'"
launchctl unload "$service_file" 2>&-
launchctl load -w "$service_file"
fi
;;
'systemd')
if [ $EUID -eq 0 ]; then
service=clouddrive
else
service=clouddrive-$USER
fi
service_file=/etc/systemd/system/$service.service
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
[Unit]
Description='CloudDrive - 解锁云存储的无限可能'
Documentation='http://www.clouddrive2.com/help.html'
After=network.target
[Service]
Type=simple
User=$USER
Restart=on-failure
ExecStart='$HOME/clouddrive.d/clouddrive'
[Install]
WantedBy=default.target
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl start $service"
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service stop"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl stop $service"
"${prep[@]}" systemctl enable "$service"
"${prep[@]}" systemctl stop "$service"
"${prep[@]}" systemctl start "$service"
fi
;;
'init')
if [ $EUID -eq 0 ]; then
service=clouddrive
else
service=clouddrive-$USER
fi
service_file=/etc/init/$service.conf
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
description "CloudDrive - 解锁云存储的无限可能"
documentation "http://www.clouddrive2.com/help.html"
start on filesystem or runlevel [2345]
stop on runlevel [!2345]
respawn
exec '$HOME/clouddrive.d/clouddrive'
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop"
"${prep[@]}" service "$service" enable
"${prep[@]}" service "$service" stop
"${prep[@]}" service "$service" start
fi
;;
'procd')
if [ $EUID -eq 0 ]; then
service=clouddrive
else
service=clouddrive-$USER
fi
service_file=/etc/init.d/$service
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file"
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m'
"${prep[@]}" tee "$service_file" << EOF
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=99
Description='CloudDrive - 解锁云存储的无限可能'
Documentation='http://www.clouddrive2.com/help.html'
start_service() {
procd_open_instance
procd_set_param command '$HOME/clouddrive.d/clouddrive'
procd_set_param respawn
procd_set_param user $USER
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile /var/run/clouddrive-$USER.pid
procd_close_instance
}
EOF
if [ $? -eq 0 ]; then
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m'
"${prep[@]}" chmod +x "$service_file"
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop"
"${prep[@]}" service "$service" enable
"${prep[@]}" service "$service" stop
"${prep[@]}" service "$service" start
fi
;;
*) # 默认情况
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "'$HOME/clouddrive.d/clouddrive' &"
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "${pgrep_arr[@]} clouddrive | xargs kill -9"
# NOTE 如果有已经运行的实例,终结之
"${pgrep_arr[@]}" clouddrive | xargs kill -9
"$HOME/clouddrive.d/clouddrive" &
;;
esac
echo
echo -e '\x1b[38;5;3mDocumentation\x1b[0m: http://www.clouddrive2.com/help.html'
echo -e "\x1b[38;5;3mServer on\x1b[0m: http://$(get-local-ipv4-select):19798"
echo '### 测试账号 ###'
echo 'mail: test@test.com'
echo 'password: 123456'
#!/usr/bin/env bash
echo "Step 1: 安装 AList"
apt update
apt install -y alist jq wget
echo "Step 2: 设置自启动"
wget -q https://gist.githubusercontent.com/ChenyangGao/e8e520de651e6375dad552b5a761902f/raw/alist.sh -O ~/alist.sh
chmod +x ~/alist.sh
~/alist.sh enable
~/alist.sh start -d
echo "Step 3: 修改 admin 的密码为 123456"
alist admin set 123456
echo "Step 4: 启用 guest 用户,免密码、启用 Webdav、只读"
AlistToken=$(wget -q -O - --header="Content-Type: application/json" --post-data='{"username": "admin", "password": "123456"}' http://localhost:5244/api/auth/login | jq -r '.data.token')
wget -q -O - --header="Content-Type: application/json" --header "Authorization: $AlistToken" --post-data='{"id": 2, "username": "guest", "password": "", "role": 1, "permission": 258, "disabled": false}' http://localhost:5244/api/admin/user/update
@ChenyangGao
Copy link
Author

ChenyangGao commented Sep 25, 2023

TermuxAndroid 平台上的一个终端模拟器和开发环境,由于没有类似 systemd 之类的进程管理器,所以想要自启动需要一些其他的办法。
下面是我想出的一种办法,可以在当前 shell 的 rc 文件中写入一段启动脚本实现开启 Termux 就自动运行 alist 和 clouddrive。
参见上面的 alist.shclouddrive.sh

本 gist 是这篇文章的代码部分:https://chenyanggao.github.io/2023/08/02/14.%E5%9C%A8Linux:MacOSX%E4%B8%8A%E9%83%A8%E7%BD%B2AList%E5%92%8Cclouddrive/

👊 可以用下面的脚本实现伴随 Termux 打开后的自动启动 alist:

bash -c "$(wget -q -O - https://gist.githubusercontent.com/ChenyangGao/e8e520de651e6375dad552b5a761902f/raw/termux-init-alist.sh)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment