Created
March 22, 2025 16:24
-
-
Save lmzxtek/d46873f7f61d549ba6d2947e217e2f38 to your computer and use it in GitHub Desktop.
qiq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| echoT(){ FLAG=$1 && shift && echo -e "\033[39m$FLAG\033[39m$@";} | |
| echoY(){ FLAG=$1 && shift && echo -e "\033[38;5;148m$FLAG\033[39m$@";} | |
| echoG(){ FLAG=$1 && shift && echo -e "\033[38;5;71m$FLAG\033[39m$@"; } | |
| echoB(){ FLAG=$1 && shift && echo -e "\033[38;1;34m$FLAG\033[39m$@" ;} | |
| echoR(){ FLAG=$1 && shift && echo -e "\033[38;5;203m$FLAG\033[39m$@"; } | |
| FCLS='\033[34m' # 前景色:蓝色 | |
| FTCZ='\033[0m' # 字体:重置所有 | |
| FTSS='\033[5m' # 字体:闪烁 | |
| VLATEST="${FCLS}${FTSS}NEW${FTCZ}" # 蓝色闪烁字体 | |
| url_redir='https://sub.zwdk.org/qiq' | |
| url_script='https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/src/qiq.sh' | |
| url_update='https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/src/log.sh' | |
| clear | |
| echoR " >>> " $(echoY "脚本更新日志") $(echoR "<<<") | |
| echoB " - " $(echoT $url_update) | |
| echoT "--------------------------------" | |
| echoT " -=> 2025-03-21 v0.7.2" " " | |
| echoT " 1.日志文件接之前的版本" | |
| echoT " 2.测试DD脚本项" | |
| echoT " 3.修正测试项链接" | |
| echoT " 4.完善Docker部署" | |
| echoT "--------------------------------" | |
| echoR " -=> 2025-03-22 v0.7.3" " $VLATEST" | |
| echoY " 1.美化单栏菜单显示效果:左侧增加自定义Emoji表情" | |
| echoY " 2.美化系统信息显示效果" | |
| echoY " 3.修改双栏显示函数的调用方式,增加输入参数,控制显示效果" | |
| echoT "--------------------------------" | |
| echoR "" $(echoY "url") $(echoR ": $url_redir") | |
| echoR "" $(echoY "url") $(echoR ": $url_script") | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @echo off | |
| chcp 65001 >nul | |
| title Tool Menu | |
| setlocal enabledelayedexpansion | |
| :: 检测 winget 是否可用 | |
| where winget >nul 2>&1 | |
| if %errorlevel% neq 0 ( | |
| set USE_WINGET=0 | |
| ) else ( | |
| set USE_WINGET=1 | |
| ) | |
| :: 检测 choco 是否可用 | |
| where choco >nul 2>&1 | |
| if %errorlevel% neq 0 ( | |
| set USE_CHOCO=0 | |
| ) else ( | |
| set USE_CHOCO=1 | |
| ) | |
| :menu | |
| cls | |
| echo ================================== | |
| echo Tool Menu | |
| echo ================================== | |
| echo 1. Install Python (Select Version) | |
| echo 2. Install pipenv | |
| echo 3. Install PowerShell (Latest) | |
| echo 4. Set PowerShell Execution Policy | |
| echo 5. Install 7-Zip | |
| echo 6. Install Notepad++ | |
| echo 7. Install VS Code | |
| echo 8. Activate Windows/Office | |
| echo 0. Exit | |
| echo ================================== | |
| set /p choice=Enter your choice (1-8): | |
| if "%choice%"=="1" goto install_python | |
| if "%choice%"=="2" goto install_pipenv | |
| if "%choice%"=="3" goto install_powershell | |
| if "%choice%"=="4" goto set_ps_policy | |
| if "%choice%"=="5" goto install_7zip | |
| if "%choice%"=="6" goto install_notepadpp | |
| if "%choice%"=="7" goto install_vscode | |
| if "%choice%"=="0" exit | |
| echo Invalid input, please try again! | |
| pause | |
| goto menu | |
| :install_python | |
| cls | |
| echo ====================================== | |
| echo Python Installation | |
| echo ====================================== | |
| echo 1. Install Latest Version | |
| echo 2. Install Specific Version | |
| echo ====================================== | |
| set /p py_choice=Enter your choice (1-2): | |
| if "%py_choice%"=="1" ( | |
| echo Installing the latest Python version... | |
| if %USE_WINGET%==1 ( | |
| winget install Python.Python -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install python -y | |
| ) else ( | |
| echo Download and install manually: https://www.python.org/downloads/ | |
| start https://www.python.org/downloads/ | |
| ) | |
| pause | |
| goto menu | |
| ) | |
| if "%py_choice%"=="2" ( | |
| set /p py_version=Enter the Python version to install (e.g., 3.11.5): | |
| if "%py_version%"=="" ( | |
| echo Version cannot be empty, please try again! | |
| pause | |
| goto install_python | |
| ) | |
| echo Installing Python %py_version% ... | |
| if %USE_WINGET%==1 ( | |
| winget install Python.Python --version %py_version% -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install python --version %py_version% -y | |
| ) else ( | |
| echo Download and install manually: https://www.python.org/downloads/release/python-%py_version:/ | |
| start https://www.python.org/downloads/ | |
| ) | |
| pause | |
| goto menu | |
| ) | |
| echo Invalid input, please try again! | |
| pause | |
| goto install_python | |
| :install_pipenv | |
| echo Checking if Python is installed... | |
| python --version >nul 2>&1 | |
| if %errorlevel% neq 0 ( | |
| echo Python is not installed! Please install Python first. | |
| pause | |
| goto menu | |
| ) | |
| echo Installing pipenv... | |
| python -m pip install --upgrade pip | |
| python -m pip install pipenv | |
| echo pipenv installation completed! | |
| pause | |
| goto menu | |
| :install_powershell | |
| echo Installing the latest version of PowerShell... | |
| if %USE_WINGET%==1 ( | |
| winget install Microsoft.Powershell -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install powershell-core -y | |
| ) else ( | |
| echo Download and install manually: https://github.com/PowerShell/PowerShell/releases | |
| start https://github.com/PowerShell/PowerShell/releases | |
| ) | |
| pause | |
| goto menu | |
| :set_ps_policy | |
| echo Setting PowerShell execution policy to RemoteSigned... | |
| powershell -Command "Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force" | |
| echo Execution policy set successfully! | |
| pause | |
| goto menu | |
| :install_7zip | |
| echo Installing 7-Zip... | |
| if %USE_WINGET%==1 ( | |
| winget install 7zip.7zip -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install 7zip -y | |
| ) else ( | |
| echo Download and install manually: https://www.7-zip.org/download.html | |
| start https://www.7-zip.org/download.html | |
| ) | |
| pause | |
| goto menu | |
| :install_notepadpp | |
| echo Installing Notepad++... | |
| if %USE_WINGET%==1 ( | |
| winget install Notepad++.Notepad++ -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install notepadplusplus -y | |
| ) else ( | |
| echo Download and install manually: https://notepad-plus-plus.org/downloads/ | |
| start https://notepad-plus-plus.org/downloads/ | |
| ) | |
| pause | |
| goto menu | |
| :install_vscode | |
| echo Installing VS Code... | |
| if %USE_WINGET%==1 ( | |
| winget install Microsoft.VisualStudioCode -e | |
| ) else if %USE_CHOCO%==1 ( | |
| choco install vscode -y | |
| ) else ( | |
| echo Download and install manually: https://code.visualstudio.com/download | |
| start https://code.visualstudio.com/download | |
| ) | |
| pause | |
| goto menu |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #=============================================================================== | |
| # 作者:ZWDK | |
| # USAGE: | |
| # ps: > iwr https://qiq.zwdk.im/ps | iex | |
| # ps: > irm https://qiq.zwdk.im/ps | iex | |
| # cmd:> cmd /c "$(iwr https://qiq.zwdk.im/bat)" | |
| #=============================================================================== | |
| # 禁用进度条以提升下载速度 | |
| $ProgressPreference = 'SilentlyContinue' | |
| # 设置 PowerShell 输出编码,确保中文显示正常 | |
| [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 | |
| Clear-Host | |
| # 检测 winget 是否可用 | |
| $wingetAvailable = $false | |
| if (Get-Command winget -ErrorAction SilentlyContinue) { | |
| $wingetAvailable = $true | |
| } | |
| # 检测 choco 是否可用 | |
| $chocoAvailable = $false | |
| if (Get-Command choco -ErrorAction SilentlyContinue) { | |
| $chocoAvailable = $true | |
| } | |
| function Get-GitHubLatestRelease { | |
| <# | |
| .SYNOPSIS | |
| 自动下载 GitHub 仓库的最新发布版本 | |
| .DESCRIPTION | |
| 通过 GitHub API 获取指定仓库的最新发布版本,并根据当前系统自动匹配安装包 | |
| .PARAMETER RepositoryUrl | |
| GitHub 仓库地址(例如:https://github.com/PowerShell/PowerShell) | |
| .PARAMETER DownloadPath | |
| 文件保存路径(默认:用户临时目录) | |
| .PARAMETER FileNamePattern | |
| 使用正则表达式筛选资产文件(示例:"\.msi$|\.exe$") | |
| .PARAMETER ExcludePattern | |
| 排除文件的正则表达式(示例:"symbols|debug") | |
| .PARAMETER Proxy | |
| 代理服务器地址(示例:"http://proxy.example.com:8080") | |
| .EXAMPLE | |
| Get-GitHubLatestRelease -RepositoryUrl "https://github.com/PowerShell/PowerShell" | |
| .EXAMPLE | |
| Get-GitHubLatestRelease -RepositoryUrl "https://github.com/notepad-plus-plus/notepad-plus-plus" -FileNamePattern "\.exe$" | |
| .OUTPUTS | |
| System.IO.FileInfo (返回下载文件对象) | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [ValidatePattern("https?://github.com/.*")] | |
| [string]$RepositoryUrl, | |
| [string]$DownloadPath = $env:TEMP, | |
| [string]$FileNamePattern, | |
| [string]$ExcludePattern, | |
| [string]$Proxy | |
| ) | |
| begin { | |
| # 设置 TLS 1.2 避免连接问题 | |
| [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | |
| # 处理代理设置 | |
| if ($Proxy) { | |
| $webProxy = New-Object System.Net.WebProxy($Proxy, $true) | |
| $global:PSDefaultParameterValues["Invoke-RestMethod:Proxy"] = $webProxy | |
| } | |
| } | |
| process { | |
| try { | |
| # 转换仓库地址为 API 路径 | |
| $apiUrl = $RepositoryUrl -replace "https://github.com/", "https://api.github.com/repos/" -replace "/$", "" | |
| $apiUrl += "/releases/latest" | |
| # 获取发布信息 | |
| Write-Host "正在获取仓库发布信息..." -ForegroundColor Cyan | |
| $release = Invoke-RestMethod -Uri $apiUrl -Headers @{ | |
| "Accept" = "application/vnd.github.v3+json" | |
| } | |
| # 自动检测系统参数 | |
| $systemInfo = @{ | |
| OS = if ($env:OS -eq 'Windows_NT') { "win" } else { $PSVersionTable.OS.Split()[0].ToLower() } | |
| Arch = if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" } | |
| } | |
| # 构建智能匹配规则 | |
| $autoPattern = @{ | |
| win = @{ | |
| pattern = ".*(win|windows).*$($systemInfo.Arch).*(exe|msi|zip)$" | |
| priority = 1 | |
| } | |
| linux = @{ | |
| pattern = ".*(linux|ubuntu|debian).*$($systemInfo.Arch).*(deb|rpm|tar.gz)$" | |
| priority = 2 | |
| } | |
| darwin = @{ | |
| pattern = ".*(macos|osx|darwin).*(dmg|pkg|tar.gz)$" | |
| priority = 3 | |
| } | |
| } | |
| # 筛选可用资产 | |
| $assets = $release.assets | Sort-Object -Property @{ | |
| Expression = { $_.name -match ".*$($systemInfo.Arch).*" } | |
| Descending = $true | |
| } | |
| # 应用筛选条件 | |
| $selectedAsset = $assets | Where-Object { | |
| ($_.name -match $FileNamePattern) -or | |
| ($_.name -match $autoPattern[$systemInfo.OS].pattern) -and | |
| (-not ($_.name -match $ExcludePattern)) | |
| } | Sort-Object @{ | |
| Expression = { | |
| $score = 0 | |
| if ($_.name -match $autoPattern[$systemInfo.OS].pattern) { $score += 100 } | |
| if ($_.name -match $FileNamePattern) { $score += 50 } | |
| $score | |
| } | |
| Descending = $true | |
| } | Select-Object -First 1 | |
| if (-not $selectedAsset) { | |
| throw "未找到匹配的发布文件,可用文件列表:`n$($assets.name -join "`n")" | |
| } | |
| # 创建下载目录 | |
| $downloadDir = New-Item -Path (Join-Path $DownloadPath $release.tag_name) -ItemType Directory -Force | |
| # 下载文件 | |
| $localFile = Join-Path $downloadDir.FullName $selectedAsset.name | |
| Write-Host "正在下载 $($selectedAsset.name)..." -ForegroundColor Cyan | |
| Invoke-WebRequest -Uri $selectedAsset.browser_download_url -OutFile $localFile | |
| # 返回文件对象 | |
| Get-Item $localFile | |
| } | |
| catch [System.Net.WebException] { | |
| Write-Error "网络连接失败:$($_.Exception.Message)" | |
| } | |
| catch { | |
| Write-Error "操作失败:$($_.Exception.Message)" | |
| } | |
| finally { | |
| # 重置代理设置 | |
| if ($Proxy) { | |
| $global:PSDefaultParameterValues.Remove("Invoke-RestMethod:Proxy") | |
| } | |
| } | |
| } | |
| } | |
| # 统一安装软件逻辑 | |
| function Install-Software { | |
| param ( | |
| [string]$wingetName, | |
| [string]$chocoName, | |
| [string]$manualURL | |
| ) | |
| if ($wingetAvailable) { | |
| Write-Host "Using winget to install $wingetName..." | |
| winget install $wingetName -e | |
| } | |
| elseif ($chocoAvailable) { | |
| Write-Host "Using Chocolatey to install $chocoName..." | |
| choco install $chocoName -y | |
| } | |
| else { | |
| Write-Host "Download manually: $manualURL" -ForegroundColor Red | |
| Start-Process $manualURL | |
| } | |
| Pause | |
| } | |
| # 安装 Python(可选择版本) | |
| function Install-Python { | |
| while ($true) { | |
| Clear-Host | |
| Write-Host "========== Python Management ==========" -ForegroundColor Green | |
| Write-Host " 1. Install Latest Python" | |
| Write-Host " 2. Install Specific Python Version" | |
| Write-Host " 3. Install pipenv" | |
| Write-Host " 4. Set Python Pip Mirror" | |
| Write-Host " 0. Back to Main Menu" | |
| $py_choice = Read-Host "Enter your choice (1-5)" | |
| switch ($py_choice) { | |
| "1" { Install-Software "Python.Python" "python" "https://www.python.org/downloads/" } | |
| "2" { | |
| $py_version = Read-Host "Enter the Python version (e.g., 3.11.5)" | |
| Install-Software "Python.Python --version $py_version" "python --version $py_version" "https://www.python.org/downloads/release/python-$py_version/" | |
| } | |
| "3" { python -m pip install --upgrade pip; python -m pip install pipenv; Pause } | |
| "4" { Set-Pip-Mirror } | |
| "0" { return } | |
| default { Write-Host "Invalid input!" -ForegroundColor Red; Pause } | |
| } | |
| } | |
| } | |
| # 设置 pip 源 | |
| function Set-Pip-Mirror { | |
| Write-Host " 选择镜像: " | |
| Write-Host " 1. 阿里云" | |
| Write-Host " 2. 清华源" | |
| Write-Host " 3. 中科大" | |
| Write-Host " 4. 自定义" | |
| Write-Host " 0. 返回" | |
| $mirror_choice = Read-Host "Enter choice" | |
| $mirrorURL = switch ($mirror_choice) { | |
| "1" { "https://mirrors.aliyun.com/pypi/simple/" } | |
| "2" { "https://pypi.tuna.tsinghua.edu.cn/simple/" } | |
| "3" { "https://pypi.mirrors.ustc.edu.cn/simple/" } | |
| "4" { Read-Host "Enter custom pip mirror URL" } | |
| "0" { return } | |
| default { Write-Host "Invalid input"; return } | |
| } | |
| $pipConfigPath = "$env:USERPROFILE\pip\pip.ini" | |
| if (-not (Test-Path "$env:USERPROFILE\pip")) { | |
| New-Item -ItemType Directory -Path "$env:USERPROFILE\pip" -Force | |
| } | |
| @" | |
| [global] | |
| index-url = $mirrorURL | |
| "@ | Set-Content -Path $pipConfigPath -Encoding UTF8 | |
| Write-Host "Pip mirror set to: $mirrorURL" -ForegroundColor Green | |
| Pause | |
| } | |
| # 常用软件安装 | |
| function Software_install { | |
| while ($true) { | |
| Clear-Host | |
| Write-Host "====== Common Software Installation ======" -ForegroundColor Cyan | |
| Write-Host "1. Install 7-Zip" | |
| Write-Host "2. Install Notepad++" | |
| Write-Host "3. Install VS Code" | |
| Write-Host "0. Back to Main Menu" | |
| $soft_choice = Read-Host "Enter your choice (1-4)" | |
| switch ($soft_choice) { | |
| "1" { Install-Software "7zip.7zip" "7zip" "https://www.7-zip.org/download.html" } | |
| "2" { Install-Software "Notepad++.Notepad++" "notepadplusplus" "https://notepad-plus-plus.org/downloads/" } | |
| "3" { Install-Software "Microsoft.VisualStudioCode" "vscode" "https://code.visualstudio.com/download" } | |
| "0" { return } | |
| default { Write-Host "Invalid input!" -ForegroundColor Red; Pause } | |
| } | |
| } | |
| } | |
| # 系统设置 | |
| function System_Settings { | |
| while ($true) { | |
| Clear-Host | |
| Write-Host "======= System Settings =======" -ForegroundColor Yellow | |
| Write-Host "1. Set PowerShell Execution Policy" | |
| Write-Host "2. Enable OpenSSH Service" | |
| Write-Host "3. Set Default Shell to pwsh" | |
| Write-Host "0. Back to Main Menu" | |
| $sys_choice = Read-Host "Enter your choice (1-4)" | |
| switch ($sys_choice) { | |
| "1" { Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force; Write-Host "Execution policy set!"; Pause } | |
| "2" { Enable-OpenSSH } | |
| "3" { Set-DefaultShell-Pwsh } | |
| "0" { return } | |
| default { Write-Host "Invalid input!" -ForegroundColor Red; Pause } | |
| } | |
| } | |
| } | |
| # 启用 OpenSSH 服务 | |
| function Enable-OpenSSH { | |
| Write-Host "Enabling OpenSSH server..." | |
| Add-WindowsFeature -Name OpenSSH-Server | |
| Set-Service -Name sshd -StartupType Automatic | |
| Start-Service sshd | |
| Write-Host "OpenSSH is enabled!" -ForegroundColor Green | |
| Pause | |
| } | |
| # 设置 PowerShell 7 为默认 shell | |
| function Set-DefaultShell-Pwsh { | |
| if (Get-Command pwsh -ErrorAction SilentlyContinue) { | |
| $pwshPath = (Get-Command pwsh).Source | |
| New-ItemProperty -Path "HKCU:\Software\Microsoft\Command Processor" -Name "AutoRun" -Value "$pwshPath" -PropertyType String -Force | |
| Write-Host "Default shell set to PowerShell 7 (pwsh)." -ForegroundColor Green | |
| } else { | |
| Write-Host "PowerShell 7 is not installed! Install it first." -ForegroundColor Red | |
| } | |
| Pause | |
| } | |
| function download_all_software { | |
| "PowerShell", "git", "vscode" | ForEach-Object { | |
| Get-GitHubLatestRelease -RepositoryUrl "https://github.com/$_/$_" | |
| } | |
| } | |
| function get_download_path { | |
| param ([string]$sfld) | |
| # 获取脚本所在的目录路径 | |
| # $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent | |
| $scriptDir = $PWD.Path | |
| # 创建目标子目录 Apps(如果不存在) | |
| $targetDir = Join-Path -Path $scriptDir -ChildPath $sfld | |
| if (-not (Test-Path -Path $targetDir)) { | |
| New-Item -ItemType Directory -Path $targetDir | |
| } | |
| # 定义目标文件路径 | |
| # $targetFilePath = Join-Path -Path $targetDir -ChildPath "file.zip" | |
| return $targetDir | |
| } | |
| function app_download{ | |
| $sfld = 'Apps' | |
| $targetDir = get_download_path $sfld | |
| function Show_Menu_app_download { | |
| Clear-Host | |
| Write-Host "========== Download Menu ==========" -ForegroundColor Cyan | |
| Write-Host " 1. VC_redist.x64" -ForegroundColor Green | |
| Write-Host " 2. NekoBox 4.0.1" -ForegroundColor Yellow | |
| Write-Host " 3. Python 3.12.7" -ForegroundColor Blue | |
| Write-Host " 4. PowerShell" | |
| Write-Host " 5. Notepad++" | |
| Write-Host " 6. Hiddify" | |
| Write-Host " 7. VSCode" | |
| Write-Host " 8. 7zip" -ForegroundColor Green | |
| Write-Host " 9. All" | |
| Write-Host " 0. Exit" -ForegroundColor Red | |
| Write-Host "===============================" -ForegroundColor Cyan | |
| } | |
| function download_vc_redist64{ | |
| $file = "VC_redist.x64.exe" | |
| # $targetDir = get_download_path $sfld | |
| $targetFilePath = Join-Path -Path $targetDir -ChildPath $file | |
| $url_dl = "https://alist.ywzsqx.top/d/a/apps/$file" | |
| write-host "下载文件:$url_dl" | |
| write-host "目标目录:$targetDir" -ForegroundColor Cyan | |
| # Invoke-WebRequest -Uri $url_dl -OutFile $targetFilePath # | |
| Start-BitsTransfer -Source $url_dl -Destination $targetFilePath # 适合下载大文件或需要后台下载的场景 | |
| write-host "成功下载:$targetFilePath" -ForegroundColor Green | |
| } | |
| function download_nekobox{ | |
| $file = "nekoray-4.0.1-2024-12-12-windows64.zip" | |
| # $targetDir = get_download_path $sfld | |
| $targetFilePath = Join-Path -Path $targetDir -ChildPath $file | |
| $url_dl = "https://alist.ywzsqx.top/d/a/apps/$file" | |
| write-host "下载文件:$url_dl" | |
| write-host "目标目录:$targetDir" -ForegroundColor Cyan | |
| # Invoke-WebRequest -Uri $url_dl -OutFile $targetFilePath # | |
| Start-BitsTransfer -Source $url_dl -Destination $targetFilePath # 适合下载大文件或需要后台下载的场景 | |
| write-host "成功下载:$targetFilePath" -ForegroundColor Green | |
| } | |
| function download_python3127{ | |
| $file = "python-3.12.7-amd64.exe" | |
| # $targetDir = get_download_path $sfld | |
| $targetFilePath = Join-Path -Path $targetDir -ChildPath $file | |
| $url_dl = "https://alist.ywzsqx.top/d/a/apps/$file" | |
| write-host "下载文件:$url_dl" | |
| write-host "目标目录:$targetDir" -ForegroundColor Cyan | |
| # Invoke-WebRequest -Uri $url_dl -OutFile $targetFilePath # | |
| Start-BitsTransfer -Source $url_dl -Destination $targetFilePath # 适合下载大文件或需要后台下载的场景 | |
| write-host "成功下载:$targetFilePath" -ForegroundColor Green | |
| } | |
| function download_powershell{ | |
| $downloadedFile = Get-GitHubLatestRelease -RepositoryUrl "https://github.com/PowerShell/PowerShell" | |
| if ($downloadedFile) { | |
| Write-Host "下载完成!文件路径:" -ForegroundColor Green | |
| $downloadedFile.FullName | |
| } | |
| else { | |
| Write-Host "下载失败!" -ForegroundColor Red | |
| } | |
| } | |
| # 菜单循环 | |
| while ($true) { | |
| Show_Menu_app_download | |
| $choice = Read-Host " 请选择 (1-9)" | |
| switch ($choice) { | |
| "1" { download_vc_redist64; } | |
| "2" { download_nekobox; } | |
| "3" { download_python3127; } | |
| "4" { download_powershell; } | |
| "0" { exit } | |
| default { Write-Host "Invalid input!" -ForegroundColor Red; } | |
| } | |
| # Pause | |
| $null = Read-Host " 按 Enter 键继续 " | |
| } | |
| } | |
| function activate_win_office{ | |
| # > irm https://get.activated.win | iex | |
| Invoke-RestMethod "https://get.activated.win" | Invoke-Expression | |
| } | |
| function print_web_links{ | |
| Clear-Host | |
| Write-Host "========== Web Urls ============" -ForegroundColor Cyan | |
| Write-Host " 1. NekoBox : https://nekoray.net/" | |
| Write-Host " 2. VC_Redist : https://aka.ms/vs/17/release/vc_redist.x64.exe" | |
| Write-Host " 3. PowerShell: https://aka.ms/powershell-release?tag=stable" | |
| Write-Host " 4. Python : https://www.python.org/downloads/windows/" | |
| Write-Host " 5. Git : https://git-scm.com/downloads/win" | |
| Write-Host " 6. VSCode : https://code.visualstudio.com/Download" | |
| Write-Host " 7. Notepad++ : https://notepad-plus-plus.org/downloads/" | |
| # Write-Host " 0. Exit" -ForegroundColor Red | |
| Write-Host "===============================" -ForegroundColor Cyan | |
| } | |
| function main_menu { | |
| # 菜单界面 | |
| function Show-Menu { | |
| Clear-Host | |
| Write-Host "========== Tool Menu ==========" -ForegroundColor Cyan | |
| Write-Host " 1. 常用链接" | |
| Write-Host " 2. 下载软件" -ForegroundColor Green | |
| Write-Host " 3. 安装软件" | |
| Write-Host " 4. 系统设置" -ForegroundColor Yellow | |
| Write-Host " 5. 激活工具" -ForegroundColor Blue | |
| Write-Host " 6. Python管理" | |
| Write-Host " 0. 退出" -ForegroundColor Red | |
| Write-Host "===============================" -ForegroundColor Cyan | |
| } | |
| # 菜单循环 | |
| while ($true) { | |
| Show-Menu | |
| $choice = Read-Host "Enter your choice (1-4)" | |
| switch ($choice) { | |
| "1" { print_web_links; Pause } | |
| "2" { app_download } | |
| "3" { Software_install } | |
| "4" { System_Settings } | |
| "5" { activate_win_office } | |
| "6" { Install-Python } | |
| "0" { exit } | |
| default { Write-Host "Invalid input!" -ForegroundColor Red; Pause } | |
| } | |
| } | |
| } | |
| main_menu | |
| # # 使用示例 | |
| # $downloadedFile = Get-GitHubLatestRelease -RepositoryUrl "https://github.com/PowerShell/PowerShell" | |
| # if ($downloadedFile) { | |
| # Write-Host "下载完成!文件路径:" -ForegroundColor Green | |
| # $downloadedFile.FullName | |
| # } | |
| # 查找包含 Python 3.12 的 Windows 安装包 | |
| # Get-GitHubLatestRelease -RepositoryUrl "https://github.com/python/cpython" ` | |
| # -FileNamePattern "python-3\.12.*-win.*\.exe" | |
| # 排除测试版本 | |
| # Get-GitHubLatestRelease -RepositoryUrl "https://github.com/microsoft/vscode" ` | |
| # -ExcludePattern "insider|exploration" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| #======================================================== | |
| # System Required: CentOS 7+ | Debian 8+ | Ubuntu 16+ | Alpine 3+ | | |
| # Description: QiQ一键安装脚本 | |
| # GitHub : https://github.com/lmzxtek/qiqtools | |
| # GitCode: https://gitcode.com/lmzxtek/qiqtools | |
| # | |
| # 一键安装命令如下: | |
| # $> wget -qO qiqtools.sh https://sub.zwdk.org/qiq && chmod +x qiqtools.sh && ./qiqtools.sh | |
| # $> curl -sSL -o qiqtools.sh https://sub.zwdk.org/qiq && chmod +x qiqtools.sh && ./qiqtools.sh | |
| # $> wget -qN https://raw.gitcode.com/lmzxtek/qiqtools/raw/main/qiq.sh && chmod +x qiqtools.sh && ./qiqtools.sh | |
| # $> curl -sS -O https://raw.gitcode.com/lmzxtek/qiqtools/raw/main/qiq.sh && chmod +x qiqtools.sh && ./qiqtools.sh | |
| #======================================================== | |
| #==== 脚本版本号 =========== | |
| SRC_VER=v0.7.3 | |
| #========================== | |
| URL_PROXY='https://proxy.zwdk.org/proxy/' | |
| URL_REDIRECT='https://sub.zwdk.org/qiq' | |
| URL_SCRIPT='https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/src/qiq.sh' | |
| URL_UPDATE='https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/src/log.sh' | |
| # Emoji: 💡🧹🎉⚙️♻️🔧🛠️🏹💣🎯🧲🌍🌎🌏🌐🏡🏚️🏠🏯🗼🧭♨️💧📡👫 | |
| # 🐵🐒🐕🦍🫏🦒🦜🐔🐤🐓🦅🪿🐦⬛🐋🐬🪼🪲🌹🥀🌿🌱☘️🍓🍉 | |
| # Emoji: 😀😀😝😔🫨💥💯💤💫⭐🌟✨💦🛑⚓🎁🎀🏅🎖️🥇🥈🥉❗❕⚠️ | |
| # Emoji: 💔💖💝🩷❤️💗⛳🕹️🎨♥️♠️♣️♦️♟️🃏🔒🔓🔐🔏🔑🗝️ | |
| # 👌👍✌️👋👉👈👆👇👎✊👊🤛🤝👐👀👁️🦶🩸💊🩹 | |
| # ⚠️🚸⛔🚫🚳📵☣️☢️🔅🔆✖️➕➖➗🟰♾️⁉️❓❔💲♻️🔱⚜️📛⭕❌✔️☑️✅❎✳️❇️✴️ | |
| # 🔛🔚🔙🔜🔝⬆️⬇️⬅️➡️↖️↕️↗️↪️↙️↩️⤴️⤵️↔️🔄🔃 | |
| BOLD='\033[1m' | |
| PLAIN='\033[0m' | |
| RESET='\033[0m' | |
| WORKING="\033[1;36m✨️${PLAIN}" | |
| PRIGHT="\033[1;36m👉${PLAIN}" | |
| SUCCESS="\033[1;32m✅${PLAIN}" | |
| COMPLETE="\033[1;32m✔${PLAIN}" | |
| WARN="\033[1;36m⚠️${PLAIN}" | |
| ERROR="\033[1;31m✘${PLAIN}" | |
| FAIL="\033[1;31m✘${PLAIN}" | |
| TIP="\033[1;36m💡${PLAIN}" | |
| _TAG_DEFAULT="\033[1;36m🌿${PLAIN}" | |
| # 颜色定义:\033比\e的兼容性更好 | |
| BLACK='\033[30m' | |
| RED='\033[31m' | |
| GREEN='\033[32m' | |
| YELLOW='\033[33m' | |
| BLUE='\033[34m' | |
| PURPLE='\033[35m' | |
| MAGENTA='\033[35m' | |
| CYAN='\033[36m' | |
| AZURE='\033[36m' | |
| WHITE='\033[37m' | |
| DEFAULT='\033[39m' | |
| FCMR='\033[39m' # 前景色:默认 | |
| FCBL='\033[30m' # 前景色:黑色 | |
| FCRE='\033[31m' # 前景色:红色 | |
| FCGR='\033[32m' # 前景色:绿色 | |
| FCYE='\033[33m' # 前景色:黄色 | |
| FCLS='\033[34m' # 前景色:蓝色 | |
| FCZS='\033[35m' # 前景色:紫色 | |
| FCTL='\033[36m' # 前景色:天蓝 | |
| FCQH='\033[37m' # 前景色:白色|浅灰 | |
| FCSH='\033[90m' # 前景:深灰 | |
| FCHD='\033[91m' # 前景:红灯 | |
| FCLG='\033[92m' # 前景:浅绿 | |
| FCDH='\033[93m' # 前景:淡黄 | |
| FCLB='\033[94m' # 前景:浅蓝 | |
| FCYH='\033[95m' # 前景:浅洋红 | |
| FCQQ='\033[96m' # 前景:浅青色 | |
| FCBS='\033[97m' # 前景:白色 | |
| BCMR='\033[49m' # 背景色:默认 | |
| BCBL='\033[40m' # 背景色:黑色 | |
| BCRE='\033[41m' # 背景色:红色 | |
| BCGR='\033[42m' # 背景色:绿色 | |
| BCYE='\033[43m' # 背景色:黄色 | |
| BCLS='\033[44m' # 背景色:蓝色 | |
| BCZS='\033[45m' # 背景色:紫色 | |
| BCTL='\033[46m' # 背景色:天蓝 | |
| BCQH='\033[47m' # 背景色:白色|浅灰 | |
| BCSH='\033[100m' # 背景:深灰 | |
| BCHD='\033[101m' # 背景:红灯 | |
| BCLG='\033[102m' # 背景:浅绿 | |
| BCDH='\033[103m' # 背景:淡黄 | |
| BCLB='\033[104m' # 背景:浅蓝 | |
| BCYH='\033[105m' # 背景:浅洋红 | |
| BCQQ='\033[106m' # 背景:浅青色 | |
| BCBS='\033[107m' # 背景:白色 | |
| FTCZ='\033[0m' # 字体:重置所有 | |
| FTCT='\033[1m' # 字体:粗体 | |
| FTDH='\033[2m' # 字体:淡化 | |
| FTXT='\033[3m' # 字体:斜体 | |
| FTXH='\033[4m' # 字体:下划线 | |
| FTSS='\033[5m' # 字体:闪烁 | |
| FTFX='\033[7m' # 字体:反显 | |
| FTYC='\033[8m' # 字体:隐藏 | |
| FTHD='\033[9m' # 字体:划掉 | |
| FDCT='\033[21m' # 字体:取消粗体 | |
| FDDH='\033[22m' # 字体:取消淡化 | |
| FDXT='\033[23m' # 字体:取消斜体 | |
| FDXH='\033[24m' # 字体:取消下划线 | |
| FDSS='\033[25m' # 字体:取消闪烁 | |
| FDFX='\033[27m' # 字体:取消反显 | |
| FDYC='\033[28m' # 字体:取消隐藏 | |
| FDHD='\033[29m' # 字体:取消划掉 | |
| ## 报错退出 | |
| function output_error() { | |
| [ "$1" ] && echo -e "\n$ERROR $1\n" | |
| exit 1 | |
| } | |
| ## 权限判定 | |
| function permission_judgment() { | |
| if [ $UID -ne 0 ]; then | |
| output_error "权限不足,无法设置qiq快捷命令,请使用 Root 用户运行本脚本" | |
| fi | |
| } | |
| # 设置脚本的快捷命令为 `qiq` | |
| function set_qiq_alias() { | |
| local is_set=${1:-0} | |
| if [ $UID -ne 0 ]; then | |
| echo -e "\n$WARN 权限不足,请使用 Root 用户运行本脚本 \n" | |
| else | |
| if command -v qiq &>/dev/null; then | |
| echo -e "\n $WARN qiq快捷命令已设置: $(whereis qiq) \n" | |
| if [[ $is_set -eq 1 ]]; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否更新快捷命令?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="Y" | |
| if [[ $INPUT == [Yy] || $INPUT == [Yy][Ee][Ss] ]]; then | |
| rm -f /usr/local/bin/qiq | |
| ln -sf ~/qiq.sh /usr/local/bin/qiq | |
| fi | |
| fi | |
| else | |
| echo -e "\n $WARN qiq 快捷命令未设置 ... \n" | |
| ln -sf ~/qiq.sh /usr/local/bin/qiq | |
| fi | |
| fi | |
| } | |
| function del_qiq_alias(){ | |
| if [ $UID -ne 0 ]; then | |
| echo -e "\n$WARN 权限不足,请使用 Root 用户运行本脚本 \n" | |
| else | |
| if command -v qiq &>/dev/null; then | |
| rm -f /usr/local/bin/qiq | |
| echo -e "\n $WARN qiq 快捷命令已删除 ... \n" | |
| else | |
| echo -e "\n $WARN qiq 快捷命令未设置 ... \n" | |
| fi | |
| fi | |
| } | |
| # 定义颜色渐变函数,返回带颜色的字符串 | |
| function gradient_text() { | |
| local text=$1 | |
| local gradient=("${!2}") # 获取颜色渐变数组 | |
| local length=${#text} | |
| local result="" | |
| for ((i = 0; i < length; i++)); do | |
| char=${text:i:1} | |
| color_code=${gradient[$((i % ${#gradient[@]}))]} | |
| result+=$(echo -en "\033[38;5;${color_code}m${char}\033[0m") | |
| done | |
| echo "$result" | |
| } | |
| function init_global_vars(){ | |
| blue_green_gradient=("118" "154" "82" "34" "36" "46" ) # 蓝色到绿色的渐变颜色代码 | |
| CONSTSTR='QiQ Tools' | |
| CONSTSTR=$(gradient_text "${CONSTSTR}" blue_green_gradient[@]) | |
| NUM_SPLIT=${NUM_SPLIT:-4} # 左右栏的宽度间隔 | |
| NUM_WIDTH=${NUM_WIDTH:-3} # 序号最大宽度 | |
| MAX_COL_NUM=${MAX_COL_NUM:-24} # 单栏字符串最大宽度,默认为24 | |
| ITEM_CAT_CHAR=${ITEM_CAT_CHAR:-'.'} # 序号与字符连接字符,默认为 '.' | |
| MAX_SPLIT_CHAR_NUM=${MAX_SPLIT_CHAR_NUM:-35} # 最大分割字符数量,默认为35 | |
| } | |
| ## 定义系统判定变量 | |
| SYSTEM_DEBIAN="Debian" | |
| SYSTEM_UBUNTU="Ubuntu" | |
| SYSTEM_KALI="Kali" | |
| SYSTEM_DEEPIN="Deepin" | |
| SYSTEM_LINUX_MINT="Linuxmint" | |
| SYSTEM_ZORIN="Zorin" | |
| SYSTEM_REDHAT="RedHat" | |
| SYSTEM_RHEL="Red Hat Enterprise Linux" | |
| SYSTEM_CENTOS="CentOS" | |
| SYSTEM_CENTOS_STREAM="CentOS Stream" | |
| SYSTEM_ROCKY="Rocky" | |
| SYSTEM_ALMALINUX="AlmaLinux" | |
| SYSTEM_FEDORA="Fedora" | |
| SYSTEM_OPENCLOUDOS="OpenCloudOS" | |
| SYSTEM_OPENCLOUDOS_STREAM="OpenCloudOS Stream" | |
| SYSTEM_OPENEULER="openEuler" | |
| SYSTEM_ANOLISOS="Anolis" | |
| SYSTEM_OPENKYLIN="openKylin" | |
| SYSTEM_OPENSUSE="openSUSE" | |
| SYSTEM_ARCH="Arch" | |
| SYSTEM_ALPINE="Alpine" | |
| SYSTEM_GENTOO="Gentoo" | |
| SYSTEM_NIXOS="NixOS" | |
| ## 定义系统版本文件 | |
| File_LinuxRelease=/etc/os-release | |
| File_RedHatRelease=/etc/redhat-release | |
| File_DebianVersion=/etc/debian_version | |
| File_ArmbianRelease=/etc/armbian-release | |
| File_openEulerRelease=/etc/openEuler-release | |
| File_OpenCloudOSRelease=/etc/opencloudos-release | |
| File_AnolisOSRelease=/etc/anolis-release | |
| File_OracleLinuxRelease=/etc/oracle-release | |
| File_ArchLinuxRelease=/etc/arch-release | |
| File_AlpineRelease=/etc/alpine-release | |
| File_GentooRelease=/etc/gentoo-release | |
| File_openKylinVersion=/etc/kylin-version/kylin-system-version.conf | |
| File_ProxmoxVersion=/etc/pve/.version | |
| ## 收集系统信息 | |
| function collect_system_info() { | |
| ## 定义系统名称 | |
| SYSTEM_NAME="$(cat $File_LinuxRelease | grep -E "^NAME=" | awk -F '=' '{print$2}' | sed "s/[\'\"]//g")" | |
| grep -q "PRETTY_NAME=" $File_LinuxRelease && SYSTEM_PRETTY_NAME="$(cat $File_LinuxRelease | grep -E "^PRETTY_NAME=" | awk -F '=' '{print$2}' | sed "s/[\'\"]//g")" | |
| ## 定义系统版本号 | |
| SYSTEM_VERSION_NUMBER="$(cat $File_LinuxRelease | grep -E "^VERSION_ID=" | awk -F '=' '{print$2}' | sed "s/[\'\"]//g")" | |
| SYSTEM_VERSION_NUMBER_MAJOR="${SYSTEM_VERSION_NUMBER%.*}" | |
| SYSTEM_VERSION_NUMBER_MINOR="${SYSTEM_VERSION_NUMBER#*.}" | |
| ## 定义系统ID | |
| SYSTEM_ID="$(cat $File_LinuxRelease | grep -E "^ID=" | awk -F '=' '{print$2}' | sed "s/[\'\"]//g")" | |
| ## 判定当前系统派系 | |
| if [ -s $File_DebianVersion ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_DEBIAN}" | |
| elif [ -s $File_OracleLinuxRelease ]; then | |
| # output_error "当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| echo -e "$ERROR 当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| elif [ -s $File_RedHatRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_REDHAT}" | |
| elif [ -s $File_openEulerRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_OPENEULER}" | |
| elif [ -s $File_OpenCloudOSRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_OPENCLOUDOS}" # 自 9.0 版本起不再基于红帽 | |
| elif [ -s $File_AnolisOSRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_ANOLISOS}" # 自 8.8 版本起不再基于红帽 | |
| elif [ -s $File_openKylinVersion ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_OPENKYLIN}" | |
| elif [ -f $File_ArchLinuxRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_ARCH}" | |
| elif [ -f $File_AlpineRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_ALPINE}" | |
| elif [ -f $File_GentooRelease ]; then | |
| SYSTEM_FACTIONS="${SYSTEM_GENTOO}" | |
| elif [[ "${SYSTEM_NAME}" == *"openSUSE"* ]]; then | |
| SYSTEM_FACTIONS="${SYSTEM_OPENSUSE}" | |
| elif [[ "${SYSTEM_NAME}" == *"NixOS"* ]]; then | |
| SYSTEM_FACTIONS="${SYSTEM_NIXOS}" | |
| else | |
| # output_error "当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| echo -e "$ERROR 当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| fi | |
| ## 判定系统类型、版本、版本号 | |
| case "${SYSTEM_FACTIONS}" in | |
| "${SYSTEM_DEBIAN}" | "${SYSTEM_OPENKYLIN}") | |
| local os_info=$(lsb_release -ds 2>/dev/null) | |
| if [ -z "$os_info" ]; then | |
| # 检查常见的发行文件 | |
| if [ -f "/etc/os-release" ]; then | |
| os_info=$(source /etc/os-release && echo "$PRETTY_NAME") | |
| elif [ -f "/etc/debian_version" ]; then | |
| os_info="Debian $(cat /etc/debian_version)" | |
| elif [ -f "/etc/redhat-release" ]; then | |
| os_info=$(cat /etc/redhat-release) | |
| else | |
| os_info="Unknown" | |
| fi | |
| SYSTEM_JUDGMENT="${os_info}" | |
| SYSTEM_VERSION_CODENAME="${os_info}" | |
| else | |
| SYSTEM_JUDGMENT="$(lsb_release -is)" | |
| SYSTEM_VERSION_CODENAME="${DEBIAN_CODENAME:-"$(lsb_release -cs)"}" | |
| fi | |
| # if [ ! -x /usr/bin/lsb_release ]; then | |
| # apt-get install -y lsb-release | |
| # if [ $? -ne 0 ]; then | |
| # # output_error "lsb-release 软件包安装失败\n\n本脚本依赖 lsb_release 指令判断系统具体类型和版本,当前系统可能为精简安装,请自行安装后重新执行脚本!" | |
| # echo -e "$ERROR lsb-release 软件包安装失败\n\n本脚本依赖 lsb_release 指令判断系统具体类型和版本,当前系统可能为精简安装,请自行安装后重新执行脚本!" | |
| # fi | |
| # fi | |
| ;; | |
| "${SYSTEM_REDHAT}") | |
| SYSTEM_JUDGMENT="$(awk '{printf $1}' $File_RedHatRelease)" | |
| ## 特殊系统判断 | |
| # Red Hat Enterprise Linux | |
| grep -q "${SYSTEM_RHEL}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_RHEL}" | |
| # CentOS Stream | |
| grep -q "${SYSTEM_CENTOS_STREAM}" $File_RedHatRelease && SYSTEM_JUDGMENT="${SYSTEM_CENTOS_STREAM}" | |
| ;; | |
| *) | |
| SYSTEM_JUDGMENT="${SYSTEM_FACTIONS}" | |
| ;; | |
| esac | |
| ## 判断系统及版本是否适配 | |
| local is_supported="true" | |
| case "${SYSTEM_JUDGMENT}" in | |
| "${SYSTEM_DEBIAN}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" -lt 8 || "${SYSTEM_VERSION_NUMBER_MAJOR}" -gt 13 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_UBUNTU}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" -lt 14 || "${SYSTEM_VERSION_NUMBER_MAJOR}" -gt 24 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_LINUX_MINT}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 19 && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 2[0-2] && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 6 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_RHEL}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [7-9] ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_CENTOS}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [7-8] ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_CENTOS_STREAM}" | "${SYSTEM_ROCKY}" | "${SYSTEM_ALMALINUX}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [8-9] ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_FEDORA}") | |
| if [[ "${SYSTEM_VERSION_NUMBER}" != [3-4][0-9] ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_OPENEULER}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 2[1-4] ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_OPENCLOUDOS}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != [8-9] && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 23 ]] || [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" == 8 && "$SYSTEM_VERSION_NUMBER_MINOR" -lt 6 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_ANOLISOS}") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 8 && "${SYSTEM_VERSION_NUMBER_MAJOR}" != 23 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "${SYSTEM_OPENSUSE}") | |
| case "${SYSTEM_ID}" in | |
| "opensuse-leap") | |
| if [[ "${SYSTEM_VERSION_NUMBER_MAJOR}" != 15 ]]; then | |
| is_supported="false" | |
| fi | |
| ;; | |
| "opensuse-tumbleweed") ;; | |
| *) | |
| is_supported="false" | |
| ;; | |
| esac | |
| ;; | |
| "${SYSTEM_KALI}" | "${SYSTEM_DEEPIN}" | "${SYSTEM_ZORIN}" | "${SYSTEM_ARCH}" | "${SYSTEM_ALPINE}" | "${SYSTEM_GENTOO}" | "${SYSTEM_OPENKYLIN}" | "${SYSTEM_NIXOS}") | |
| # 理论全部支持或不作判断 | |
| ;; | |
| *) | |
| # output_error "当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| echo -e "$ERROR 当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| ;; | |
| esac | |
| if [[ "${is_supported}" == "false" ]]; then | |
| # output_error "当前系统版本不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| echo -e "$ERROR 当前操作系统不在本脚本的支持范围内,请前往官网查看支持列表!" | |
| fi | |
| ## 判定系统处理器架构 | |
| case "$(uname -m)" in | |
| x86_64) | |
| DEVICE_ARCH="x86_64" | |
| ;; | |
| aarch64) | |
| DEVICE_ARCH="ARM64" | |
| ;; | |
| armv7l) | |
| DEVICE_ARCH="ARMv7" | |
| ;; | |
| armv6l) | |
| DEVICE_ARCH="ARMv6" | |
| ;; | |
| i686) | |
| DEVICE_ARCH="x86_32" | |
| ;; | |
| *) | |
| DEVICE_ARCH="$(uname -m)" | |
| ;; | |
| esac | |
| ## 定义软件源仓库名称 | |
| if [[ -z "${SOURCE_BRANCH}" ]]; then | |
| ## 默认为系统名称小写,替换空格 | |
| SOURCE_BRANCH="${SYSTEM_JUDGMENT,,}" | |
| SOURCE_BRANCH="${SOURCE_BRANCH// /-}" | |
| ## 处理特殊的仓库名称 | |
| case "${SYSTEM_JUDGMENT}" in | |
| "${SYSTEM_DEBIAN}") | |
| case "${SYSTEM_VERSION_NUMBER_MAJOR}" in | |
| 8 | 9 | 10) | |
| SOURCE_BRANCH="debian-archive" # EOF | |
| ;; | |
| *) | |
| SOURCE_BRANCH="debian" | |
| ;; | |
| esac | |
| ;; | |
| "${SYSTEM_UBUNTU}" | "${SYSTEM_ZORIN}") | |
| if [[ "${DEVICE_ARCH}" == "x86_64" || "${DEVICE_ARCH}" == *i?86* ]]; then | |
| SOURCE_BRANCH="ubuntu" | |
| else | |
| SOURCE_BRANCH="ubuntu-ports" | |
| fi | |
| ;; | |
| "${SYSTEM_RHEL}") | |
| case "${SYSTEM_VERSION_NUMBER_MAJOR}" in | |
| 9) | |
| SOURCE_BRANCH="centos-stream" # 使用 CentOS Stream 仓库 | |
| ;; | |
| *) | |
| SOURCE_BRANCH="centos-vault" # EOF | |
| ;; | |
| esac | |
| ;; | |
| "${SYSTEM_CENTOS}") | |
| if [[ "${DEVICE_ARCH}" == "x86_64" ]]; then | |
| SOURCE_BRANCH="centos-vault" # EOF | |
| else | |
| SOURCE_BRANCH="centos-altarch" | |
| fi | |
| ;; | |
| "${SYSTEM_CENTOS_STREAM}") | |
| # 自 CentOS Stream 9 开始使用 centos-stream 仓库,旧版本使用 centos 仓库 | |
| case "${SYSTEM_VERSION_NUMBER_MAJOR}" in | |
| 8) | |
| if [[ "${DEVICE_ARCH}" == "x86_64" ]]; then | |
| SOURCE_BRANCH="centos-vault" # EOF | |
| else | |
| SOURCE_BRANCH="centos-altarch" | |
| fi | |
| ;; | |
| *) | |
| SOURCE_BRANCH="centos-stream" | |
| ;; | |
| esac | |
| ;; | |
| "${SYSTEM_FEDORA}") | |
| if [[ "${SYSTEM_VERSION_NUMBER}" -lt 39 ]]; then | |
| SOURCE_BRANCH="fedora-archive" | |
| fi | |
| ;; | |
| "${SYSTEM_ARCH}") | |
| if [[ "${DEVICE_ARCH}" == "x86_64" || "${DEVICE_ARCH}" == *i?86* ]]; then | |
| SOURCE_BRANCH="archlinux" | |
| else | |
| SOURCE_BRANCH="archlinuxarm" | |
| fi | |
| ;; | |
| "${SYSTEM_OPENCLOUDOS}") | |
| # OpenCloudOS Stream | |
| grep -q "${SYSTEM_OPENCLOUDOS_STREAM}" $File_OpenCloudOSRelease | |
| if [ $? -eq 0 ]; then | |
| SOURCE_BRANCH="${SYSTEM_OPENCLOUDOS_STREAM,,}" | |
| SOURCE_BRANCH="${SOURCE_BRANCH// /-}" | |
| fi | |
| ;; | |
| "${SYSTEM_NIXOS}") | |
| SOURCE_BRANCH="nix-channels" | |
| ;; | |
| esac | |
| fi | |
| ## 定义软件源更新文字 | |
| case "${SYSTEM_FACTIONS}" in | |
| "${SYSTEM_DEBIAN}" | "${SYSTEM_ALPINE}" | "${SYSTEM_OPENKYLIN}") | |
| SYNC_MIRROR_TEXT="更新软件源" | |
| ;; | |
| "${SYSTEM_REDHAT}" | "${SYSTEM_OPENEULER}" | "${SYSTEM_OPENCLOUDOS}" | "${SYSTEM_ANOLISOS}") | |
| SYNC_MIRROR_TEXT="生成软件源缓存" | |
| ;; | |
| "${SYSTEM_OPENSUSE}") | |
| SYNC_MIRROR_TEXT="刷新软件源" | |
| ;; | |
| "${SYSTEM_ARCH}" | "${SYSTEM_GENTOO}") | |
| SYNC_MIRROR_TEXT="同步软件源" | |
| ;; | |
| "${SYSTEM_NIXOS}") | |
| SYNC_MIRROR_TEXT="更新二进制缓存与频道源" | |
| ;; | |
| esac | |
| ## 判断是否可以使用高级交互式选择器 | |
| CAN_USE_ADVANCED_INTERACTIVE_SELECTION="false" | |
| if [ ! -z "$(command -v tput)" ]; then | |
| CAN_USE_ADVANCED_INTERACTIVE_SELECTION="true" | |
| fi | |
| } | |
| ## 计算输入字符串字符数量,检测中文字符和Emoji字符 | |
| function str_width_awk() { | |
| echo -n "$1" | awk '{ | |
| len=0 | |
| for (i=1; i<=length($0); i++) { | |
| c=substr($0, i, 1) | |
| if (c ~ /[一-龥]/) { len+=2 } # 处理中文全角字符 | |
| else if (c ~ /[\x{1F600}-\x{1F64F}]/) { len+=2 } # 处理Emoji | |
| else { len+=1 } | |
| } | |
| print len | |
| }' | |
| } | |
| function get_split_list() { | |
| local items=("${@}") | |
| local result=() | |
| # local length=0 | |
| for i in "${!items[@]}"; do | |
| # length=${#items[i]} | |
| if [[ ! "${items[i]}" =~ ^[0-9] ]]; then # 只要不是数字开头的项,就作为分割线 | |
| result+=("$i") # 记录分隔符的位置索引 | |
| fi | |
| done | |
| echo "${result[@]}" # 输出所有分割线的位置索引 | |
| } | |
| # 生成重复字符的分割行,并应用颜色 | |
| function generate_separator() { | |
| local separator_info="$1" | |
| local count=${2:-$MAX_SPLIT_CHAR_NUM} | |
| # 解析分割符和颜色 | |
| IFS='|' read -r separator color <<< "$separator_info" | |
| # 颜色默认值(如果未提供颜色) | |
| color=${color:-$RESET} | |
| local first_char="${separator:0:1}" # 取分割符的第一个字符 | |
| # 颜色化输出分割线 | |
| echo -e "${color}$(printf "%0.s$first_char" $(seq 1 "$count"))${RESET}" | |
| } | |
| function fill_array() { | |
| local -n arr=$1 # 使用命名引用传递数组 | |
| local num=${2:-5} # 默认填充5个空字符串 | |
| local length=${#arr[@]} | |
| if (( length < num )); then | |
| for ((i=length; i<length+length; i++)); do | |
| arr[i]="" | |
| done | |
| fi | |
| } | |
| ## 菜单项按1栏显示 | |
| function print_sub_items_1() { | |
| # local items=("${@}") | |
| local items=("${!1}") # 传入数组 | |
| # local ncol=${2:-$MAX_COL_NUM} # | |
| local total_items=${#items[@]} | |
| for ((i=0; i<total_items; i++)); do | |
| local left_item=${items[i]} | |
| # 解析左栏 | |
| IFS='|' read -r nn txt cc <<< "$left_item" | |
| cc=${cc:-$RESET} # 默认颜色 | |
| local txt_fmt="${cc}${ITEM_CAT_CHAR}${txt}${RESET}" | |
| printf "%${NUM_WIDTH}d%-b\n" $nn "$txt_fmt" | |
| # printf "%${NUM_WIDTH}d%-${ncol}b\n" $nn "$l_formatted" | |
| done | |
| } | |
| ## 菜单项按2栏显示 | |
| function print_sub_items_2() { | |
| # local items=("${@}") | |
| local items=("${!1}") # 传入数组 | |
| local ncol=${2:-$MAX_COL_NUM} # | |
| local total_items=${#items[@]} | |
| local half=$(( (total_items + 1) / 2 )) # 计算左右分栏 | |
| for ((i=0; i<half; i++)); do | |
| local left_item=${items[i]} | |
| local right_index=$((i + half)) | |
| local right_item=${items[right_index]:-} # 可能为空 | |
| # 解析左栏 | |
| IFS='|' read -r l_num l_text l_color <<< "$left_item" | |
| l_color=${l_color:-$RESET} # 默认颜色 | |
| local l_formatted="${l_color}${ITEM_CAT_CHAR}$l_text$RESET" | |
| # 计算中文字符数量 | |
| chinese_left=$(echo -n "$l_formatted" | grep -oP '[\p{Han}]' | wc -l) | |
| # 计算Emoji数量 | |
| emoji_count=$(echo -n "$l_formatted" | grep -oP "[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}]" | wc -l) | |
| adj_left_width=$((ncol + chinese_left + emoji_count)) | |
| # adj_split_num=$((NUM_SPLIT - chinese_left - emoji_count )) | |
| if [[ $adj_split_num -lt 0 ]]; then | |
| adj_split_num=0 | |
| fi | |
| # 解析右栏(如果有的话) | |
| if [ -n "$right_item" ]; then | |
| IFS='|' read -r r_num r_text r_color <<< "$right_item" | |
| r_color=${r_color:-$RESET} # 默认颜色 | |
| local r_formatted="${r_color}${ITEM_CAT_CHAR}$r_text$RESET" | |
| printf "%${NUM_WIDTH}d%-${adj_left_width}b%${adj_split_num}s%${NUM_WIDTH}d%-${ncol}b\n" \ | |
| $l_num "$l_formatted" "" $r_num "$r_formatted" | |
| else | |
| local r_formatted="" | |
| printf "%${NUM_WIDTH}d%-${adj_left_width}b\n" $l_num "$l_formatted" | |
| fi | |
| done | |
| } | |
| ## 输出数组列表 | |
| function print_items_list(){ | |
| local items=("${!1}") # 传入数组 | |
| local head="$2" | |
| # local tagd="${3:-${PRIGHT}}" | |
| # clear | |
| [[ -n ${head} ]] && echo -e "\n${BOLD}${head}: \n${PLAIN}" | |
| for option in "${items[@]}"; do | |
| IFS='|' read -r l_text l_color tag <<< "$option" | |
| l_color=${l_color:-$RESET} # 默认颜色 | |
| tag=${tag:-$_TAG_DEFAULT} # 默认标识符 | |
| echo -e "${tag} ${l_color}${l_text}${RESET}" | |
| done | |
| } | |
| # 根据分割位置拆分数组,并用 n 个分割符号替换原始分割线 | |
| function split_menu_items() { | |
| local items=("${!1}") # 传入数组 | |
| local is2check=${2:-1} # 是否检测元数个数: 当元素个数小于5时单栏显示,否则双栏显示 | |
| local ncol=${3:-$MAX_COL_NUM} # 双栏最大宽度, | |
| local nmin_items=${4:-5} # 双栏最小元素 | |
| # local nsp=${4:-$MAX_SPLIT_CHAR_NUM} # 分割符宽度, | |
| local nsp=$(( $ncol * 1 + $NUM_SPLIT * 3 )) | |
| # nsp=$(( $ncol * 2 + $NUM_SPLIT )) | |
| local split_indices=($(get_split_list "${items[@]}")) | |
| local sub_list=() | |
| local start=0 | |
| for split in "${split_indices[@]}"; do | |
| # 取出当前子列表 | |
| sub_list=("${items[@]:start:split-start}") | |
| local length=${#sub_list[@]} | |
| if [[ ${is2check} -eq 1 && length -lt ${nmin_items} ]] ; then | |
| # print_items_list sub_list[@] '' '' | |
| print_sub_items_1 sub_list[@] | |
| else | |
| # print_sub_items "${sub_list[@]}" | |
| print_sub_items_2 sub_list[@] $ncol | |
| fi | |
| # 生成新的分割行 | |
| generate_separator "${items[split]}" "$nsp" | |
| start=$((split + 1)) | |
| done | |
| # 处理最后一部分(如果还有剩余项) | |
| if [[ $start -lt ${#items[@]} ]]; then | |
| sub_list=("${items[@]:start}") | |
| local length=${#sub_list[@]} | |
| if [[ ${is2check} -eq 1 && length -lt ${nmin_items} ]] ; then | |
| # print_items_list sub_list[@] '' '' | |
| print_sub_items_1 sub_list[@] | |
| else | |
| print_sub_items_2 sub_list[@] $ncol | |
| fi | |
| fi | |
| } | |
| function check_ip_command() { | |
| if ! command -v ip &> /dev/null; then | |
| echo -e "$WARN 'ip' command not found. Attempting to install iproute2 package...\n" | |
| if command -v apt-get &> /dev/null; then | |
| # Debian/Ubuntu | |
| sudo apt-get update | |
| sudo apt-get install -y iproute2 | |
| elif command -v yum &> /dev/null; then | |
| # CentOS/RHEL | |
| sudo yum install -y iproute | |
| elif command -v dnf &> /dev/null; then | |
| # Fedora | |
| sudo dnf install -y iproute | |
| else | |
| echo -e "$ERROR Could not determine package manager. Please install iproute2 manually.\n" | |
| exit 1 | |
| fi | |
| if ! command -v ip &> /dev/null; then | |
| echo -e "$ERROR Failed to install 'ip' command. Please install iproute2 manually.\n" | |
| exit 1 | |
| else | |
| echo -e "$SUCCESS 'ip' command installed successfully.\n" | |
| fi | |
| fi | |
| } | |
| function check_ip_support() { | |
| # 检查IPv4支持 | |
| if ip -4 addr show | grep -q "inet "; then | |
| export IPV4_SUPPORTED=1 | |
| else | |
| export IPV4_SUPPORTED=0 | |
| fi | |
| # 检查IPv6支持 | |
| if ip -6 addr show | grep -q "inet6 "; then | |
| export IPV6_SUPPORTED=1 | |
| else | |
| export IPV6_SUPPORTED=0 | |
| fi | |
| } | |
| function check_warp_status() { | |
| local ip_version=$1 | |
| if [[ "$ip_version" -ne 4 && "$ip_version" -ne 6 ]]; then | |
| echo -e "\n$WARN Invalid IP version. Please use 4 or 6!" | |
| return 1 | |
| fi | |
| if [[ IPV${ip_version}_SUPPORTED -eq 0 ]]; then | |
| echo -e "$WARN IPv${ip_version} is not supported!" | |
| return 1 | |
| fi | |
| echo -e " $WORKING Check warp status for IPv${ip_version} ..." | |
| url="https://www.cloudflare.com/cdn-cgi/trace" | |
| response=$(curl -${ip_version} -sS --retry 2 --max-time 1 "$url") | |
| if [[ -z "$response" ]]; then | |
| echo -e "${WARN} Failed to check warp for IPv${ip_version} from cloudflare.com \n" | |
| return 1 | |
| fi | |
| local location_ip=$( echo -e "$response" | grep "loc=" | awk -F= '{print $2}') | |
| local warp_status=$( echo -e "$response" | grep "warp=" | awk -F= '{print $2}') | |
| [[ -n "$location_ip" ]] && export WARP_LOC${ip_version}=${location_ip} | |
| # 设置全局变量 | |
| if [[ "$warp_status" =~ ^on$ ]] ; then | |
| # export WARP${ip_version}=$(echo -e "${location_ip}, ${RED}Warp${PLAIN}") | |
| export WARPSTATUS${ip_version}=1 | |
| else | |
| # export WARP${ip_version}=$(echo -e ${location_ip}) | |
| export WARPSTATUS${ip_version}=0 | |
| fi | |
| } | |
| function check_ip_china() { | |
| local country=$(curl -s --connect-timeout 1 --max-time 3 ipinfo.io/country) | |
| if [ "$country" = "CN" ]; then | |
| _IS_CN=1 | |
| else | |
| _IS_CN=0 | |
| fi | |
| } | |
| ## 判断IP所在地,给url设置代理 | |
| function get_proxy_url() { | |
| local url="$1" | |
| check_ip_china | |
| [[ $_IS_CN -eq 1 ]] && url="${URL_PROXY}${url}" | |
| echo "$url" | |
| } | |
| ## 下载脚本并修改可执行权限 | |
| function fetch_script_from_url() { | |
| local url="$1" | |
| local file="$2" | |
| local is_proxy=${3:-1} | |
| [[ $is_proxy -eq 1 ]] && url=$(get_proxy_url "$url") | |
| if command -v curl &>/dev/null; then | |
| curl -L -o ${file} "${url}" && chmod +x ${file} && bash ${file} | |
| elif command -v wget &>/dev/null; then | |
| wget -O ${file} ${url} && chmod +x ${file} && bash ${file} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| fi | |
| } | |
| function print_warp_ip_info() { | |
| local ip_version=$1 | |
| local result="" | |
| if [ "$ip_version" -eq 4 ]; then | |
| local result="${GREEN}IPv4${PLAIN}: $WAN4 ${PURPLE}$WARP_LOC4${PLAIN}" | |
| elif [ "$ip_version" -eq 6 ]; then | |
| local result="${GREEN}IPv6${PLAIN}: $WAN6 ${PURPLE}$WARP_LOC6${PLAIN}" | |
| else | |
| echo -e " $WARN Invalid ip version. Please enter 4 or 6." | |
| return 1 | |
| fi | |
| result=$(echo -en "${result}") | |
| [[ WARPSTATUS${ip_version} -eq 1 ]] && result+=$(echo -en ", ${RED}warp${PLAIN}") | |
| echo "$result" | |
| } | |
| function get_ip_info() { | |
| local ip_version=$1 | |
| if [[ "$ip_version" -ne 4 && "$ip_version" -ne 6 ]]; then | |
| echo -e "\n$WARN Invalid IP version. Please use 4 or 6!" | |
| return 1 | |
| fi | |
| if [[ IPV${ip_version}_SUPPORTED -eq 0 ]]; then | |
| echo -e "$WARN IPv${ip_version} is not supported!" | |
| return 1 | |
| fi | |
| echo -e " $WORKING Check IPv${ip_version} information ..." | |
| local url | |
| local response | |
| local loc_ip | |
| local loc_country | |
| local loc_asn local loc_asn_org | |
| local ip_info | |
| url="https://ifconfig.co/json" | |
| response=$(curl -${ip_version} -sS --retry 2 --max-time 1 "$url") | |
| if [[ -z "$response" ]]; then | |
| echo -e "${WARN} Failed to fetch IPv${ip_version} information from ifconfig.co \n" | |
| return 1 | |
| fi | |
| # loc_ip=$(echo "$response" | jq -r '.ip') | |
| # loc_country=$(echo "$response" | jq -r '.country') | |
| # loc_asn=$(echo "$response" | jq -r '.asn') | |
| # loc_asn_org=$(echo "$response" | jq -r '.asn_org') | |
| loc_ip=$(echo "$response" | grep -o '"ip": *"[^"]*"' | awk -F': ' '{print $2}' | tr -d '"') | |
| loc_asn=$(echo "$response" | grep -o '"asn": *"[^"]*"' | awk -F': ' '{print $2}' | tr -d '"') | |
| loc_asn_org=$(echo "$response" | grep -o '"asn_org": *"[^"]*"' | awk -F': ' '{print $2}' | tr -d '"') | |
| loc_country=$(echo "$response" | grep -o '"country": *"[^"]*"' | awk -F': ' '{print $2}' | tr -d '"') | |
| ip_info=$(echo -e "${loc_country}, ${loc_asn}, ${loc_asn_org}") | |
| # 设置全局变量 | |
| [[ -n "$loc_ip" ]] && export WAN${ip_version}=$(printf "%s" ${loc_ip}) | |
| [[ -n "$loc_country" ]] && export COUNTRY${ip_version}=$loc_country | |
| [[ -n "$loc_asn_org" ]] && export ASNORG${ip_version}=$loc_asn_org | |
| # [[ -n "$ip_info" ]] && export IP_INFO${ip_version}=$(printf "%s" ${ip_info}) | |
| [[ -n "$ip_info" ]] && export IP_INFO${ip_version}=$loc_asn | |
| } | |
| function check_ip_status() { | |
| # 检查 'ip' 命令是否可用 | |
| check_ip_command | |
| # 检查IPv4和IPv6支持 | |
| check_ip_support | |
| # 示例调用 | |
| if [[ $IPV4_SUPPORTED -eq 1 ]]; then | |
| get_ip_info 4 | |
| check_warp_status 4 | |
| else | |
| echo -e "$WARN IPv4 is not supported on this system.\n" | |
| fi | |
| if [[ $IPV6_SUPPORTED -eq 1 ]]; then | |
| get_ip_info 6 | |
| check_warp_status 6 | |
| else | |
| echo -e "$WARN IPv6 is not supported on this system.\n" | |
| fi | |
| } | |
| function print_menu_head() { | |
| local n=${1:-35} # 传入分割符重复次数, 默认35 | |
| echo "" | |
| local head=$(echo -e "${YELLOW}♧♧♧${PLAIN} ${CONSTSTR} ${BLUE}${SRC_VER}${PLAIN} ${YELLOW}♧♧♧${PLAIN}") | |
| printf "%2s%s\n${RESET}" "" "$head" | |
| generate_separator "~|$AZURE" "$n" # 另一个分割线 | |
| print_warp_ip_info 4 | |
| print_warp_ip_info 6 | |
| generate_separator "=|$YELLOW" "$n" # 另一个分割线 | |
| } | |
| function print_sys_title() { | |
| local system_name="${SYSTEM_PRETTY_NAME:-"${SYSTEM_NAME} ${SYSTEM_VERSION_NUMBER}"}" | |
| local arch="${DEVICE_ARCH}" | |
| local date_time time_zone | |
| date_time="$(date "+%Y-%m-%d %H:%M")" | |
| time_zone="$(timedatectl status 2>/dev/null | grep "Time zone" | awk -F ':' '{print$2}' | awk -F ' ' '{print$1}')" | |
| echo -e "运行环境: ${BLUE}${system_name} ${arch}${PLAIN}" | |
| echo -e "系统时间: ${BLUE}${date_time} ${time_zone}${PLAIN}" | |
| } | |
| function print_sub_head() { | |
| local head="$1" | |
| local n=${2:-35} # 传入分割符重复次数, 默认35 | |
| local is_machine_info_show=${3:-0} | |
| local is_ip_info_show=${4:-1} | |
| echo "" | |
| printf "${BOLD}%1s%s\n${RESET}" "" "$head" | |
| generate_separator "=|$AZURE" "$n" # 另一个分割线 | |
| if [[ $is_machine_info_show -eq 1 ]]; then | |
| collect_system_info | |
| print_sys_title | |
| generate_separator "~|$AZURE" "$n" # 另一个分割线 | |
| fi | |
| if [[ $is_ip_info_show -eq 1 ]]; then | |
| print_warp_ip_info 4 | |
| print_warp_ip_info 6 | |
| generate_separator "=|$YELLOW" "$n" # 另一个分割线 | |
| fi | |
| } | |
| ## 输出菜单尾项 | |
| function print_main_menu_tail() { | |
| local n=${1:-35} # 传入分割符重复次数, 默认35 | |
| generate_separator "=|$AZURE" "$n" # 另一个分割线 | |
| emoji_count=1 | |
| chinese_width=4 | |
| # adj_width=$((MAX_COL_NUM + chinese_width + emoji_count + chinese_width + emoji_count)) | |
| adj_width=$((MAX_COL_NUM + chinese_width + emoji_count)) | |
| s_exit=${RED}'退出脚本'${RED}"✘"${RESET} | |
| s_restart=${WHITE}'重启系统'${BLUE}"☋"${RESET} | |
| printf "%${NUM_WIDTH}s.%-${adj_width}b%${NUM_SPLIT}s%${NUM_WIDTH}s.%-${MAX_COL_NUM}b\n${RESET}" \ | |
| '0' $s_exit "" 'xx' $s_restart | |
| generate_separator "…" "$n" | |
| emoji_count=1 | |
| chinese_width=4 | |
| # adj_width=$((MAX_COL_NUM + chinese_width + emoji_count + chinese_width + emoji_count)) | |
| adj_width=$((MAX_COL_NUM + chinese_width + emoji_count )) | |
| s_update=${GREEN}'脚本更新'${PURPLE}"ღ"${RESET} | |
| s_qiq=${BLUE}'✟✟'${ITEM_CAT_CHAR}${RESET}'快捷命令☽_'${YELLOW}"qiq"${BLUE}${RESET}"_☾" | |
| printf "%${NUM_WIDTH}s${ITEM_CAT_CHAR}%-${adj_width}b%${NUM_SPLIT}s%-${MAX_COL_NUM}b\n\n${RESET}" \ | |
| '00' $s_update "" $s_qiq | |
| } | |
| ## 输出子菜单尾项 | |
| function print_sub_menu_tail() { | |
| local n=${1:-35} # 传入分割符重复次数, 默认35 | |
| generate_separator "=|$AZURE" "$n" # 另一个分割线 | |
| emoji_count=1 | |
| chinese_width=4 | |
| # adj_width=$((MAX_COL_NUM + chinese_width + emoji_count + chinese_width + emoji_count)) | |
| adj_width=$((MAX_COL_NUM + chinese_width + emoji_count)) | |
| s_exit=${BLUE}'返回'${RED}"🔙"${RESET} | |
| s_restart=${BLUE}'重启系统'${RED}"☋"${RESET} | |
| printf "%${NUM_WIDTH}s.%-${adj_width}b%${NUM_SPLIT}s%${NUM_WIDTH}s.%-${MAX_COL_NUM}b\n\n${RESET}" \ | |
| '0' $s_exit "" 'xx' $s_restart | |
| } | |
| function check_sys_virt() { | |
| if [ $(type -p systemd-detect-virt) ]; then | |
| VIRT=$(systemd-detect-virt) | |
| elif [ $(type -p hostnamectl) ]; then | |
| VIRT=$(hostnamectl | awk '/Virtualization/{print $NF}') | |
| elif [ $(type -p virt-what) ]; then | |
| VIRT=$(virt-what) | |
| fi | |
| VIRT=${VIRT^^} || VIRT="UNKNOWN" | |
| } | |
| ## 显示系统基本信息 | |
| function print_system_info() { | |
| # collect_system_info | |
| DEVICE_ARCH=$(uname -m) | |
| # 判断虚拟化 | |
| check_sys_virt | |
| local hostname=$(hostname) | |
| local kernel_version=$(uname -r) | |
| local cpu_cores=$(nproc) | |
| local cpu_freq=$(cat /proc/cpuinfo | grep "MHz" | head -n 1 | awk '{printf "%.1f GHz\n", $4/1000}') | |
| if [ "$(uname -m)" == "x86_64" ]; then | |
| local cpu_info=$(cat /proc/cpuinfo | grep 'model name' | uniq | sed -e 's/model name[[:space:]]*: //') | |
| else | |
| local cpu_info=$(lscpu | grep 'BIOS Model name' | awk -F': ' '{print $2}' | sed 's/^[ \t]*//') | |
| fi | |
| local cpu_usage_percent=$(awk '{u=$2+$4; t=$2+$4+$5; if (NR==1){u1=u; t1=t;} else printf "%.0f\n", (($2+$4-u1) * 100 / (t-t1))}' \ | |
| <(grep 'cpu ' /proc/stat) <(sleep 1; grep 'cpu ' /proc/stat)) | |
| local os_info=$(lsb_release -ds 2>/dev/null) | |
| # 如果 lsb_release 命令失败,则尝试其他方法 | |
| if [ -z "$os_info" ]; then | |
| # 检查常见的发行文件 | |
| if [ -f "/etc/os-release" ]; then | |
| local os_info=$(source /etc/os-release && echo "$PRETTY_NAME") | |
| elif [ -f "/etc/debian_version" ]; then | |
| local os_info="Debian $(cat /etc/debian_version)" | |
| elif [ -f "/etc/redhat-release" ]; then | |
| local os_info=$(cat /etc/redhat-release) | |
| else | |
| local os_info="Unknown" | |
| fi | |
| fi | |
| local load=$(uptime | awk '{print $(NF-2), $(NF-1), $NF}') | |
| local mem_info=$(free -b | awk 'NR==2{printf "%.2f/%.2f MB (%.2f%%)", $3/1024/1024, $2/1024/1024, $3*100/$2}') | |
| local disk_info=$(df -h | awk '$NF=="/"{printf "%s/%s (%s)", $3, $2, $5}') | |
| local swap_used=$(free -m | awk 'NR==3{print $3}') | |
| local swap_total=$(free -m | awk 'NR==3{print $2}') | |
| if [ "$swap_total" -eq 0 ]; then | |
| local swap_percentage=0 | |
| else | |
| local swap_percentage=$((swap_used * 100 / swap_total)) | |
| fi | |
| local swap_info="${swap_used}MB/${swap_total}MB (${swap_percentage}%)" | |
| clear | |
| echo "" | |
| echo -e " ⚙️ 系统信息 " | |
| generate_separator "↓|$FCYE" 40 # 割线 | |
| echo -e "${FCQH}主机名称: ${FCTL}$hostname" | |
| echo -e "${FCQH}运营商家: ${FCTL}$ASNORG4" | |
| echo -e "${FCQH}系统版本: ${FCTL}$os_info" | |
| echo -e "${FCQH}内核版本: ${FCTL}$kernel_version" | |
| echo -e "${FCQH}虚拟类型: ${FCGR}$VIRT" | |
| generate_separator "…|$AZURE" 40 # 割线 | |
| echo -e "${FCQH}CPU核数: ${FCTL}$cpu_cores" | |
| echo -e "${FCQH}CPU架构: ${FCTL}$DEVICE_ARCH" | |
| echo -e "${FCQH}CPU频率: ${FCGR}$cpu_freq" | |
| echo -e "${FCQH}CPU型号: ${FCTL}$cpu_info" | |
| generate_separator "…|$AZURE" 40 # 割线 | |
| echo -e "${FCQH}CPU占用: ${FCTL}$cpu_usage_percent%" | |
| echo -e "${FCQH}系统负载: ${FCTL}$load" | |
| echo -e "${FCQH}物理内存: ${FCTL}$mem_info" | |
| echo -e "${FCQH}虚拟内存: ${FCGR}$swap_info" | |
| echo -e "${FCQH}硬盘占用: ${FCTL}$disk_info" | |
| generate_separator "…|$FCYE" 40 # 割线 | |
| if [[ $IPV4_SUPPORTED -eq 1 ]]; then | |
| echo -e "${FCQH}IPv4地址: ${FCGR}$WAN4" | |
| [[ -n "$WAN4" ]] && echo -e "${FCTL}地理位置: ${BLUE}$COUNTRY4,$IP_INFO4,$ASNORG4" | |
| else | |
| echo -e "${FCQH}IPv4地址: ${FCGR} Not Supported " | |
| fi | |
| if [[ $IPV6_SUPPORTED -eq 1 ]]; then | |
| echo -e "${FCQH}IPv6地址: ${FCGR}$WAN6" | |
| [[ -n "$WAN6" ]] && echo -e "${FCTL}地理位置: ${BLUE}$COUNTRY6,$IP_INFO6,$ASNORG6" | |
| else | |
| echo -e "${FCQH}IPv6地址: ${FCGR} Not Supported " | |
| fi | |
| generate_separator "~|$AZURE" 40 # 割线 | |
| local dns_addresses=$(awk '/^nameserver/{printf "%s, ", $2} END {print ""}' /etc/resolv.conf) | |
| local congestion_algorithm=$(sysctl -n net.ipv4.tcp_congestion_control) | |
| local queue_algorithm=$(sysctl -n net.core.default_qdisc) | |
| echo -e "${FCQH}DNS地址: ${BLUE}$dns_addresses" | |
| echo -e "${FCQH}网络算法: ${FCZS}$congestion_algorithm $queue_algorithm" | |
| generate_separator "…|$AZURE" 40 # 割线 | |
| local date_time="$(date "+%Y-%m-%d %H:%M")" | |
| local time_zone="$(timedatectl status 2>/dev/null | grep "Time zone" | awk -F ':' '{print$2}' | awk -F ' ' '{print$1}')" | |
| local runtime=$(cat /proc/uptime | awk -F. '{run_days=int($1 / 86400);run_hours=int(($1 % 86400) / 3600);run_minutes=int(($1 % 3600) / 60); if (run_days > 0) printf("%d天 ", run_days); if (run_hours > 0) printf("%d时 ", run_hours); printf("%d分\n", run_minutes)}') | |
| echo -e "${FCLS}系统时间: ${BLUE}$time_zone $date_time" | |
| echo -e "${FCLS}运行时长: ${FCTL}$runtime" | |
| generate_separator "↑|$FCYE" 40 # 割线 | |
| _BREAK_INFO=" 系统信息获取完成" | |
| _IS_BREAK="true" | |
| } | |
| function interactive_select_mirror() { | |
| _SELECT_RESULT="" | |
| local options=("$@") | |
| local message="${options[${#options[@]} - 1]}" | |
| unset options[${#options[@]}-1] | |
| local selected=0 | |
| local start=0 | |
| local page_size=$(($(tput lines) - 3)) # 减去1行用于显示提示信息 | |
| function clear_menu() { | |
| tput rc | |
| for ((i = 0; i < ${#options[@]} + 1; i++)); do | |
| echo -e "\r\033[K" | |
| done | |
| tput rc | |
| } | |
| function cleanup() { | |
| clear_menu | |
| tput rc | |
| tput cnorm | |
| tput rmcup | |
| exit | |
| } | |
| function draw_menu() { | |
| tput clear | |
| tput cup 0 0 | |
| echo -e "${message}" | |
| local end=$((start + page_size - 1)) | |
| if [ $end -ge ${#options[@]} ]; then | |
| end=${#options[@]}-1 | |
| fi | |
| for ((i = start; i <= end; i++)); do | |
| if [ "$i" -eq "$selected" ]; then | |
| echo -e "\033[34;4m➤ ${options[$i]%@*}\033[0m" | |
| else | |
| echo -e " ${options[$i]%@*}" | |
| fi | |
| done | |
| } | |
| function read_key() { | |
| IFS= read -rsn1 key | |
| if [[ $key == $'\x1b' ]]; then | |
| IFS= read -rsn2 key | |
| key="$key" | |
| fi | |
| echo "$key" | |
| } | |
| tput smcup # 保存当前屏幕并切换到新屏幕 | |
| tput sc # 保存光标位置 | |
| tput civis # 隐藏光标 | |
| trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标 | |
| draw_menu # 初始化菜单位置 | |
| # 处理选择 | |
| while true; do | |
| key=$(read_key) | |
| case "$key" in | |
| "[A" | "w" | "W") | |
| # 上箭头 / W | |
| if [ "$selected" -gt 0 ]; then | |
| selected=$((selected - 1)) | |
| if [ "$selected" -lt "$start" ]; then | |
| start=$((start - 1)) | |
| fi | |
| fi | |
| ;; | |
| "[B" | "s" | "S") | |
| # 下箭头 / S | |
| if [ "$selected" -lt $((${#options[@]} - 1)) ]; then | |
| selected=$((selected + 1)) | |
| if [ "$selected" -ge $((start + page_size)) ]; then | |
| start=$((start + 1)) | |
| fi | |
| fi | |
| ;; | |
| "") | |
| # Enter 键 | |
| tput rmcup | |
| break | |
| ;; | |
| *) ;; | |
| esac | |
| draw_menu | |
| done | |
| # clear_menu # 清除菜单 | |
| tput cnorm # 恢复光标 | |
| tput rmcup # 恢复之前的屏幕 | |
| # tput rc # 恢复光标位置 | |
| # 处理结果 | |
| _SELECT_RESULT="${options[$selected]}" | |
| } | |
| function interactive_select_boolean() { | |
| _SELECT_RESULT="" | |
| local selected=0 | |
| local message="$1" | |
| function clear_menu() { | |
| tput rc | |
| for ((i = 0; i < 2 + 2; i++)); do | |
| echo -e "\r\033[K" | |
| done | |
| tput rc | |
| } | |
| function cleanup() { | |
| clear_menu | |
| tput rc | |
| tput cnorm | |
| tput rmcup | |
| exit | |
| } | |
| function draw_menu() { | |
| tput rc | |
| echo -e "╭─ ${message}" | |
| echo -e "│" | |
| if [ "$selected" -eq 0 ]; then | |
| echo -e "╰─ \033[32m●\033[0m 是\033[2m / ○ 否\033[0m" | |
| else | |
| echo -e "╰─ \033[2m○ 是 / \033[0m\033[32m●\033[0m 否" | |
| fi | |
| } | |
| function draw_menu_confirmed() { | |
| tput rc | |
| echo -e "╭─ ${message}" | |
| echo -e "│" | |
| if [ "$selected" -eq 0 ]; then | |
| echo -e "╰─ \033[32m●\033[0m \033[1m是\033[0m\033[2m / ○ 否\033[0m" | |
| else | |
| echo -e "╰─ \033[2m○ 是 / \033[0m\033[32m●\033[0m \033[1m否\033[0m" | |
| fi | |
| } | |
| function read_key() { | |
| IFS= read -rsn1 key | |
| if [[ $key == $'\x1b' ]]; then | |
| IFS= read -rsn2 key | |
| key="$key" | |
| fi | |
| echo "$key" | |
| } | |
| tput sc # 保存光标位置 | |
| tput civis # 隐藏光标 | |
| trap "cleanup" INT TERM # 捕捉脚本结束时恢复光标 | |
| draw_menu # 初始化菜单位置 | |
| # 处理选择 | |
| while true; do | |
| key=$(read_key) | |
| case "$key" in | |
| "[D" | "a" | "A") | |
| # 左箭头 / A | |
| if [ "$selected" -gt 0 ]; then | |
| selected=$((selected - 1)) | |
| fi | |
| ;; | |
| "[C" | "d" | "D") | |
| # 右箭头 / D | |
| if [ "$selected" -lt 1 ]; then | |
| selected=$((selected + 1)) | |
| fi | |
| ;; | |
| "") | |
| # Enter 键 | |
| draw_menu_confirmed | |
| break | |
| ;; | |
| *) ;; | |
| esac | |
| draw_menu | |
| done | |
| # clear_menu # 清除菜单 | |
| tput cnorm # 恢复光标 | |
| # tput rc # 恢复光标位置 | |
| # 处理结果 | |
| if [ "$selected" -eq 0 ]; then | |
| _SELECT_RESULT="true" | |
| else | |
| _SELECT_RESULT="false" | |
| fi | |
| } | |
| ## 处理break,显示信息或直接跳过 | |
| function case_end_tackle() { | |
| _IS_BREAK=${_IS_BREAK:-"false"} | |
| _BREAK_INFO=${_BREAK_INFO:-" 操作完成"} | |
| echo -e "\n${TIP}${_BREAK_INFO}${RESET}" | |
| if ${_IS_BREAK} == "true"; then | |
| echo "└─ 按任意键继续 ..." | |
| read -n 1 -s -r -p "" | |
| fi | |
| _IS_BREAK="true" | |
| _BREAK_INFO="操作完成" | |
| # echo -e "${RESET}" | |
| } | |
| ## 重启系统,需要用户确认 | |
| function sys_reboot() { | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否要重启系统? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 重启系统 ...\n" | |
| _BREAK_INFO=" 系统重启中 ..." | |
| reboot | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 取消重启系统!" | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误!" | |
| _BREAK_INFO=" 输入错误,不重启系统!" | |
| _IS_BREAK="true" | |
| ;; | |
| esac | |
| } | |
| # 修复dpkg中断问题 | |
| function fix_dpkg() { | |
| pkill -9 -f 'apt|dpkg' | |
| rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock | |
| DEBIAN_FRONTEND=noninteractive dpkg --configure -a | |
| } | |
| # 安装应用程序 | |
| function app_install() { | |
| if [ $# -eq 0 ]; then | |
| echo "未提供软件包参数!" | |
| return 1 | |
| fi | |
| for package in "$@"; do | |
| if ! command -v "$package" &>/dev/null; then | |
| echo -e "${gl_huang}正在安装 $package...${gl_bai}" | |
| if command -v dnf &>/dev/null; then | |
| dnf -y update | |
| dnf install -y epel-release | |
| dnf install -y "$package" | |
| elif command -v yum &>/dev/null; then | |
| yum -y update | |
| yum install -y epel-release | |
| yum install -y "$package" | |
| elif command -v apt &>/dev/null; then | |
| apt update -y | |
| apt install -y "$package" | |
| elif command -v apk &>/dev/null; then | |
| apk update | |
| apk add "$package" | |
| elif command -v pacman &>/dev/null; then | |
| pacman -Syu --noconfirm | |
| pacman -S --noconfirm "$package" | |
| elif command -v zypper &>/dev/null; then | |
| zypper refresh | |
| zypper install -y "$package" | |
| elif command -v opkg &>/dev/null; then | |
| opkg update | |
| opkg install "$package" | |
| elif command -v pkg &>/dev/null; then | |
| pkg update | |
| pkg install -y "$package" | |
| else | |
| echo "未知的包管理器!" | |
| return 1 | |
| fi | |
| fi | |
| done | |
| } | |
| function app_remove() { | |
| if [ $# -eq 0 ]; then | |
| echo "未提供软件包参数!" | |
| return 1 | |
| fi | |
| for package in "$@"; do | |
| echo -e "${gl_huang}正在卸载 $package...${gl_bai}" | |
| if command -v dnf &>/dev/null; then | |
| dnf remove -y "$package" | |
| elif command -v yum &>/dev/null; then | |
| yum remove -y "$package" | |
| elif command -v apt &>/dev/null; then | |
| apt purge -y "$package" | |
| elif command -v apk &>/dev/null; then | |
| apk del "$package" | |
| elif command -v pacman &>/dev/null; then | |
| pacman -Rns --noconfirm "$package" | |
| elif command -v zypper &>/dev/null; then | |
| zypper remove -y "$package" | |
| elif command -v opkg &>/dev/null; then | |
| opkg remove "$package" | |
| elif command -v pkg &>/dev/null; then | |
| pkg delete -y "$package" | |
| else | |
| echo "未知的包管理器!" | |
| return 1 | |
| fi | |
| done | |
| } | |
| function sys_update() { | |
| _BREAK_INFO=" 系统更新完成!" | |
| _IS_BREAK="true" | |
| echo -e "\n${WORKING}${GREEN}正在系统更新...${RESET}" | |
| if command -v dnf &>/dev/null; then | |
| dnf -y update | |
| elif command -v yum &>/dev/null; then | |
| yum -y update | |
| elif command -v apt &>/dev/null; then | |
| fix_dpkg | |
| DEBIAN_FRONTEND=noninteractive apt update -y | |
| DEBIAN_FRONTEND=noninteractive apt full-upgrade -y | |
| elif command -v apk &>/dev/null; then | |
| apk update && apk upgrade | |
| elif command -v pacman &>/dev/null; then | |
| pacman -Syu --noconfirm | |
| elif command -v zypper &>/dev/null; then | |
| zypper refresh | |
| zypper update | |
| elif command -v opkg &>/dev/null; then | |
| opkg update | |
| else | |
| echo -e "$WARN 未知的包管理器!" | |
| _BREAK_INFO=" 系统更新失败!" | |
| return | |
| fi | |
| } | |
| function sys_clean() { | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 系统清理完成!" | |
| echo -e "\n${WORKING}${RED}正在系统清理...${RESET}" | |
| if command -v dnf &>/dev/null; then | |
| rpm --rebuilddb | |
| dnf autoremove -y | |
| dnf clean all | |
| dnf makecache | |
| journalctl --rotate | |
| journalctl --vacuum-time=1s | |
| journalctl --vacuum-size=500M | |
| elif command -v yum &>/dev/null; then | |
| rpm --rebuilddb | |
| yum autoremove -y | |
| yum clean all | |
| yum makecache | |
| journalctl --rotate | |
| journalctl --vacuum-time=1s | |
| journalctl --vacuum-size=500M | |
| elif command -v apt &>/dev/null; then | |
| fix_dpkg | |
| apt autoremove --purge -y | |
| apt clean -y | |
| apt autoclean -y | |
| journalctl --rotate | |
| journalctl --vacuum-time=1s | |
| journalctl --vacuum-size=500M | |
| elif command -v apk &>/dev/null; then | |
| echo "清理包管理器缓存..." | |
| apk cache clean | |
| echo "删除系统日志..." | |
| rm -rf /var/log/* | |
| echo "删除APK缓存..." | |
| rm -rf /var/cache/apk/* | |
| echo "删除临时文件..." | |
| rm -rf /tmp/* | |
| elif command -v pacman &>/dev/null; then | |
| pacman -Rns $(pacman -Qdtq) --noconfirm | |
| pacman -Scc --noconfirm | |
| journalctl --rotate | |
| journalctl --vacuum-time=1s | |
| journalctl --vacuum-size=500M | |
| elif command -v zypper &>/dev/null; then | |
| zypper clean --all | |
| zypper refresh | |
| journalctl --rotate | |
| journalctl --vacuum-time=1s | |
| journalctl --vacuum-size=500M | |
| elif command -v opkg &>/dev/null; then | |
| echo "删除系统日志..." | |
| rm -rf /var/log/* | |
| echo "删除临时文件..." | |
| rm -rf /tmp/* | |
| elif command -v pkg &>/dev/null; then | |
| echo "清理未使用的依赖..." | |
| pkg autoremove -y | |
| echo "清理包管理器缓存..." | |
| pkg clean -y | |
| echo "删除系统日志..." | |
| rm -rf /var/log/* | |
| echo "删除临时文件..." | |
| rm -rf /tmp/* | |
| else | |
| echo -e "$WARN 未知的包管理器!" | |
| _BREAK_INFO=" 系统清理失败!" | |
| return | |
| fi | |
| return | |
| } | |
| postgresql_usage(){ | |
| echo -e '\nPostgreSQL使用说明' | |
| echo -e 'Start the database server using: pg_ctlcluster 11 main start' | |
| echo -e '============================================================' | |
| echo -e 'apt show postgresql # 查看已经安装的postgresql版本 ' | |
| echo -e 'service postgresql status # 检查PostgreSQL是否正在运行 ' | |
| echo -e 'su - postgresql # 登录账户 ' | |
| echo -e 'psql # 启动PostgreSQL Shell ' | |
| echo -e '\q # 退出PosqgreSQL Shell ' | |
| echo -e '\l # 查看所有表 ' | |
| echo -e '\du # 查看PostSQL用户 ' | |
| echo -e '===========================================================' | |
| echo -e "ALTER USER postgres WITH PASSWORD 'my_password'; # 更改任何用户的密码 " | |
| echo -e "CREATE USER my_user WITH PASSWORD 'my_password'; # 创建一个用户 " | |
| echo -e 'ALTER USER my_user WITH SUPERUSER; # 给用户添加超级用户权限 ' | |
| echo -e 'DROP USER my_user; # 删除用户 ' | |
| echo -e 'CREATE DATABASE my_db OWNER my_user; # 创建数据库,并指定所有者 ' | |
| echo -e 'DROP DATABASE my_db; # 删除数据库 ' | |
| echo -e '===========================================================' | |
| echo -e 'select current_database(); # 查看当前数据库 ' | |
| echo -e '\c - next_db; # 切换数据库 ' | |
| echo -e 'psql -U my_user # \q退出后,使用my_user登录 ' | |
| echo -e 'psql -U my_user -d my_db # 使用-d参数直接连接数据库 ' | |
| echo -e '===========================================================' | |
| echo -e ' >>> 找到数据库bin目录./pg_ctl执行: 启停服务 ' | |
| echo -e 'systemctl stop postgresql.service # 停止 ' | |
| echo -e 'systemctl start postgresql.service # 启动 ' | |
| } | |
| # 定义性能测试数组 | |
| MENU_TEST_ITEMS=( | |
| # "1|ChatGPT解锁状态|$WHITE" | |
| # "2|Region流媒体状态|$WHITE" | |
| # "3|yeahwu流媒体状态|$WHITE" | |
| # "………………………|$WHITE" | |
| # "11|三网测速(Superspeed)|$CYAN" | |
| # "12|三网回程(bestrace)|$WHITE" | |
| # "13|回程线路(mtr_trace)|$WHITE" | |
| # "21|单线程测速|$WHITE" | |
| # "22|带宽性能(yabs)|$WHITE" | |
| # "………………………|$WHITE" | |
| # "31|性能测试(bench)|$CYAN" | |
| # "32|融合怪测评(spiritysdx)|$CYAN" | |
| "………………………………………………………………💡||💡" | |
| "IP解锁状态检测|$GREEN|🌏" | |
| " 1.ChatGPT解锁状态" | |
| " 2.Region流媒体状态" | |
| " 3.yeahwu流媒体状态" | |
| " 4.流媒体地区限制检测|$BLUE" | |
| "………………………………………………………………💡||💡" | |
| "网络线路测速|$GREEN|🌐" | |
| "11.三网测速(Superspeed)" | |
| "12.三网回程(bestrace)" | |
| "13.回程线路(mtr_trace)" | |
| "21.单线程测速" | |
| "22.带宽性能(yabs)" | |
| "………………………………………………………………💡||💡" | |
| "综合测试|$GREEN|🌏" | |
| "31.性能测试(bench)|$RED" | |
| "32.融合怪测评(spiritysdx)" | |
| ) | |
| function system_test_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ 性能测试 " $MAX_SPLIT_CHAR_NUM 1 1 | |
| print_items_list MENU_TEST_ITEMS[@] ' ⚓ 性能测试脚本 ' | |
| # print_main_menu_tail $MAX_SPLIT_CHAR_NUM | |
| print_sub_menu_tail $MAX_SPLIT_CHAR_NUM | |
| } | |
| while true; do | |
| _IS_BREAK="true" | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) bash <(curl -Ls https://cdn.jsdelivr.net/gh/missuo/OpenAI-Checker/openai.sh) ;; | |
| 2) bash <(curl -L -s check.unlock.media) ;; | |
| 3) | |
| url=$(get_proxy_url "https://github.com/yeahwu/check/raw/main/check.sh") | |
| wget -qO- ${url} | bash ;; | |
| 4) | |
| url=$(get_proxy_url " https://raw.githubusercontent.com/1-stream/RegionRestrictionCheck/main/check.sh") | |
| bash <(curl -L -s ${url}) ;; | |
| 11) bash <(curl -Lso- https://git.io/superspeed_uxh) ;; | |
| 12) wget -qO- git.io/besttrace | bash ;; | |
| 13) | |
| url=$(get_proxy_url "https://raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh") | |
| # wget -qO- ${url} | bash ;; | |
| curl ${url} | bash ;; | |
| 21) bash <(fetch https://bench.im/hyperspeed) ;; | |
| 22) curl -sL yabs.sh | bash -s -- -i -5 ;; | |
| 31) curl -Lso- bench.sh | bash ;; | |
| 32) curl -L https://gitlab.com/spiritysdx/za/-/raw/main/ecs.sh -o ecs.sh && chmod +x ecs.sh && bash ecs.sh ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| function check_crontab_installed() { | |
| if ! command -v crontab >/dev/null 2>&1; then | |
| install_crontab | |
| fi | |
| } | |
| function install_crontab() { | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| case "$ID" in | |
| ubuntu|debian|kali) | |
| apt update | |
| apt install -y cron | |
| systemctl enable cron | |
| systemctl start cron | |
| ;; | |
| centos|rhel|almalinux|rocky|fedora) | |
| yum install -y cronie | |
| systemctl enable crond | |
| systemctl start crond | |
| ;; | |
| alpine) | |
| apk add --no-cache cronie | |
| rc-update add crond | |
| rc-service crond start | |
| ;; | |
| arch|manjaro) | |
| pacman -S --noconfirm cronie | |
| systemctl enable cronie | |
| systemctl start cronie | |
| ;; | |
| opensuse|suse|opensuse-tumbleweed) | |
| zypper install -y cron | |
| systemctl enable cron | |
| systemctl start cron | |
| ;; | |
| iStoreOS|openwrt|ImmortalWrt|lede) | |
| opkg update | |
| opkg install cron | |
| /etc/init.d/cron enable | |
| /etc/init.d/cron start | |
| ;; | |
| FreeBSD) | |
| pkg install -y cronie | |
| sysrc cron_enable="YES" | |
| service cron start | |
| ;; | |
| *) | |
| echo "不支持的发行版: $ID" | |
| return | |
| ;; | |
| esac | |
| else | |
| echo "无法确定操作系统。" | |
| return | |
| fi | |
| echo -e "$PRIGHT crontab 已安装且 cron 服务正在运行。" | |
| } | |
| function iptables_rules_save() { | |
| mkdir -p /etc/iptables | |
| touch /etc/iptables/rules.v4 | |
| iptables-save > /etc/iptables/rules.v4 | |
| check_crontab_installed | |
| crontab -l | grep -v 'iptables-restore' | crontab - > /dev/null 2>&1 | |
| (crontab -l ; echo '@reboot iptables-restore < /etc/iptables/rules.v4') | crontab - > /dev/null 2>&1 | |
| } | |
| function iptables_open() { | |
| app_install iptables | |
| iptables_rules_save | |
| iptables -P INPUT ACCEPT | |
| iptables -P FORWARD ACCEPT | |
| iptables -P OUTPUT ACCEPT | |
| iptables -F | |
| ip6tables -P INPUT ACCEPT | |
| ip6tables -P FORWARD ACCEPT | |
| ip6tables -P OUTPUT ACCEPT | |
| ip6tables -F | |
| } | |
| function add_swap() { | |
| local new_swap=$1 # 获取传入的参数 | |
| # 获取当前系统中所有的 swap 分区 | |
| local swap_partitions=$(grep -E '^/dev/' /proc/swaps | awk '{print $1}') | |
| # 遍历并删除所有的 swap 分区 | |
| for partition in $swap_partitions; do | |
| swapoff "$partition" | |
| wipefs -a "$partition" | |
| mkswap -f "$partition" | |
| done | |
| # 确保 /swapfile 不再被使用 | |
| swapoff /swapfile | |
| # 删除旧的 /swapfile | |
| rm -f /swapfile | |
| # 创建新的 swap 分区 | |
| fallocate -l ${new_swap}M /swapfile | |
| chmod 600 /swapfile | |
| mkswap /swapfile | |
| swapon /swapfile | |
| sed -i '/\/swapfile/d' /etc/fstab | |
| echo "/swapfile swap swap defaults 0 0" >> /etc/fstab | |
| if [ -f /etc/alpine-release ]; then | |
| echo "nohup swapon /swapfile" > /etc/local.d/swap.start | |
| chmod +x /etc/local.d/swap.start | |
| rc-update add local | |
| fi | |
| echo -e "虚拟内存大小已调整为${gl_huang}${new_swap}${gl_bai}M" | |
| } | |
| function check_swap() { | |
| local swap_total=$(free -m | awk 'NR==3{print $2}') | |
| # 判断是否需要创建虚拟内存 | |
| [ "$swap_total" -gt 0 ] || add_swap 1024 | |
| } | |
| function bbr_on() { | |
| cat > /etc/sysctl.conf << EOF | |
| net.ipv4.tcp_congestion_control=bbr | |
| EOF | |
| sysctl -p | |
| } | |
| function system_dd_usage(){ | |
| echo -e " " | |
| echo -e "$PRIGHT DD脚本使用说明 " | |
| echo -e "—————————————————————————————————————" | |
| echo -e " Linux : ${BLUE}root${red}@${yellow}LeitboGi0ro${PLAIN}" | |
| echo -e " Windows : ${BLUE}Administrator${red}@${yellow}Teddysun.com" | |
| echo -e " @bin456789 : ${BLUE}root|Administrator${red}@${yellow}123@@@" | |
| echo -e " ${white}(Windows need mininumn 15G Storage)${PLAIN}" | |
| echo -e ' (当administrator无法登录时, 可尝试.\\administrator)\n' | |
| echo -e " bash InstallNET.sh -windows 10 -lang 'en'" | |
| echo -e " bash InstallNET.sh -windows 11 -lang 'cn'\n" | |
| echo -e " reinstall.sh alma 8|9" | |
| echo -e " reinstall.sh rocky 8|9" | |
| echo -e " reinstall.sh debian 9|10|11|12" | |
| echo -e " reinstall.sh ubuntu 24.04 [--minimal]" | |
| echo -e " reinstall.sh alpine 3.17|3.18|3.19|3.20\n" | |
| echo -e " reinstall.bat windows --image-name='windows server 2022 serverdatacenter' --lang=zh-cn " | |
| echo -e " bash reinstall.sh windows --image-name 'Windows 10 Enterprise LTSC 2021'--lang en-us " | |
| echo -e " bash reinstall.sh windows --image-name 'windows 11 pro' --lang zh-cn \n" | |
| echo -e " bash reinstall.sh windows --image-name 'windows 11 business 23h2'" | |
| echo -e " --iso 'https://drive.massgrave.dev/zh-cn_windows_11_business_editions_version_23h2_updated_aug_2024_x64_dvd_6ca91c94.iso' \n" | |
| echo -e " bash reinstall.sh windows --image-name 'Windows 10 business 22h2'" | |
| echo -e " --iso 'https://drive.massgrave.dev/zh-cn_windows_10_business_editions_version_22h2_updated_aug_2024_x86_dvd_8d7e500f.iso'\n" | |
| echo -e " bash reinstall.sh dd --img https://example.com/xx.xz" | |
| echo -e " bash reinstall.sh alpine --hold=1" | |
| echo -e " bash reinstall.sh netboot.xyz\n" | |
| echo -e " 注意: Windows 10 LTSC 2021 zh-cn 的wsappx进程会长期占用CPU, 需要更新系统补丁。\n" | |
| } | |
| # 定义系统工具数组 | |
| MENU_SYSTEM_TOOLS_ITEMS=( | |
| "1|修改ROOT密码|$WHITE" | |
| "2|开启ROOT登录|$WHITE" | |
| "3|禁用ROOT用户|$WHITE" | |
| "4|系统源管理|$MAGENTA" | |
| "5|DNS管理|$CYAN" | |
| "6|改主机名|$WHITE" | |
| "7|时区调整|$WHITE" | |
| "8|用户管理|$WHITE" | |
| "9|端口管理|$WHITE" | |
| "………………………|$WHITE" | |
| "21|DD系统|$GREEN" | |
| "22|虚拟内存|$CYAN" | |
| "23|开启SSH转发|$WHITE" | |
| "24|切换v4/v6|$WHITE" | |
| "25|BBRv3加速|$WHITE" | |
| "26|定时任务|$WHITE" | |
| "27|命令行美化|$YELLOW" | |
| "28|设置qiq命令|$CYAN" | |
| "29|删除qiq命令|$WHITE" | |
| ) | |
| function system_tools_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ 系统工具 " $MAX_SPLIT_CHAR_NUM 1 0 | |
| split_menu_items MENU_SYSTEM_TOOLS_ITEMS[@] | |
| # print_main_menu_tail $MAX_SPLIT_CHAR_NUM | |
| print_sub_menu_tail $MAX_SPLIT_CHAR_NUM | |
| } | |
| function sys_setting_change_root_password(){ | |
| # local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| # read -rp "${CHOICE}" INPUT | |
| echo "设置ROOT密码" && passwd | |
| } | |
| function sys_setting_enable_root(){ | |
| sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; | |
| sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; | |
| service sshd restart | |
| _BREAK_INFO=" ROOT登录设置完毕" | |
| _IS_BREAK="true" | |
| } | |
| function sys_setting_disable_root(){ | |
| app_install sudo | |
| # 提示用户输入新用户名 | |
| echo -e "$TIP 禁用Root用户,需要创建新的用户 ..." | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入新用户名: ${PLAIN}") | |
| read -rp "${CHOICE}" new_username | |
| # 创建新用户并设置密码 | |
| echo -e "$TIP 设置新用户的密码 ..." | |
| sudo useradd -m -s /bin/bash "$new_username" | |
| sudo passwd "$new_username" | |
| # 赋予新用户sudo权限 | |
| echo -e "$TIP 设置新用户sudo权限 ..." | |
| echo "$new_username ALL=(ALL:ALL) ALL" | sudo tee -a /etc/sudoers | |
| # 禁用ROOT用户登录 | |
| echo -e "$TIP 禁用Root用户 ..." | |
| sudo passwd -l root | |
| _BREAK_INFO=" 禁用ROOT用户完毕" | |
| _IS_BREAK="true" | |
| } | |
| function sys_setting_change_change_hostname(){ | |
| local cur_hostname=$(hostname) | |
| # 询问用户是否要更改主机名 | |
| echo "当前主机名: $cur_hostname" | |
| read -p "是否要更改主机名?(y/n): " answer | |
| if [ "$answer" == "y" ]; then | |
| # 获取新的主机名 | |
| read -p "请输入新的主机名: " new_hostname | |
| if [ -n "$new_hostname" && [ "$new_hostname" != "0" ]]; then | |
| if [ -f /etc/alpine-release ]; then | |
| # Alpine | |
| echo "$new_hostname" > /etc/hostname | |
| hostname "$new_hostname" | |
| else | |
| # 其他系统,如 Debian, Ubuntu, CentOS 等 | |
| hostnamectl set-hostname "$new_hostname" | |
| sed -i "s/$cur_hostname/$new_hostname/g" /etc/hostname | |
| systemctl restart systemd-hostnamed | |
| fi | |
| if grep -q "127.0.0.1" /etc/hosts; then | |
| sed -i "s/127.0.0.1 .*/127.0.0.1 $new_hostname localhost localhost.localdomain/g" /etc/hosts | |
| else | |
| echo "127.0.0.1 $new_hostname localhost localhost.localdomain" >> /etc/hosts | |
| fi | |
| if grep -q "^::1" /etc/hosts; then | |
| sed -i "s/^::1 .*/::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback/g" /etc/hosts | |
| else | |
| echo "::1 $new_hostname localhost localhost.localdomain ipv6-localhost ipv6-loopback" >> /etc/hosts | |
| fi | |
| echo "主机名更改为: $new_hostname" | |
| else | |
| echo "无效主机名。未更改主机名。" | |
| continue | |
| fi | |
| else | |
| echo "未更改主机名。" | |
| fi | |
| } | |
| function sys_setting_users_manage(){ | |
| local users_items_list=( | |
| '1.用户列表' | |
| '2.新普通账户' | |
| '3.新高级账户' | |
| '4.设置最高权限' | |
| '5.取消最高权限' | |
| '6.删除账号' | |
| '0.返回' | |
| ) | |
| function print_items_users(){ | |
| echo "用户列表" | |
| generate_separator "=|$WHITE" | |
| printf "%-24s %-34s %-20s %-10s\n" "用户名" "用户权限" "用户组" "sudo权限" | |
| while IFS=: read -r username _ userid groupid _ _ homedir shell; do | |
| groups=$(groups "$username" | cut -d : -f 2) | |
| sudo_status=$(sudo -n -lU "$username" 2>/dev/null | grep -q '(ALL : ALL)' && echo "Yes" || echo "No") | |
| printf "%-20s %-30s %-20s %-10s\n" "$username" "$homedir" "$groups" "$sudo_status" | |
| done < /etc/passwd | |
| generate_separator "=|$WHITE" | |
| } | |
| function users_add_new(){ | |
| print_items_users | |
| # echo "新普通账户" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入新用户名(普通账户): ${PLAIN}") | |
| read -rp "${CHOICE}" new_username | |
| useradd -m -s /bin/bash "$new_username" | |
| passwd "$new_username" | |
| print_items_users | |
| } | |
| function users_add_sudo(){ | |
| print_items_users | |
| # echo "新高级账户" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入新用户名(高级账户): ${PLAIN}") | |
| read -rp "${CHOICE}" new_username | |
| useradd -m -s /bin/bash "$new_username" | |
| passwd "$new_username" | |
| usermod -aG sudo "$new_username" | |
| print_items_users | |
| } | |
| function users_set_sudo(){ | |
| print_items_users | |
| # echo "设置最高权限" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入用户名(设置最高权限): ${PLAIN}") | |
| read -rp "${CHOICE}" username | |
| usermod -aG sudo "$username" | |
| print_items_users | |
| } | |
| function users_unset_sudo(){ | |
| print_items_users | |
| # echo "取消最高权限" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入用户名(取消最高权限): ${PLAIN}") | |
| read -rp "${CHOICE}" username | |
| gpasswd -d "$username" sudo | |
| print_items_users | |
| } | |
| function users_delete(){ | |
| print_items_users | |
| # echo "删除账号" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入用户名(删除账号): ${PLAIN}") | |
| read -rp "${CHOICE}" username | |
| userdel -r "$username" | |
| print_items_users | |
| } | |
| # 询问用户是否要更改主机名 | |
| clear | |
| _IS_BREAK="true" | |
| print_items_list users_items_list[@] " ⚓ 用户管理:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) print_items_users ;; | |
| 2) users_add_new ;; | |
| 3) users_add_sudo ;; | |
| 4) users_set_sudo ;; | |
| 5) users_unset_sudo ;; | |
| 6) users_delete ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| # print_items_users | |
| case_end_tackle | |
| } | |
| function sys_setting_alter_timezone(){ | |
| local cur_timezone=$(timedatectl show --property=Timezone --value) | |
| local cur_time=$(date +"%Y-%m-%d %H:%M:%S") | |
| local tz_items_regions=( | |
| "1|亚洲|$WHITE" | |
| "2|欧洲|$WHITE" | |
| "3|美洲|$WHITE" | |
| "4|UTC|$WHITE" | |
| ) | |
| local tz_items_asian=( | |
| "1|中国上海|$WHITE" | |
| "2|中国香港|$WHITE" | |
| "3|日本东京|$WHITE" | |
| "4|韩国首尔|$WHITE" | |
| "5|新加坡|$WHITE" | |
| "6|印度加尔各答|$WHITE" | |
| "7|阿联酋迪拜|$WHITE" | |
| "8|澳大利亚悉尼|$WHITE" | |
| "9|泰国曼谷|$WHITE" | |
| ) | |
| local tz_items_eu=( | |
| "1|英国伦敦|$WHITE" | |
| "2|法国巴黎|$WHITE" | |
| "3|德国柏林|$WHITE" | |
| "4|俄罗斯莫斯科|$WHITE" | |
| "5|荷兰尤特赖赫特|$WHITE" | |
| "6|西班牙马德里|$WHITE" | |
| ) | |
| local tz_items_us=( | |
| "1|美国西部|$WHITE" | |
| "2|美国东部|$WHITE" | |
| "3|加拿大|$WHITE" | |
| "4|墨西哥|$WHITE" | |
| "5|巴西|$WHITE" | |
| "6|阿根廷|$WHITE" | |
| ) | |
| function set_timedate() { | |
| local tz="$1" | |
| if grep -q 'Alpine' /etc/issue; then | |
| app_install tzdata | |
| cp /usr/share/zoneinfo/${tz} /etc/localtime | |
| hwclock --systohc | |
| else | |
| timedatectl set-timezone ${tz} | |
| fi | |
| } | |
| function tz_alter_asia(){ | |
| echo -e "$PRIGHT 当前时区" | |
| # 显示时区和时间 | |
| echo "当前时区:$cur_timezone" | |
| echo "当前时间:$cur_time" | |
| print_items_list tz_items_asian[@] " ⚓ 亚太地区列表:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择时区: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) set_timedate Asia/Shanghai ;; | |
| 2) set_timedate Asia/Hong_Kong ;; | |
| 3) set_timedate Asia/Tokyo ;; | |
| 4) set_timedate Asia/Seoul ;; | |
| 5) set_timedate Asia/Singapore ;; | |
| 6) set_timedate Asia/Kolkata ;; | |
| 7) set_timedate Asia/Dubai ;; | |
| 8) set_timedate Australia/Sydney ;; | |
| 9) set_timedate Asia/Bangkok ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| function tz_alter_eu(){ | |
| echo -e "$PRIGHT 系统时间信息" | |
| # 显示时区和时间 | |
| echo "当前系统时区:$cur_timezone" | |
| echo "当前系统时间:$cur_time" | |
| print_items_list tz_items_eu[@] " ⚓ 欧洲地区列表:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择时区: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) set_timedate Europe/London ;; | |
| 2) set_timedate Europe/Paris ;; | |
| 3) set_timedate Europe/Berlin ;; | |
| 4) set_timedate Europe/Moscow ;; | |
| 5) set_timedate Europe/Amsterdam ;; | |
| 6) set_timedate Europe/Madrid ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| function tz_alter_us(){ | |
| echo -e "$PRIGHT 系统时间信息" | |
| # 显示时区和时间 | |
| echo "当前系统时区:$cur_timezone" | |
| echo "当前系统时间:$cur_time" | |
| print_items_list tz_items_us[@] " ⚓ 美洲地区列表:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择时区: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) set_timedate America/Los_Angeles ;; | |
| 2) set_timedate America/New_York ;; | |
| 3) set_timedate America/Vancouver ;; | |
| 4) set_timedate America/Mexico_City ;; | |
| 5) set_timedate America/Sao_Paulo ;; | |
| 6) set_timedate America/Argentina/Buenos_Aires ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| echo -e "$PRIGHT 系统时间信息" | |
| # 显示时区和时间 | |
| echo "当前系统时区:$cur_timezone" | |
| echo "当前系统时间:$cur_time" | |
| print_items_list tz_items_regions[@] " ⚓ 时区地区列表:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择时区所属区域: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) tz_alter_asia ;; | |
| 2) tz_alter_eu ;; | |
| 3) tz_alter_us ;; | |
| 4) set_timedate UTC ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| function sys_setting_alter_sources(){ | |
| local source_list_options=( | |
| "1.大陆地区" | |
| "2.教育网" | |
| "3.海外地区" | |
| "0.退出" | |
| ) | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 已修改系统源!" | |
| print_items_list source_list_options[@] " ⚓ 系统源地区选择:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| bash <(curl -sSL https://linuxmirrors.cn/main.sh) | |
| _BREAK_INFO=" 已修改系统源为大陆地区!" | |
| ;; | |
| 2) | |
| bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu | |
| _BREAK_INFO=" 已修改系统源为教育网!" | |
| ;; | |
| 3) | |
| bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad | |
| _BREAK_INFO=" 已修改系统源为海外地区!" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function sys_setting_change_ports_manage(){ | |
| local ports_management_options=( | |
| "1.查看端口状态" | |
| "2.开放所有端口" | |
| "3.关闭所有端口" | |
| "4.开放指定端口" | |
| "5.关闭指定端口" | |
| "0.退出" | |
| ) | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由端口管理子菜单返回!" | |
| print_items_list ports_management_options[@] " ⚓ 选择:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| clear | |
| ss -tulnape | |
| ;; | |
| 2) | |
| # permission_judgment | |
| if [ "$EUID" -ne 0 ] ; then | |
| # echo -e "$WARN 该操作需要root权限!" | |
| _BREAK_INFO=" 开放所有端口需要root权限" | |
| case_end_tackle | |
| continue | |
| fi | |
| iptables_open | |
| app_remove iptables-persistent ufw firewalld iptables-services > /dev/null 2>&1 | |
| _BREAK_INFO=" 已开放全部端口" | |
| ;; | |
| 3) | |
| current_port=$(grep -E '^ *Port [0-9]+' /etc/ssh/sshd_config | awk '{print $2}') | |
| cat > /etc/iptables/rules.v4 << EOF | |
| *filter | |
| :INPUT DROP [0:0] | |
| :FORWARD DROP [0:0] | |
| :OUTPUT ACCEPT [0:0] | |
| -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT | |
| -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT | |
| -A INPUT -i lo -j ACCEPT | |
| -A FORWARD -i lo -j ACCEPT | |
| -A INPUT -p tcp --dport $current_port -j ACCEPT | |
| COMMIT | |
| EOF | |
| iptables-restore < /etc/iptables/rules.v4 | |
| _BREAK_INFO=" 已关闭所有端口!" | |
| ;; | |
| 4) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入要开放的端口号: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| sed -i "/COMMIT/i -A INPUT -p tcp --dport $INPUT -j ACCEPT" /etc/iptables/rules.v4 | |
| sed -i "/COMMIT/i -A INPUT -p udp --dport $INPUT -j ACCEPT" /etc/iptables/rules.v4 | |
| iptables-restore < /etc/iptables/rules.v4 | |
| _BREAK_INFO=" 已开放端口: $INPUT!" | |
| ;; | |
| 5) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入要关闭的端口号: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| sed -i "/--dport $INPUT/d" /etc/iptables/rules.v4 | |
| iptables-restore < /etc/iptables/rules.v4 | |
| _BREAK_INFO=" 已关闭端口: $INPUT!" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function sys_setting_dns_manage(){ | |
| local dns_list_options=( | |
| "1.国外DNS" | |
| "2.国内DNS" | |
| "3.自定义DNS" | |
| "0.返回" | |
| ) | |
| function set_dns() { | |
| local dns1_ipv4="$1" | |
| local dns2_ipv4="$2" | |
| local dns1_ipv6="$3" | |
| local dns2_ipv6="$4" | |
| cp /etc/resolv.conf /etc/resolv.conf.bak | |
| rm /etc/resolv.conf | |
| touch /etc/resolv.conf | |
| if [ $IPV6_SUPPORTED -eq 1 ]; then | |
| echo "nameserver $dns1_ipv6" >> /etc/resolv.conf | |
| echo "nameserver $dns2_ipv6" >> /etc/resolv.conf | |
| fi | |
| if [ $IPV4_SUPPORTED -eq 1 ]; then | |
| echo "nameserver $dns1_ipv4" >> /etc/resolv.conf | |
| echo "nameserver $dns2_ipv4" >> /etc/resolv.conf | |
| fi | |
| } | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 已修改DNS!" | |
| clear | |
| echo -e "\n\n$TIP 当前DNS地址: \n" | |
| cat /etc/resolv.conf | |
| generate_separator "=|$WHITE" | |
| print_items_list dns_list_options[@] " ⚓ DNS切换:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| local dns1_ipv4="1.1.1.1" | |
| local dns2_ipv4="8.8.8.8" | |
| local dns1_ipv6="2606:4700:4700::1111" | |
| local dns2_ipv6="2001:4860:4860::8888" | |
| set_dns ${dns1_ipv4} ${dns2_ipv4} ${dns1_ipv6} ${dns2_ipv6} | |
| _BREAK_INFO=" DNS 已切换为海外DNS!" | |
| ;; | |
| 2) | |
| local dns1_ipv4="223.5.5.5" | |
| local dns2_ipv4="183.60.83.19" | |
| local dns1_ipv6="2400:3200::1" | |
| local dns2_ipv6="2400:da00::6666" | |
| set_dns ${dns1_ipv4} ${dns2_ipv4} ${dns1_ipv6} ${dns2_ipv6} | |
| _BREAK_INFO=" DNS 已切换为国内DNS!" | |
| ;; | |
| 3) | |
| app_install nano | |
| nano /etc/resolv.conf | |
| _BREAK_INFO=" 已手动修改DNS!" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function sys_setting_dd_system(){ | |
| local sys_dd_options=( | |
| "1.Leitbogioro" | |
| "2.MoeClub" | |
| "3.0oVicero0" | |
| "4.mowwom" | |
| "5.bin456789" | |
| "0.返回" | |
| ) | |
| local sys_lang_options=( | |
| "1.中文(CN)" | |
| "2.英文(EN)" | |
| ) | |
| function select_system_language(){ | |
| local sys_lang='CN' | |
| print_items_list sys_lang_options[@] " ⚓ 系统语言选择:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择语言(默认为中文)[CN/EN]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| # 1) | |
| # sys_lang='CN' | |
| # _BREAK_INFO=" 已选择中文!" | |
| # ;; | |
| 2) | |
| sys_lang='EN' | |
| _BREAK_INFO=" 已选择英文!" | |
| esac | |
| echo ${sys_lang} | |
| } | |
| local systems_list=( | |
| "1|Alpine Edge|$WHITE" | |
| "2|Alpine 3.20|$WHITE" | |
| "3|Alpine 3.19|$WHITE" | |
| "4|Alpine 3.18|$WHITE" | |
| "…………………………………|$WHITE" | |
| "11|Debian 12|$YELLOW" | |
| "12|Debian 11|$WHITE" | |
| "13|Debian 10|$WHITE" | |
| "14|Ubuntu 24.04|$YELLOW" | |
| "15|Ubuntu 22.04|$WHITE" | |
| "16|Ubuntu 20.04|$WHITE" | |
| "…………………………………|$WHITE" | |
| "21|AlmaLinux 9|$WHITE" | |
| "22|AlmaLinux 8|$WHITE" | |
| "23|RockyLinux 9|$WHITE" | |
| "24|RockyLinux 8|$WHITE" | |
| "…………………………………|$WHITE" | |
| "31|Windows 2025|$YELLOW" | |
| "32|Windows 2022|$WHITE" | |
| "33|Windows 2019|$WHITE" | |
| "34|Windows 11|$WHITE" | |
| "35|Windows 10|$WHITE" | |
| "36|Windows 7|$WHITE" | |
| "…………………………………|$WHITE" | |
| "88|41合一脚本|$WHITE" | |
| "99|脚本说明|$WHITE" | |
| ) | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" DD系统!" | |
| check_sys_virt | |
| if [[ "$VIRT" != *"KVM"* ]]; then | |
| # 如果系统虚拟化不是KVM,则使用OsMutation进行DD系统 | |
| local fname='OsMutation.sh' | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/LloydAsp/OsMutation/main/OsMutation.sh') | |
| if command -v curl &>/dev/null; then | |
| curl -sL -o ${fname} "${url}" && chmod u+x ${fname} && bash ${fname} | |
| elif command -v wget &>/dev/null; then | |
| wget -qO ${fname} $url && chmod u+x ${fname} && bash ${fname} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| fi | |
| continue | |
| fi | |
| function dd_sys_login_info(){ | |
| local username=$1 | |
| local password=$2 | |
| local port=$3 | |
| echo -e "\n$TIP DD系统登录信息:" | |
| echo -e "=======================" | |
| echo -e "$BOLD 用户: ${username}" | |
| echo -e "$BOLD 密码: ${password}" | |
| echo -e "$BOLD 端口: ${port}" | |
| echo -e "=======================" | |
| _BREAK_INFO=" DD系统后登录信息:" | |
| # _IS_BREAK="true" | |
| # break_tacle | |
| } | |
| function dd_sys_mollylau(){ | |
| local sys_type=$1 | |
| local sys_ver=$2 | |
| local sys_lang=$3 | |
| local weburl='https://github.com/leitbogioro/Tools' | |
| local fname='InstallNET.sh' | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh') | |
| if command -v curl &>/dev/null; then | |
| curl -sL -o ${fname} "${url}" && chmod a+x ${fname} | |
| elif command -v wget &>/dev/null; then | |
| wget -qO ${fname} $url && chmod a+x ${fname} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| _IS_BREAK="true" | |
| return | |
| fi | |
| # echo -e "\n$TIP dd input: ${sys_type} ${sys_ver}\n" | |
| if [[ -n "${sys_lang}" ]] ; then | |
| bash ${fname} "-"${sys_type} ${sys_ver} -lang $sys_lang | |
| else | |
| bash ${fname} "-"${sys_type} ${sys_ver} | |
| fi | |
| _IS_BREAK="false" | |
| sys_reboot | |
| } | |
| function dd_sys_bin456789(){ | |
| local sys_type=$1 | |
| local sys_ver=$2 | |
| local sys_lang=$3 | |
| local weburl='https://github.com/bin456789/reinstall' | |
| local fname='reinstall.sh' | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh') | |
| if command -v curl &>/dev/null; then | |
| curl -sL -o ${fname} "${url}" && chmod a+x ${fname} | |
| elif command -v wget &>/dev/null; then | |
| wget -qO ${fname} $url && chmod a+x ${fname} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| _IS_BREAK="true" | |
| return | |
| fi | |
| if [[ -n "${sys_lang}" ]] ; then | |
| sys_lang='en-us' | |
| [[ "${sys_lang}" == "cn" ]] && sys_lang='zh-cn' | |
| bash ${fname} ${sys_type} ${sys_ver} --lang $sys_lang | |
| else | |
| bash ${fname} ${sys_type} ${sys_ver} | |
| fi | |
| _IS_BREAK="false" | |
| sys_reboot | |
| } | |
| clear | |
| local num_split=40 | |
| print_sub_head " DD系统 " $num_split 1 0 | |
| # print_items_list sys_dd_options[@] " ⚓ DD系统脚本选择:" | |
| split_menu_items systems_list[@] | |
| print_sub_menu_tail $num_split | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择要DD的系统: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'alpine' '' | |
| ;; | |
| 2) | |
| dd_sys_mollylau 'alpine' 3.20 | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| ;; | |
| 3) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'alpine' 3.19 | |
| ;; | |
| 4) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'alpine' 3.18 | |
| ;; | |
| 11) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'debian' 12 | |
| ;; | |
| 12) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'debian' 11 | |
| ;; | |
| 13) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'debian' 10 | |
| ;; | |
| 14) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'ubuntu' 24.04 | |
| ;; | |
| 15) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'ubuntu' 22.04 | |
| ;; | |
| 16) | |
| dd_sys_login_info 'root' 'LeitboGi0ro' '22' | |
| dd_sys_mollylau 'ubuntu' 20.04 | |
| ;; | |
| 21) | |
| dd_sys_login_info 'root' '123@@@' '22' | |
| dd_sys_bin456789 'almalinux' 9 | |
| ;; | |
| 22) | |
| dd_sys_login_info 'root' '123@@@' '22' | |
| dd_sys_bin456789 'almalinux' 8 | |
| ;; | |
| 23) | |
| dd_sys_login_info 'root' '123@@@' '22' | |
| dd_sys_bin456789 'rocky' 9 | |
| ;; | |
| 24) | |
| dd_sys_login_info 'root' '123@@@' '22' | |
| dd_sys_bin456789 'rocky' 8 | |
| ;; | |
| 31) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' 'Teddysun.com' '3389' | |
| # dd_sys_bin456789 'windows' 2025 $lang | |
| bash reinstall.sh dd --img "https://dl.lamp.sh/vhd/zh-cn_win2025.xz" | |
| ;; | |
| 32) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' 'Teddysun.com' '3389' | |
| dd_sys_mollylau 'windows' 2022 $lang | |
| ;; | |
| 33) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' 'Teddysun.com' '3389' | |
| dd_sys_mollylau 'windows' 2019 $lang | |
| ;; | |
| 34) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' 'Teddysun.com' '3389' | |
| dd_sys_mollylau 'windows' 11 $lang | |
| ;; | |
| 35) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' 'Teddysun.com' '3389' | |
| dd_sys_mollylau 'windows' 10 $lang | |
| ;; | |
| 36) | |
| local lang=$(get_sys_lang) | |
| dd_sys_login_info 'Administrator' '123@@@' '3389' | |
| dd_sys_mollylau 'windows' 7 $lang | |
| ;; | |
| 88) | |
| sys_update | |
| _BREAK_INFO=" 从 41合一脚本DD系统 返回" | |
| local fname='NewReinstall.sh' | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/fcurrk/reinstall/master/NewReinstall.sh') | |
| if command -v curl &>/dev/null; then | |
| curl -sL -o ${fname} "${url}" && chmod a+x ${fname} && bash ${fname} | |
| elif command -v wget &>/dev/null; then | |
| wget -qO ${fname} $url && chmod a+x ${fname} && bash ${fname} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| fi | |
| # wget --no-check-certificate -O NewReinstall.sh https://raw.githubusercontent.com/fcurrk/reinstall/master/NewReinstall.sh && chmod a+x NewReinstall.sh && bash NewReinstall.sh | |
| ;; | |
| 99) system_dd_usage && _BREAK_INFO=" DD系统说明 " ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| xx) sys_reboot ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| function sys_setting_alter_swap(){ | |
| local swap_used=$(free -m | awk 'NR==3{print $3}') | |
| local swap_total=$(free -m | awk 'NR==3{print $2}') | |
| local swap_info=$(free -m | awk 'NR==3{used=$3; total=$2; if (total == 0) {percentage=0} else {percentage=used*100/total}; printf "%dM/%dM (%d%%)", used, total, percentage}') | |
| local swap_size_options=( | |
| "1. 1024M" | |
| "2. 2048M" | |
| "3. 4096M" | |
| "4. 8192M" | |
| "5. 自定义" | |
| "0. 返回" | |
| ) | |
| _IS_BREAK="true" | |
| print_items_list swap_size_options[@] " ⚓ 虚拟内存容量菜单:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| add_swap 1024 | |
| _BREAK_INFO=" 已设置1G虚拟内存!" | |
| ;; | |
| 2) | |
| add_swap 2048 | |
| _BREAK_INFO=" 已设置2G虚拟内存!" | |
| ;; | |
| 3) | |
| add_swap 4096 | |
| _BREAK_INFO=" 已设置4G虚拟内存!" | |
| ;; | |
| 4) | |
| add_swap 8192 | |
| _BREAK_INFO=" 已设置8G虚拟内存!" | |
| ;; | |
| 5) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入要设置的虚拟内存大小(M): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| if [[ $INPUT =~ ^[0-9]+$ ]]; then | |
| add_swap $INPUT | |
| _BREAK_INFO=" 已设置${INPUT}M虚拟内存!" | |
| else | |
| _BREAK_INFO=" 虚拟内存大小输入错误,格式有误,应为数字!" | |
| fi | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function sys_setting_enable_ssh_reproxy(){ | |
| # 这项功能主要用于将服务器作为中转站,进行网络请求的转发 | |
| sed -i 's/^#\?AllowTcpForwarding.*/AllowTcpForwarding yes/g' /etc/ssh/sshd_config; | |
| sed -i 's/^#\?GatewayPorts.*/GatewayPorts yes/g' /etc/ssh/sshd_config; | |
| service sshd restart | |
| _BREAK_INFO=" 已开启SSH转发功能" | |
| _IS_BREAK="true" | |
| } | |
| function sys_setting_alter_priority_v4v6(){ | |
| local ipv6_disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6) | |
| if [ "$ipv6_disabled" -eq 1 ]; then | |
| echo -e "\n${PRIGHT} 当前网络: IPv4 优先\n" | |
| else | |
| echo -e "\n${PRIGHT} 当前网络: IPv6 优先\n" | |
| fi | |
| local net_1st_options=( | |
| "1.IPv4优先" | |
| "2.IPv6优先" | |
| "3.IPv6修复" | |
| "0.返回" | |
| ) | |
| _IS_BREAK="true" | |
| print_items_list net_1st_options[@] " ⚓ 功能菜单:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| sysctl -w net.ipv6.conf.all.disable_ipv6=1 > /dev/null 2>&1 | |
| echo "已切换为 IPv4 优先" | |
| _BREAK_INFO=" 已切换为 IPv4 优先!" | |
| ;; | |
| 2) | |
| sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null 2>&1 | |
| echo "已切换为 IPv6 优先" | |
| _BREAK_INFO=" 已切换为 IPv6 优先!" | |
| ;; | |
| 3) | |
| bash <(curl -L -s jhb.ovh/jb/v6.sh) | |
| # echo "该功能由jhb大神提供,感谢他!" | |
| _BREAK_INFO=" IPv6 修复成功!(jhb脚本)" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function sys_setting_bbrv3_manage(){ | |
| local cpu_arch=$(uname -m) | |
| if [ "$cpu_arch" = "aarch64" ]; then | |
| bash <(curl -sL jhb.ovh/jb/bbrv3arm.sh) | |
| _BREAK_INFO=" 系统为ARM架构,已使用jhb的bbrv3arm.sh安装BBRv3内核" | |
| _IS_BREAK="true" | |
| case_end_tackle | |
| continue | |
| fi | |
| if dpkg -l | grep -q 'linux-xanmod'; then | |
| local bbrv3_1st_options=( | |
| "1.更新BBRv3" | |
| "2.卸载BBRv3" | |
| "0.返回" | |
| ) | |
| _IS_BREAK="true" | |
| local kernel_version=$(uname -r) | |
| echo -e "\n$TIP 系统已安装xanmod的BBRv3内核" | |
| echo -e "\n$PRIGHT 当前内核版本: $kernel_version" | |
| print_items_list bbrv3_1st_options[@] " ⚓ BBRv3功能选项:" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| apt purge -y 'linux-*xanmod1*' | |
| update-grub | |
| # wget -qO - https://dl.xanmod.org/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes | |
| wget -qO - ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/archive.key | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes | |
| # 步骤3:添加存储库 | |
| echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list | |
| # version=$(wget -q https://dl.xanmod.org/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') | |
| local version=$(wget -q ${gh_proxy}raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') | |
| apt update -y | |
| apt install -y linux-xanmod-x64v$version | |
| echo "XanMod内核已更新。重启后生效" | |
| rm -f /etc/apt/sources.list.d/xanmod-release.list | |
| rm -f check_x86-64_psabi.sh* | |
| _BREAK_INFO=" 已更新 linux-xammod1内核 !" | |
| _IS_BREAK="false" | |
| case_end_tackle | |
| sys_reboot | |
| continue | |
| ;; | |
| 2) | |
| apt purge -y 'linux-*xanmod1*' | |
| update-grub | |
| echo "XanMod内核已卸载。重启后生效" | |
| _BREAK_INFO=" XanMod内核已卸载。重启后生效" | |
| _IS_BREAK="false" | |
| case_end_tackle | |
| sys_reboot | |
| continue | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| else | |
| clear | |
| echo -e "$PRIGHT 设置BBR3加速 " | |
| echo -e "=========================================================" | |
| echo -e " 仅支持[Debian|Ubuntu|Alpine]" | |
| echo -e " 请备份数据,将为你升级Linux内核开启BBR3" | |
| echo -e " 若系统内存为${RED}512M${RESET},请提前添加1G虚拟内存,以防机器失联!" | |
| echo -e "=========================================================" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定继续安装BBRv3? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| if [ -r /etc/os-release ]; then | |
| . /etc/os-release | |
| if [ "$ID" == "alpine" ]; then | |
| bbr_on | |
| _BREAK_INFO=" 当前为Alpine系统" | |
| _IS_BREAK="false" | |
| case_end_tackle | |
| sys_reboot | |
| continue | |
| elif [ "$ID" != "debian" ] && [ "$ID" != "ubuntu" ]; then | |
| _BREAK_INFO=" 当前环境不支持, 仅支持Alpine,Debian和Ubuntu系统" | |
| _IS_BREAK="true" | |
| case_end_tackle | |
| continue | |
| fi | |
| else | |
| echo "无法确定操作系统类型" | |
| _BREAK_INFO=" 无法确定操作系统类型" | |
| _IS_BREAK="true" | |
| case_end_tackle | |
| continue | |
| fi | |
| check_swap | |
| app_install wget gnupg | |
| local url=$(get_proxy_url "https://raw.githubusercontent.com/kejilion/sh/main/archive.key") | |
| wget -qO - ${url} | gpg --dearmor -o /usr/share/keyrings/xanmod-archive-keyring.gpg --yes | |
| # 步骤3:添加存储库 | |
| echo 'deb [signed-by=/usr/share/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org releases main' | tee /etc/apt/sources.list.d/xanmod-release.list | |
| local url=$(get_proxy_url "https://raw.githubusercontent.com/kejilion/sh/main/check_x86-64_psabi.sh") | |
| local version=$(wget -q ${url} && chmod +x check_x86-64_psabi.sh && ./check_x86-64_psabi.sh | grep -oP 'x86-64-v\K\d+|x86-64-v\d+') | |
| apt update -y | |
| apt install -y linux-xanmod-x64v$version | |
| bbr_on | |
| rm -f /etc/apt/sources.list.d/xanmod-release.list | |
| rm -f check_x86-64_psabi.sh* | |
| _BREAK_INFO=" XanMod内核安装并BBR3启用成功。重启后生效" | |
| _IS_BREAK="false" | |
| sys_reboot | |
| continue | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 已取消" | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 无效的选择。" | |
| _IS_BREAK="true" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function sys_setting_beautify_cmd_style(){ | |
| function print_better_cmd_style_options(){ | |
| echo -e "" | |
| # echo -e " 1. \033[1;32mroot@\033[1;34mlocalhost \033[1;31m~ ${RESET}#" | |
| # echo -e " 2. \033[1;35mroot@\033[1;36mlocalhost \033[1;33m~ ${RESET}#" | |
| # echo -e " 3. \033[1;31mroot@\033[1;32mlocalhost \033[1;34m~ ${RESET}#" | |
| # echo -e " 4. \033[1;36mroot@\033[1;33mlocalhost \033[1;37m~ ${RESET}#" | |
| # echo -e " 5. \033[1;37mroot@\033[1;31mlocalhost \033[1;32m~ ${RESET}#" | |
| # echo -e " 6. \033[1;33mroot@\033[1;34mlocalhost \033[1;35m~ ${RESET}#" | |
| echo -e " 1. ${FCGR}root@${FCLS}localhost ${FCRE}~ ${RESET}#" # 绿, 蓝, 红 | |
| echo -e " 2. ${FCZS}root@${FCTL}localhost ${FCYE}~ ${RESET}#" # 紫,天蓝, 黄 | |
| echo -e " 3. ${FCRE}root@${FCGR}localhost ${FCLS}~ ${RESET}#" # 红, 绿, 蓝 | |
| echo -e " 4. ${FCTL}root@${FCYE}localhost ${FCQH}~ ${RESET}#" # 天蓝,黄,浅灰 | |
| echo -e " 5. ${FCQH}root@${FCRE}localhost ${FCGR}~ ${RESET}#" # 浅灰,红, 绿 | |
| echo -e " 6. ${FCYE}root@${FCLS}localhost ${FCZS}~ ${RESET}#" # 黄, 蓝, 紫 | |
| echo -e " 7. root@localhost ~ #" | |
| echo -e " 0. 返回" | |
| } | |
| function shell_custom_style_profile() { | |
| local ss="$1" | |
| if command -v dnf &>/dev/null || command -v yum &>/dev/null; then | |
| sed -i '/^PS1=/d' ~/.bashrc | |
| echo "${ss}" >> ~/.bashrc | |
| # source ~/.bashrc | |
| else | |
| sed -i '/^PS1=/d' ~/.profile | |
| echo "${ss}" >> ~/.profile | |
| # source ~/.profile | |
| fi | |
| hash -r | |
| } | |
| _IS_BREAK="true" | |
| print_better_cmd_style_options | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 选择命令行样式? ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| local bianse="PS1='\[\033[1;32m\]\u\[\033[0m\]@\[\033[1;34m\]\h\[\033[0m\] \[\033[1;31m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(绿, 蓝, 红),重启终端后生效" | |
| ;; | |
| 2) | |
| local bianse="PS1='\[\033[1;35m\]\u\[\033[0m\]@\[\033[1;36m\]\h\[\033[0m\] \[\033[1;33m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(紫,天蓝, 黄 ),重启终端后生效" | |
| ;; | |
| 3) | |
| local bianse="PS1='\[\033[1;31m\]\u\[\033[0m\]@\[\033[1;32m\]\h\[\033[0m\] \[\033[1;34m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(红,绿, 蓝),重启终端后生效" | |
| ;; | |
| 4) | |
| local bianse="PS1='\[\033[1;36m\]\u\[\033[0m\]@\[\033[1;33m\]\h\[\033[0m\] \[\033[1;37m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(天蓝,黄,浅灰 ),重启终端后生效" | |
| ;; | |
| 5) | |
| local bianse="PS1='\[\033[1;37m\]\u\[\033[0m\]@\[\033[1;31m\]\h\[\033[0m\] \[\033[1;32m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(浅灰,红, 绿 ),重启终端后生效" | |
| ;; | |
| 6) | |
| local bianse="PS1='\[\033[1;33m\]\u\[\033[0m\]@\[\033[1;34m\]\h\[\033[0m\] \[\033[1;35m\]\w\[\033[0m\] # '" | |
| shell_custom_style_profile "${bianse}" | |
| _BREAK_INFO=" 已美化命令行样式(黄, 蓝, 紫 ),重启终端后生效" | |
| ;; | |
| 7) | |
| shell_custom_style_profile '' | |
| _BREAK_INFO=" 命令行无样式,重启终端后生效" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| while true; do | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1 ) sys_setting_change_root_password ;; | |
| 2 ) sys_setting_enable_root ;; | |
| 3 ) sys_setting_disable_root ;; | |
| 4 ) sys_setting_alter_sources ;; | |
| 5 ) sys_setting_dns_manage ;; | |
| 6 ) sys_setting_change_change_hostname ;; | |
| 7 ) sys_setting_alter_timezone ;; | |
| 8 ) sys_setting_users_manage ;; | |
| 9 ) sys_setting_change_ports_manage ;; | |
| 21) sys_setting_dd_system ;; | |
| 22) sys_setting_alter_swap ;; | |
| 23) sys_setting_enable_ssh_reproxy ;; | |
| 24) sys_setting_alter_priority_v4v6 ;; | |
| 25) sys_setting_bbrv3_manage ;; | |
| 27) sys_setting_beautify_cmd_style ;; | |
| 28) set_qiq_alias 1 && _BREAK_INFO=" 成功设置qiq快捷命令 " ;; | |
| 29) del_qiq_alias && _BREAK_INFO=" 成功删除qiq快捷命令 " ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 定义性能测试数组 | |
| MENU_COMMONLY_TOOLS_ITEMS=( | |
| "1|curl|$WHITE" | |
| "2|wget|$WHITE" | |
| "3|gdu|$MAGENTA" | |
| "4|btop|$WHITE" | |
| "5|htop|$WHITE" | |
| "6|iftop|$WHITE" | |
| "7|unzip|$WHITE" | |
| "8|Fail2Ban|$YELLOW" | |
| "9|SuperVisor|$YELLOW" | |
| "………………………|$WHITE" | |
| "21|安装常用|$CYAN" | |
| "22|安装指定|$WHITE" | |
| "23|卸载指定|$WHITE" | |
| "24|全部安装|$CYAN" | |
| "25|全部卸载|$WHITE" | |
| "………………………|$WHITE" | |
| "31|贪吃蛇|$WHITE" | |
| "32|俄罗期方块|$WHITE" | |
| "33|太空入侵者|$WHITE" | |
| "34|跑火车屏保(sl)|$WHITE" | |
| "35|黑客帝国屏保(cmatrix)|$WHITE" | |
| "36|最新天气☀|$WHITE" | |
| ) | |
| function commonly_tools_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| # local num_split=$MAX_SPLIT_CHAR_NUM | |
| local num_split=40 | |
| print_sub_head "▼ 常用工具 " $num_split 1 0 | |
| split_menu_items MENU_COMMONLY_TOOLS_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| while true; do | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| local app_name='curl' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| _IS_BREAK='true' | |
| ;; | |
| 2) | |
| local app_name='wget' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install wget | |
| _IS_BREAK='true' | |
| ;; | |
| 3) | |
| local app_name='gdu' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install gdu | |
| _IS_BREAK='true' | |
| ;; | |
| 4) | |
| local app_name='btop' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install btop | |
| _IS_BREAK='true' | |
| ;; | |
| 5) | |
| local app_name='htop' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install htop | |
| _IS_BREAK='true' | |
| ;; | |
| 6) | |
| local app_name='iftop' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install iftop | |
| _IS_BREAK='true' | |
| ;; | |
| 7) | |
| local app_name='unzip' | |
| app_install ${app_name} | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| app_install unzip | |
| _IS_BREAK='true' | |
| ;; | |
| 8) | |
| local app_name='fail2ban' | |
| if ! systemctl status ${app_name} > /dev/null 2>&1; then | |
| app_install ${app_name} | |
| app_install rsyslog | |
| sudo systemctl start ${app_name} | |
| sudo systemctl enable ${app_name} | |
| sudo systemctl status ${app_name} | |
| fi | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| _IS_BREAK='true' | |
| ;; | |
| 9) | |
| local app_name='supervisor' | |
| if ! systemctl status ${app_name} > /dev/null 2>&1; then | |
| app_install ${app_name} | |
| fi | |
| echo -e "\n $PRIGHT ${app_name}已安装:" | |
| _IS_BREAK='true' | |
| ;; | |
| 21) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否要安装常用的工具(curl wget btop gdu supervisor fail2ban)? [Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z $INPUT ]] && INPUT='Y' | |
| if [[ $INPUT == [Yy] || $INPUT == [Yy][Ee][Ss] ]]; then | |
| app_install curl | |
| app_install wget | |
| app_install btop | |
| app_install gdu | |
| app_install supervisor | |
| app_install fail2ban | |
| app_install rsyslog | |
| sudo systemctl start fail2ban | |
| sudo systemctl enable fail2ban | |
| sudo systemctl status fail2ban | |
| fi | |
| echo -e "\n $PRIGHT 已安装常用工具:(curl wget btop gdu supervisor fail2ban)" | |
| _IS_BREAK='true' | |
| ;; | |
| 24) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否要安装常用的工具(wget btop gdu supervisor fail2ban)? [Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z $INPUT ]] && INPUT='Y' | |
| if [[ $INPUT == [Yy] || $INPUT == [Yy][Ee][Ss] ]]; then | |
| # app_install curl | |
| app_install wget | |
| app_install btop | |
| app_install gdu | |
| app_install supervisor | |
| app_install fail2ban | |
| app_install rsyslog | |
| sudo systemctl start fail2ban | |
| sudo systemctl enable fail2ban | |
| sudo systemctl status fail2ban | |
| fi | |
| echo -e "\n $PRIGHT 已安装常用工具:(wget btop gdu supervisor fail2ban)" | |
| _IS_BREAK='true' | |
| ;; | |
| 25) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否要卸载常用的工具(wget btop gdu supervisor fail2ban)? [Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z $INPUT ]] && INPUT='Y' | |
| if [[ $INPUT == [Yy] || $INPUT == [Yy][Ee][Ss] ]]; then | |
| # app_remove curl | |
| app_remove wget | |
| app_remove btop | |
| app_remove gdu | |
| app_remove supervisor | |
| sudo systemctl stop fail2ban | |
| app_remove fail2ban | |
| app_remove rsyslog | |
| sys_clean | |
| fi | |
| echo -e "\n $PRIGHT 已卸载常用工具:(wget btop gdu supervisor fail2ban)" | |
| _IS_BREAK='true' | |
| ;; | |
| 22) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入要安装的名称: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n $INPUT ]] && app_install $INPUT | |
| echo -e "\n $PRIGHT ${INPUT}已安装:" | |
| _IS_BREAK='true' | |
| ;; | |
| 23) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入要卸载的名称: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n $INPUT ]] && app_remove $INPUT | |
| echo -e "\n $PRIGHT ${INPUT}已卸载:" | |
| _IS_BREAK='true' | |
| ;; | |
| 31) | |
| app_install nsnake | |
| clear | |
| /usr/games/nsnake | |
| ;; | |
| 32) | |
| app_install bastet | |
| clear | |
| /usr/games/bastet | |
| ;; | |
| 33) | |
| app_install ninvaders | |
| clear | |
| /usr/games/ninvaders | |
| ;; | |
| 34) | |
| app_install sl | |
| clear | |
| /usr/games/sl | |
| ;; | |
| 35) | |
| app_install cmatrix | |
| clear | |
| cmatrix | |
| ;; | |
| 36) | |
| clear | |
| curl wttr.in | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" > curl wttr.in " | |
| ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 常用面板和软件 | |
| MENU_SERVICE_TOOLS_ITEMS=( | |
| "1|1Panel|$YELLOW" | |
| "2|aaPanel|$WHITE" | |
| "3|Ajenti|$WHITE" | |
| "4|Cockpit|$WHITE" | |
| "5|VestaCP|$WHITE" | |
| "6|HestiaCP|$CYAN" | |
| "7|CloudPanel|$CYAN" | |
| "8|Cyberpanel|$WHITE" | |
| "………………………|$WHITE" | |
| "21|Redis|$CYAN" | |
| "22|MySQL|$WHITE" | |
| "23|MariaDB|$WHITE" | |
| "24|PostgreSQL|$WHITE" | |
| "25|frps|$WHITE" | |
| "26|frpc|$WHITE" | |
| "27|Lucky|$WHITE" | |
| "28|Nezha|$WHITE" | |
| "29|Chrome|$WHITE" | |
| "30|Coder|$WHITE" | |
| "31|Code Server|$YELLOW" | |
| "32|Akile Monitor|$WHITE" | |
| "………………………|$WHITE" | |
| "41|RustDesk|$WHITE" | |
| "42|SubLinkX|$WHITE" | |
| "43|DeepLX|$WHITE" | |
| "44|iyCMS|$GREEN" | |
| "45|V2RayA|$WHITE" | |
| "46|Singbox(@farsman)|$YELLOW" | |
| "47|Singbox(@ygkkk)|$WHITE" | |
| "48|Warp(@farsman)|$YELLOW" | |
| "49|Warp(@ygkkk)|$YELLOW" | |
| "50|Warp(@hamid)|$WHITE" | |
| ) | |
| function service_tools_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| # local num_split=$MAX_SPLIT_CHAR_NUM | |
| local num_split=40 | |
| print_sub_head "▼ 服务工具 " $num_split 1 0 | |
| split_menu_items MENU_SERVICE_TOOLS_ITEMS[@] 1 30 | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| # 获取当前系统类型 | |
| function get_system_type() { | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| if [ "$ID" == "centos" ]; then | |
| echo "centos" | |
| elif [ "$ID" == "ubuntu" ]; then | |
| echo "ubuntu" | |
| elif [ "$ID" == "debian" ]; then | |
| echo "debian" | |
| else | |
| echo "unknown" | |
| fi | |
| else | |
| echo "unknown" | |
| fi | |
| } | |
| function tools_install_1panel(){ | |
| _IS_BREAK="true" | |
| local app_name='1Panel' | |
| if command -v 1pctl &> /dev/null; then | |
| ## 系统已安装1Panel | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| ## 系统未安装1Panel | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| # sys_update | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| if [ "$system_type" == "centos" ]; then | |
| curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh | |
| elif [ "$system_type" == "ubuntu" ]; then | |
| curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && bash quick_start.sh | |
| elif [ "$system_type" == "debian" ]; then | |
| curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && bash quick_start.sh | |
| else | |
| bash <(curl -sSL https://linuxmirrors.cn/docker.sh) && curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh | |
| fi | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_aaPanel(){ | |
| _IS_BREAK="true" | |
| local app_name='aaPanel' | |
| if [ -f "/etc/init.d/bt" ] && [ -d "/www/server/panel" ]; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| # sys_update | |
| app_install wget | |
| _BREAK_INFO=" 成功安装: ${app_name}!" | |
| if [ "$system_type" == "centos" ]; then | |
| yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh aapanel | |
| elif [ "$system_type" == "ubuntu" ]; then | |
| wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && bash install.sh aapanel | |
| elif [ "$system_type" == "debian" ]; then | |
| wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && bash install.sh aapanel | |
| else | |
| _BREAK_INFO=" 不支持的系统类型(Debian|Ubuntu|CentOS), aaPanel安装取消!" | |
| fi | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装: ${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_ajenti(){ | |
| _IS_BREAK="true" | |
| local app_name='Ajenti' | |
| if systemctl status ajenti.service &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| # https://docs.ajenti.org/en/latest/man/install.html | |
| # curl https://raw.githubusercontent.com/ajenti/ajenti/master/scripts/install-venv.sh | sudo bash -s - | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/ajenti/ajenti/master/scripts/install.sh') | |
| curl $url | sudo bash -s - | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_cockpit(){ | |
| _IS_BREAK="true" | |
| local app_name='Cockpit' | |
| if systemctl status cockpit.socket &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| # https://cockpit-project.org/running.html | |
| # http://localip:9090 | |
| # systemctl start --now cockpit.socket | |
| # systemctl enable --now cockpit.socket | |
| sys_update | |
| app_install cockpit && systemctl start --now cockpit.socket && systemctl enable --now cockpit.socket | |
| # app_install cockpit* # 安装所有相关的插件 | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_vestacp(){ | |
| _IS_BREAK="true" | |
| local app_name='HestiaCP' | |
| _BREAK_INFO=" 尚未实现VestaCP的安装!" | |
| } | |
| function tools_install_hestiacp(){ | |
| _IS_BREAK="true" | |
| local app_name='HestiaCP' | |
| # if [ -f "/etc/init.d/bt" ] && [ -d "/www/server/panel" ]; then | |
| # _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| # else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| # https://hestiacp.com/docs/introduction/getting-started.html | |
| # https://hestiacp.com/install | |
| # sys_update | |
| app_install wget | |
| local url=$(get_proxy_url 'https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh') | |
| wget $url && apt-get update && apt-get install ca-certificates && bash hst-install.sh | |
| _BREAK_INFO=" 成功安装: ${app_name}!" | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装: ${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| # fi | |
| } | |
| function tools_install_cloudpanel(){ | |
| _IS_BREAK="true" | |
| local app_name='CloudPanel' | |
| if systemctl status ajenti.service &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| # https://www.cloudpanel.io/docs/v2/getting-started/other/ | |
| # https://yourIpAddress:8443 | |
| echo -e "$PRIGHT 1. MySQL 8.0" | |
| echo -e "$PRIGHT 2. MariaDB 11.4" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择要安装的数据库(默认MySQL): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="1" | |
| case "$INPUT" in | |
| 1) | |
| local url=$(get_proxy_url 'https://installer.cloudpanel.io/ce/v2/install.sh') | |
| curl -sS $url -o install.sh; \ | |
| echo "a3ba69a8102345127b4ae0e28cfe89daca675cbc63cd39225133cdd2fa02ad36 install.sh" | \ | |
| sha256sum -c && sudo bash install.sh | |
| _BREAK_INFO=" 成功安装${app_name}(MySQL 8.0)!" | |
| ;; | |
| 2) | |
| local url=$(get_proxy_url 'https://installer.cloudpanel.io/ce/v2/install.sh') | |
| curl -sS $url -o install.sh; \ | |
| echo "a3ba69a8102345127b4ae0e28cfe89daca675cbc63cd39225133cdd2fa02ad36 install.sh" | \ | |
| sha256sum -c && sudo bash install.sh | |
| _BREAK_INFO=" 成功安装${app_name}(MariaDB 11.4)!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| # 安装MariaDb数据库 | |
| # curl -sS $url -o install.sh; \ | |
| # echo "a3ba69a8102345127b4ae0e28cfe89daca675cbc63cd39225133cdd2fa02ad36 install.sh" | \ | |
| # sha256sum -c && sudo DB_ENGINE=MARIADB_11.4 bash install.sh | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_cyberpanel(){ | |
| _IS_BREAK="true" | |
| local app_name='CyberPanel' | |
| if systemctl status ajenti.service &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| local system_type=$(get_system_type) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 确定安装${app_name}吗? (Y/n): ${PLAIN}") | |
| [[ -z "${INPUT}" ]] && INPUT="Y" | |
| read -rp "${CHOICE}" INPUT | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| # https://cyberpanel.net/KnowledgeBase/home/install-cyberpanel/ | |
| # https://github.com/usmannasir/cyberpanel | |
| # https://yourIpAddress:8443 | |
| # Ubuntu 18.04, Ubuntu 20.04, AlmaLinux 8, AlmaLinux 9, Ubuntu 22.04, CloudLinux 8. 1024MB RAM, or higher | |
| local url_install='https://cyberpanel.net/install.sh' | |
| local url_update=$(get_proxy_url 'https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgrade.sh') | |
| sh <(curl $url_install || wget -O - $url_install) | |
| # sh <(curl $url_update || wget -O - $url_update) | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| _BREAK_INFO=" 取消安装${app_name}!" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 输入错误,请重新输入!" | |
| ;; | |
| esac | |
| fi | |
| } | |
| function tools_install_redis(){ | |
| local app_name='Redis' | |
| local app_cmd='redis' | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| # echo -e " > WebURL: https://coder.com/ " | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:6379 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:6379 " | |
| } | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name}数据库,无需重复安装!" | |
| # print_app_usage | |
| else | |
| curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg | |
| echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list | |
| apt update | |
| apt install redis | |
| systemctl start redis-server | |
| systemctl enable redis-server | |
| # print_app_usage | |
| _BREAK_INFO=" 成功安装${app_name}数据库!" | |
| fi | |
| } | |
| function tools_install_mysql(){ | |
| local app_name='MySQL' | |
| local app_cmd='mysql' | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| # function print_app_usage(){ | |
| # echo -e "\n${BOLD} ${POINTING} ${app_name}使用说明: ${PLAIN}\n" | |
| # # echo -e " > WebURL: https://coder.com/ " | |
| # echo "" | |
| # [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:6379 " | |
| # [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:6379 " | |
| # } | |
| # if command -v ${app_cmd} &> /dev/null; then | |
| # _BREAK_INFO=" 系统已安装${app_name}数据库,无需重复安装!" | |
| # # print_app_usage | |
| # else | |
| # curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg | |
| # echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list | |
| # apt update | |
| # apt install redis | |
| # systemctl start redis-server | |
| # systemctl enable redis-server | |
| # # print_app_usage | |
| # _BREAK_INFO=" 成功安装${app_name}数据库!" | |
| # fi | |
| _BREAK_INFO=" 尚未实现安装${app_name}数据库!" | |
| } | |
| function tools_install_mariadb(){ | |
| local app_name='MariaDB' | |
| local app_cmd='mariadb' | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name}数据库,无需重复安装!" | |
| else | |
| apt install apt-transport-https curl | |
| mkdir -p /etc/apt/keyrings | |
| curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp' | |
| cat > /etc/apt/sources.list.d/mariadb.sources << EOF | |
| X-Repolib-Name: MariaDB | |
| Types: deb | |
| # deb.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details. | |
| URIs: https://deb.mariadb.org/11.2/ubuntu | |
| Suites: jammy | |
| Components: main main/debug | |
| Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp | |
| EOF | |
| apt update | |
| apt install mariadb-server | |
| systemctl start mariadb | |
| systemctl enable mariadb | |
| mariadb-secure-installation | |
| _BREAK_INFO=" 成功安装${app_name}数据库!" | |
| fi | |
| } | |
| function tools_install_postgresql(){ | |
| local app_name='PostgreSQL' | |
| local app_cmd='postgresql' | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name}数据库,无需重复安装!" | |
| postgresql_usage | |
| else | |
| install postgresql-client && apt update && install postgresql | |
| postgresql_usage | |
| _BREAK_INFO=" 成功安装${app_name}数据库!" | |
| fi | |
| } | |
| function tools_install_frps(){ | |
| _IS_BREAK="true" | |
| local app_name='frps' | |
| local app_cmd='frps' | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " - GitHub: https://github.com/fatedier/frp/ " | |
| echo -e "" | |
| echo -e " > systemctl status ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl start ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl stop ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl restart ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:7500 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:7500 " | |
| echo "" | |
| } | |
| function download_frp(){ | |
| local arch=$(uname -m) | |
| local url='https://api.github.com/repos/fatedier/frp/releases/latest' | |
| local frp_v=$(curl -s $(get_proxy_url $url) | grep -oP '"tag_name": "v\K.*?(?=")') | |
| if [[ "$arch" == "x86_64" ]]; then | |
| url=$(get_proxy_url 'https://github.com/fatedier/frp/releases/download') | |
| curl -L ${url}/v${frp_v}/frp_${frp_v}_linux_amd64.tar.gz -o frp_${frp_v}_linux_amd64.tar.gz | |
| elif [[ "$arch" == "armv7l" || "$arch" == "aarch64" ]]; then | |
| curl -L ${url}/v${frp_v}/frp_${frp_v}_linux_arm.tar.gz -o frp_${frp_v}_linux_amd64.tar.gz | |
| else | |
| echo " 不支持当前CPU架构: $arch" | |
| _BREAK_INFO=" 不支持当前CPU架构: $arch!" | |
| return 1 | |
| fi | |
| # 解压 .tar.gz 文件 | |
| app_install tar | |
| tar -zxvf frp_*.tar.gz | |
| dir_name=$(tar -tzf frp_*.tar.gz | head -n 1 | cut -f 1 -d '/') | |
| mv "$dir_name" frp_0.61.0_linux_amd64 | |
| } | |
| if systemctl status ${app_cmd} > /dev/null 2>&1; then | |
| _BREAK_INFO=" ${app_name}服务已安装,无需重复安装!" | |
| print_app_usage | |
| else | |
| print_app_usage | |
| _BREAK_INFO=" 成功安装: ${app_name}!" | |
| fi | |
| } | |
| function tools_install_frpc(){ | |
| _IS_BREAK="true" | |
| local app_name='Lucky' | |
| local app_cmd='lucky' | |
| _BREAK_INFO=" 尚未实现安装: ${app_name}!" | |
| } | |
| function tools_install_lucky(){ | |
| _IS_BREAK="true" | |
| local app_name='Lucky' | |
| local app_cmd='lucky' | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " > WebURL: https://lucky666.cn " | |
| echo -e " > GitHub: https://github.com/gdy666/lucky " | |
| echo -e "" | |
| echo -e " > systemctl status ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl start ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl stop ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl restart ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:16601 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:16601 " | |
| echo "" | |
| echo -e " > Login account: 666@666" | |
| echo "" | |
| } | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| local file="lucky.sh" | |
| local url="https://release.ilucky.net:66" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $file 0 | |
| print_app_usage | |
| _BREAK_INFO=" 成功安装: ${app_name}!" | |
| fi | |
| # URL="https://release.ilucky.net:66"; curl -o /tmp/install.sh "$URL/install.sh" && sh /tmp/install.sh "$URL" | |
| # URL="https://release.ilucky.net:66"; wget -O /tmp/install.sh "$URL/install.sh" && sh /tmp/install.sh "$URL" | |
| # curl -o /tmp/install.sh https://6.666666.host:66/files/golucky.sh && sh /tmp/install.sh https://6.666666.host:66/files 2.11.2 | |
| } | |
| function tools_install_neza(){ | |
| local app_name='NeZha Monitor' | |
| local app_cmd='nz' | |
| _IS_BREAK="true" | |
| local fname="nezha.sh" | |
| local url="https://raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| _BREAK_INFO=" 从${app_name}返回!" | |
| echo -e "\n $TIP 后续可直接运行脚本: ./${fname}\n" | |
| # curl -L https://raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh | |
| } | |
| function tools_install_chrome(){ | |
| _IS_BREAK="true" | |
| local app_name='Chrome' | |
| local app_cmd='chrome' | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| else | |
| _BREAK_INFO=" 成功安装${app_name}!" | |
| local fname="google-chrome-stable_current_amd64.deb" | |
| local url="https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" | |
| sudo apt-get install -f -y && wget ${url} && sudo dpkg -i ${fname} | |
| # sudo apt-get install -f -y | |
| # wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb | |
| # sudo dpkg -i google-chrome-stable_current_amd64.deb | |
| fi | |
| } | |
| function tools_install_coder(){ | |
| local app_name='Coder Server' | |
| local app_cmd='coder server' | |
| _IS_BREAK="true" | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " > WebURL: https://coder.com/ " | |
| echo -e " > WebURL: https://github.com/coder/coder " | |
| echo -e " > Docker: https://github.com/coder/coder/blob/main/docker-compose.yaml " | |
| echo -e "\n > ${app_cmd} # 临时启动${app_name}" | |
| echo -e "\n > sudo systemctl enable --now code-server@$USER # 以当前用户开启${app_name}服务" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:3000 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:3000 " | |
| } | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| _BREAK_INFO=" 成功安装${app_name}服务!" | |
| local file="coder.sh" | |
| local url="https://coder.com/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $file 0 | |
| print_app_usage | |
| fi | |
| # curl -L https://coder.com/install.sh | sh ;; | |
| } | |
| function tools_install_codeserver(){ | |
| local app_name='Code Server' | |
| local app_cmd='code-server' | |
| _IS_BREAK="true" | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " > WebURL: https://coder.com/ " | |
| echo -e " > WebURL: https://github.com/coder/coder " | |
| echo -e " > GitHub: https://github.com/coder/code-server " | |
| echo -e "\n > ${app_cmd} # 临时启动${app_name}" | |
| echo -e "\n > sudo systemctl enable --now code-server@$USER # 以当前用户开启${app_name}服务" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:8080 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:8080 " | |
| } | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| _BREAK_INFO=" 成功安装${app_name}服务!" | |
| local file="code-server.sh" | |
| local url="https://code-server.dev/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $file 0 | |
| print_app_usage | |
| fi | |
| # curl -fsSL https://code-server.dev/install.sh | sh ;; | |
| } | |
| function tools_install_akilemonitor(){ | |
| local app_name='Akile Monitor' | |
| local app_cmd='akm' | |
| _IS_BREAK="true" | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local file="ak-setup.sh" | |
| local url="https://raw.githubusercontent.com/akile-network/akile_monitor/refs/heads/main/${file}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $file 1 | |
| } | |
| function tools_install_rustdesk(){ | |
| _IS_BREAK="true" | |
| local app_name='RustDesk' | |
| local app_cmd='rustdesk' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="rustdesk.sh" | |
| local url="https://raw.githubusercontent.com/dinger1986/rustdeskinstall/master/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| # wget https://raw.githubusercontent.com/dinger1986/rustdeskinstall/master/install.sh && chmod +x install.sh && ./install.sh ;; | |
| } | |
| function tools_install_sublinkx(){ | |
| _IS_BREAK="true" | |
| local app_name='SubLinkX' | |
| local app_cmd='sublink' | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}" | |
| echo -e "\n - GitHub: https://github.com/gooaclok819/sublinkX" | |
| echo -e "\n - ${app_cmd} # 查看${app_name}管理菜单" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:8000 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:8000 " | |
| } | |
| if command -v ${app_cmd} &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| _BREAK_INFO=" 成功安装${app_name}服务!" | |
| local fname="sublinkx.sh" | |
| local url="https://raw.githubusercontent.com/gooaclok819/sublinkX/main/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| print_app_usage | |
| fi | |
| # curl -s https://raw.githubusercontent.com/gooaclok819/sublinkX/main/install.sh | sudo bash | |
| } | |
| function tools_install_deeplx(){ | |
| _IS_BREAK="true" | |
| local app_name='DeepLX' | |
| local app_cmd='deeplx' | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " - WebURL: https://deeplx.owo.network/" | |
| echo -e " - GitHub: https://github.com/OwO-Network/DeepLX" | |
| echo "" | |
| echo -e " > ${app_cmd} # 查看${app_name}运行状态" | |
| echo "" | |
| if [[ -n "$WAN4" ]] ; then | |
| echo "" | |
| echo -e " URL: http://$WAN4:1188" | |
| echo -e " URL: http://$WAN4:1188/translate" | |
| echo -e " URL: http://$WAN4:1188/v1/translate" | |
| echo -e " URL: http://$WAN4:1188/v2/translate" | |
| fi | |
| if [[ -n "$WAN6" ]] ; then | |
| echo "" | |
| echo -e " URL: http://[$WAN6]:1188" | |
| echo -e " URL: http://[$WAN6]:1188/translate" | |
| echo -e " URL: http://[$WAN6]:1188/v1/translate" | |
| echo -e " URL: http://[$WAN6]:1188/v2/translate" | |
| fi | |
| # [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:1188 " | |
| } | |
| if command -v deeplx &> /dev/null; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| _BREAK_INFO=" 成功安装${app_name}服务!" | |
| local fname="deeplx.sh" | |
| local url="https://raw.githubusercontent.com/OwO-Network/DeepLX/main/install.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| print_app_usage | |
| fi | |
| # bash <(curl -Ls https://ssa.sx/dx) | |
| # bash <(curl -Ls https://raw.githubusercontent.com/OwO-Network/DeepLX/main/install.sh) | |
| } | |
| function tools_install_iycms(){ | |
| _IS_BREAK="true" | |
| local app_name='爱影CMS' | |
| local app_cmd='iycms' | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " - WebURL: https://iycms.com/index.html" | |
| echo -e "" | |
| echo -e " > systemctl status ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl start ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl stop ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo -e " > systemctl restart ${app_cmd} # 查看${app_name}服务运行状态" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:21007 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:21007 " | |
| } | |
| if systemctl status iycms > /dev/null 2>&1; then | |
| _BREAK_INFO=" 系统已安装${app_name},无需重复安装!" | |
| print_app_usage | |
| else | |
| local file="lucky.sh" | |
| local url="https://www.iycms.com/api/static/down/linux/ubuntu/install_x86_64.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $file 0 | |
| print_app_usage | |
| _BREAK_INFO=" 成功安装: ${app_name}" | |
| fi | |
| } | |
| function tools_install_v2raya(){ | |
| _IS_BREAK="true" | |
| local app_name='V2RayA' | |
| local app_cmd='v2raya' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| function print_app_usage(){ | |
| echo -e "\n${BOLD} ${PRIGHT} ${app_name}使用说明: ${PLAIN}\n" | |
| echo -e " - WebURL: https://v2raya.org/" | |
| echo -e " - GitHub: https://github.com/v2rayA/v2rayA-installer" | |
| echo "" | |
| echo -e " > ${app_cmd} # 查看${app_name}管理菜单" | |
| echo -e " > sudo systemctl start v2raya.service # 启动${app_name}服务" | |
| echo -e " > sudo systemctl enable v2raya.service # 设置${app_name}自启动" | |
| echo -e " > v2raya-reset-password # 重新设置${app_name}密码" | |
| echo -e " > /usr/local/etc/v2raya # 配置文件目录" | |
| echo "" | |
| [[ -n "$WAN4" ]] && echo -e " URL: http://$WAN4:2017 " | |
| [[ -n "$WAN6" ]] && echo -e " URL: http://[$WAN6]:2017 " | |
| } | |
| # wget -qO - https://apt.v2raya.org/key/public-key.asc | sudo tee /etc/apt/keyrings/v2raya.asc | |
| # echo "deb [signed-by=/etc/apt/keyrings/v2raya.asc] https://apt.v2raya.org/ v2raya main" | sudo tee /etc/apt/sources.list.d/v2raya.list | |
| # sudo apt update | |
| # sudo apt install v2raya v2ray ## 也可以使用 xray 包 | |
| # sudo systemctl start v2raya.service | |
| # sudo systemctl enable v2raya.service | |
| function start_v2ray_service(){ | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否启动${app_name}服务? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 启动服务 ...\n" | |
| sudo systemctl start v2raya.service | |
| _BREAK_INFO=" 服务启动中 ..." | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 不启动服务!" | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误!" | |
| _BREAK_INFO=" 输入错误,不重启系统!" | |
| _IS_BREAK="true" | |
| ;; | |
| esac | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否设置${app_name}服务自启动? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 设置自启动服务 ...\n" | |
| sudo systemctl enable v2raya.service | |
| _BREAK_INFO=" 设置服务自启动成功 ..." | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 不启动服务!" | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误!" | |
| _BREAK_INFO=" 输入错误,不重启系统!" | |
| _IS_BREAK="true" | |
| ;; | |
| esac | |
| } | |
| local v2raya_options_list=( | |
| "1. 安装 V2RayA(v2ray)" | |
| "2. 安装 V2RayA(xray)" | |
| "3. 卸载 V2RayA" | |
| "0. 退出" | |
| ) | |
| local fname="v2raya-installer.sh" | |
| local url="https://github.com/v2rayA/v2rayA-installer/raw/main/installer.sh" | |
| url=$(get_proxy_url "$url") | |
| print_items_list v2raya_options_list[@] " ⚓ ${app_name}菜单" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| _BREAK_INFO=" 成功安装${app_name}(v2ray内核)!" | |
| sudo sh -c "$(wget -qO- ${url})" @ --with-v2ray | |
| print_app_usage | |
| start_v2ray_service | |
| ;; | |
| 2) | |
| _BREAK_INFO=" 成功安装${app_name}(xray内核)!" | |
| sudo sh -c "$(wget -qO- ${url})" @ --with-xray | |
| print_app_usage | |
| start_v2ray_service | |
| ;; | |
| 3) | |
| local fname="v2raya-uninstaller.sh" | |
| local url="https://github.com/v2rayA/v2rayA-installer/raw/main/uninstaller.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| # sudo sh -c "$(wget -qO- ${url})" | |
| _BREAK_INFO=" 成功卸载${app_name}!" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| ;; | |
| esac | |
| } | |
| function tools_install_sbfarsman(){ | |
| _IS_BREAK="true" | |
| local app_name='Singbox' | |
| local app_cmd='sb' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="sing-box.sh" | |
| local url="https://raw.githubusercontent.com/fscarmen/sing-box/main/${fname}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| } | |
| function tools_install_sbygkkk(){ | |
| _IS_BREAK="true" | |
| local app_name='Singbox(yg)' | |
| local app_cmd='sb' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="sb.sh" | |
| local url="https://raw.githubusercontent.com/yonggekkk/sing-box-yg/main/sb.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| } | |
| function tools_install_warpfarsman(){ | |
| _IS_BREAK="true" | |
| local app_name='Warp' | |
| local app_cmd='warp' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="menu.sh" | |
| local url="https://gitlab.com/fscarmen/warp/-/raw/main/${fname}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| } | |
| function tools_install_warpygkkk(){ | |
| _IS_BREAK="true" | |
| local app_name='Warp(yg)' | |
| local app_cmd='sb' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="sb-yg.sh" | |
| local url="https://gitlab.com/rwkgyg/CFwarp/raw/main/CFwarp.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| } | |
| function tools_install_warphamid(){ | |
| _IS_BREAK="true" | |
| local app_name='Warp(hamid)' | |
| local app_cmd='warp' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="warp_proxy.sh" | |
| local ghurl="https://github.com/hamid-gh98" | |
| local url="https://raw.githubusercontent.com/hamid-gh98/x-ui-scripts/main/install_warp_proxy.sh" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 1 | |
| } | |
| while true; do | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1 ) tools_install_1panel ;; | |
| 2 ) tools_install_aaPanel ;; | |
| 3 ) tools_install_ajenti ;; | |
| 4 ) tools_install_cockpit ;; | |
| 6 ) tools_install_hestiacp ;; | |
| 7 ) tools_install_cloudpanel ;; | |
| 8 ) tools_install_cyberpanel ;; | |
| 21) tools_install_redis ;; | |
| 22) tools_install_mysql ;; | |
| 23) tools_install_mariadb ;; | |
| 24) tools_install_postgresql ;; | |
| 25) tools_install_frps ;; | |
| 27) tools_install_lucky ;; | |
| 28) tools_install_neza ;; | |
| 29) tools_install_chrome ;; | |
| 30) tools_install_coder ;; | |
| 31) tools_install_codeserver ;; | |
| 32) tools_install_akilemonitor ;; | |
| 41) tools_install_rustdesk ;; | |
| 42) tools_install_sublinkx ;; | |
| 43) tools_install_deeplx ;; | |
| 44) tools_install_iycms ;; | |
| 45) tools_install_v2raya ;; | |
| 46) tools_install_sbfarsman ;; | |
| 47) tools_install_sbygkkk;; | |
| 48) tools_install_warpfarsman ;; | |
| 49) tools_install_warpygkkk ;; | |
| 50) tools_install_warphamid ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 其他常用脚本 | |
| MENU_OTHER_SCRIPTS_ITEMS=( | |
| "1|KijiLion|$YELLOW" | |
| "2|YiDian(docker)|$WHITE" | |
| "3|YiDian(Nginx)|$WHITE" | |
| "4|YiDian(Serv00)|$WHITE" | |
| "5|LinuxMirrors|$MAGENTA" | |
| "6|LinuxMirrors(edu)|$WHITE" | |
| "7|LinuxMirrors(abroad)|$WHITE" | |
| "8|LinuxMirrors(docker)|$WHITE" | |
| "………………………|$WHITE" | |
| "21|Sky-Box|$WHITE" | |
| ) | |
| function other_scripts_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| local num_split=$MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ 其他脚本 " $num_split 1 0 | |
| split_menu_items MENU_OTHER_SCRIPTS_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| while true; do | |
| print_sub_item_menu_headinfo | |
| _IS_BREAK="true" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) bash <(curl -sL kejilion.sh) && _BREAK_INFO=" 从 kejilion 返回 ... " ;; | |
| 2) | |
| local app_name='1keji_docker' | |
| local app_cmd='1keji_docker' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="1keji_docker.sh" | |
| local url="https://pan.1keji.net/f/rRi2/${fname}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| # echo -e " 1keji_docker.sh 脚本下载中...\n" | |
| # wget -qO 1keji_docker.sh "https://pan.1keji.net/f/rRi2/1keji_docker.sh" && chmod +x 1keji_docker.sh && ./1keji_docker.sh | |
| ;; | |
| 3) | |
| local app_name='1keji_docker' | |
| local app_cmd='1keji_docker' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="1keji_nznginx.sh" | |
| local url="https://pan.1keji.net/f/YJTA/${fname}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| # clear | |
| # echo -e " 1keji_nznginx.sh 脚本下载中...\n" | |
| # wget -qO 1keji_nznginx.sh "https://pan.1keji.net/f/YJTA/1keji_nznginx.sh" && chmod +x 1keji_nznginx.sh && ./1keji_nznginx.sh | |
| ;; | |
| 4) | |
| local app_name='1keji_docker' | |
| local app_cmd='1keji_docker' | |
| _BREAK_INFO=" 由${app_name}返回!" | |
| local fname="1kejiV01.sh" | |
| local url="https://pan.1keji.net/f/ERGcp/${fname}" | |
| echo -e "\n $TIP 开始下载${app_name}脚本...\n url: ${url}\n $RESET" | |
| fetch_script_from_url $url $fname 0 | |
| # clear | |
| # echo -e " 1kejiV01.sh 脚本下载中...\n" | |
| # wget -qO 1kejiV01.sh "https://pan.1keji.net/f/ERGcp/1kejiV01.sh" && chmod +x 1kejiV01.sh && ./1kejiV01.sh | |
| ;; | |
| 5) bash <(curl -sSL https://linuxmirrors.cn/main.sh) && _BREAK_INFO=" 从 linuxmirrors 返回 ... " ;; | |
| 6) bash <(curl -sSL https://linuxmirrors.cn/main.sh) --edu && _BREAK_INFO=" 从 linuxmirrors(edu) 返回 ... " ;; | |
| 7) bash <(curl -sSL https://linuxmirrors.cn/main.sh) --abroad && _BREAK_INFO=" 从 linuxmirrors(abroad) 返回 ... " ;; | |
| 8) bash <(curl -sSL https://linuxmirrors.cn/docker.sh) && _BREAK_INFO=" 从 linuxmirrors(docker) 返回 ... " ;; | |
| 21) | |
| # local country=$(curl -s --connect-timeout 1 --max-time 3 ipinfo.io/country) | |
| local url=$(get_proxy_url "https://raw.githubusercontent.com/BlueSkyXN/SKY-BOX/main/box.sh") | |
| # check_ip_china | |
| # [[ $_IS_CN -eq 1 ]] && url="${URL_PROXY}${url}" | |
| # app_install wget | |
| if command -v wget &> /dev/null ; then | |
| wget -O box.sh "${url}" && chmod +x box.sh && clear && ./box.sh | |
| elif command -v curl &> /dev/null ; then | |
| curl -sSL -o box.sh "${url}" && chmod +x box.sh && clear && ./box.sh | |
| else | |
| echo -e "\n${ERROR} 很抱歉,你的系统不支持 wget 或 curl 命令!${NC}" | |
| fi | |
| _BREAK_INFO=" 从 SKY-BOX 工具箱返回 ... " | |
| ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 安装最新版本的python | |
| function python_update_to_latest() { | |
| # 系统检测 | |
| local OS=$(cat /etc/os-release | grep -o -E "Debian|Ubuntu|CentOS" | head -n 1) | |
| if [[ $OS == "Debian" || $OS == "Ubuntu" || $OS == "CentOS" ]]; then | |
| echo -e "检测到你的系统是 ${YELLOW}${OS}${NC}" | |
| else | |
| echo -e "${RED}很抱歉,你的系统不受支持!${NC}" | |
| return 1 | |
| fi | |
| # 检测安装Python3的版本 | |
| VERSION=$(python3 -V 2>&1 | awk '{print $2}') | |
| # 获取最新Python3版本 | |
| PY_VERSION=$(curl -s https://www.python.org/ | grep "downloads/release" | grep -o 'Python [0-9.]*' | grep -o '[0-9.]*') | |
| # 卸载Python3旧版本 | |
| if [[ $VERSION == "3"* ]]; then | |
| echo -e "${YELLOW}你的Python3版本是${NC}${RED}${VERSION}${NC},${YELLOW}最新版本是${NC}${RED}${PY_VERSION}${NC}" | |
| read -p "是否确认升级最新版Python3?默认不升级 [y/N]: " CONFIRM | |
| if [[ $CONFIRM == "y" ]]; then | |
| if [[ $OS == "CentOS" ]]; then | |
| echo "" | |
| rm-rf /usr/local/python3* >/dev/null 2>&1 | |
| else | |
| apt --purge remove python3 python3-pip -y | |
| rm-rf /usr/local/python3* | |
| fi | |
| else | |
| echo -e "${YELLOW}已取消升级Python3${NC}" | |
| return 1 | |
| fi | |
| else | |
| echo -e "${RED}检测到没有安装Python3。${NC}" | |
| read -p "是否确认安装最新版Python3?默认安装 [Y/n]: " CONFIRM | |
| if [[ $CONFIRM != "n" ]]; then | |
| echo -e "${GREEN}开始安装最新版Python3...${NC}" | |
| else | |
| echo -e "${YELLOW}已取消安装Python3${NC}" | |
| return 1 | |
| fi | |
| fi | |
| # 安装相关依赖 | |
| if [[ $OS == "CentOS" ]]; then | |
| yum update | |
| yum groupinstall -y "development tools" | |
| yum install wget openssl-devel bzip2-devel libffi-devel zlib-devel -y | |
| else | |
| apt update | |
| apt install wget build-essential libreadline-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev -y | |
| fi | |
| # 安装python3 | |
| cd /root/ | |
| wget https://www.python.org/ftp/python/${PY_VERSION}/Python-"$PY_VERSION".tgz | |
| tar -zxf Python-${PY_VERSION}.tgz | |
| cd Python-${PY_VERSION} | |
| ./configure --prefix=/usr/local/python3 | |
| make -j $(nproc) | |
| make install | |
| if [ $? -eq 0 ];then | |
| rm -f /usr/local/bin/python3* | |
| rm -f /usr/local/bin/pip3* | |
| ln -sf /usr/local/python3/bin/python3 /usr/bin/python3 | |
| ln -sf /usr/local/python3/bin/pip3 /usr/bin/pip3 | |
| clear | |
| echo -e "${YELLOW}Python3安装${GREEN}成功,${NC}版本为: ${NC}${GREEN}${PY_VERSION}${NC}" | |
| else | |
| clear | |
| echo -e "${RED}Python3安装失败!${NC}" | |
| exit 1 | |
| fi | |
| cd /root/ && rm -rf Python-${PY_VERSION}.tgz && rm -rf Python-${PY_VERSION} | |
| } | |
| # 安装指定版本的python | |
| function python_install_version() { | |
| local python_version="$1" | |
| if ! grep -q 'export PYENV_ROOT="\$HOME/.pyenv"' ~/.bashrc; then | |
| if command -v yum &>/dev/null; then | |
| yum update -y && yum install git -y | |
| yum groupinstall "Development Tools" -y | |
| yum install openssl-devel bzip2-devel libffi-devel ncurses-devel zlib-devel readline-devel sqlite-devel xz-devel findutils -y | |
| curl -O https://www.openssl.org/source/openssl-1.1.1u.tar.gz | |
| tar -xzf openssl-1.1.1u.tar.gz | |
| cd openssl-1.1.1u | |
| ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl shared zlib | |
| make | |
| make install | |
| echo "/usr/local/openssl/lib" > /etc/ld.so.conf.d/openssl-1.1.1u.conf | |
| ldconfig -v | |
| cd .. | |
| export LDFLAGS="-L/usr/local/openssl/lib" | |
| export CPPFLAGS="-I/usr/local/openssl/include" | |
| export PKG_CONFIG_PATH="/usr/local/openssl/lib/pkgconfig" | |
| elif command -v apt &>/dev/null; then | |
| apt update -y && apt install git -y | |
| apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev libgdbm-dev libnss3-dev libedit-dev -y | |
| elif command -v apk &>/dev/null; then | |
| apk update && apk add git | |
| apk add --no-cache bash gcc musl-dev libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev libc6-compat linux-headers make xz-dev build-base ncurses-dev | |
| else | |
| # echo "未知的包管理器!" | |
| _BREAK_INFO=" 未知的包管理器,无法安装Python${python_version}!" | |
| _IS_BREAK="true" | |
| return | |
| fi | |
| curl https://pyenv.run | bash | |
| cat << EOF >> ~/.bashrc | |
| export PYENV_ROOT="\$HOME/.pyenv" | |
| if [[ -d "\$PYENV_ROOT/bin" ]]; then | |
| export PATH="\$PYENV_ROOT/bin:\$PATH" | |
| fi | |
| eval "\$(pyenv init --path)" | |
| eval "\$(pyenv init -)" | |
| eval "\$(pyenv virtualenv-init -)" | |
| EOF | |
| fi | |
| sleep 1 | |
| source ~/.bashrc | |
| sleep 1 | |
| pyenv install $python_version | |
| pyenv global $python_version | |
| rm -rf /tmp/python-build.* | |
| rm -rf $(pyenv root)/cache/* | |
| local VERSION=$(python -V 2>&1 | awk '{print $2}') | |
| _BREAK_INFO=" 成功安装Python${VERSION}!" | |
| _IS_BREAK="true" | |
| } | |
| # Python管理 | |
| MENU_PYTHON_ITEMS=( | |
| "1|安装Python|$WHITE" | |
| "2|安装pipenv|$WHITE" | |
| "3|安装miniForge|$YELLOW" | |
| "4|安装miniConda|$WHITE" | |
| "5|设置pip源|$WHITE" | |
| "6|设置conda源|$WHITE" | |
| "………………………|$WHITE" | |
| "31|安装dash|$WHITE" | |
| "32|安装julia|$WHITE" | |
| "33|安装gunicorn|$WHITE" | |
| "34|安装hypercorn|$WHITE" | |
| ) | |
| function python_management_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| local num_split=$MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ Python管理 " $num_split 0 0 | |
| local VERSION=$(python3 -V 2>&1 | awk '{print $2}') | |
| echo -e "\n $PRIGHT 当前Python: $VERSION\n" | |
| generate_separator "…|$AZURE" $num_split # 另一个分割线 | |
| split_menu_items MENU_PYTHON_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| local py_vesions_list=( | |
| "1.升级为最新版本|$RED|👉" | |
| "2.Python3.12.7|$CYAN|👍" | |
| "3.Python3.11" | |
| "4.Python3.10" | |
| "5.Python3.9" | |
| "9.指定版本|$BLUE" | |
| "0.退出|$RED|❌" | |
| ) | |
| local pip_sources_list=( | |
| "1.官方源" | |
| "2.阿里云" | |
| "3.腾讯云" | |
| "4.清华镜像" | |
| "5.中科大镜像" | |
| "9.自定义镜像" | |
| "0.退出" | |
| ) | |
| local conda_sources_list=( | |
| "1.官方源" | |
| "2.阿里云" | |
| "3.清华镜像" | |
| "4.中科大镜像" | |
| "0.退出" | |
| ) | |
| function py_subitem_set_source_conda(){ | |
| if command -v conda &>/dev/null; then | |
| function conda_sources_backup(){ | |
| conda config --show-sources > conda_sources_backup.txt | |
| } | |
| function conda_sources_remove(){ | |
| conda config --remove-key channels | |
| } | |
| function conda_sources_default(){ | |
| conda config --remove-key channels | |
| conda config --add channels defaults | |
| } | |
| local is_to_set=1 | |
| local url="" | |
| local host="" | |
| _BREAK_INFO=" 设置conda镜像源成功!" | |
| print_items_list conda_sources_list[@] " ⚓ conda镜像列表" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 选择镜像源: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| conda_sources_default | |
| _BREAK_INFO=" 设置Conda源为默认源!" | |
| ;; | |
| 2) | |
| conda config --add channels http://mirrors.aliyun.com/anaconda/pkgs/main/ | |
| conda config --add channels http://mirrors.aliyun.com/anaconda/pkgs/r/ | |
| conda config --add channels http://mirrors.aliyun.com/anaconda/pkgs/msys2/ | |
| conda config --set show_channel_urls yes | |
| conda clean -i | |
| _BREAK_INFO=" 设置Conda源成功: 阿里云镜像!" | |
| ;; | |
| 3) | |
| conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ | |
| conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ | |
| conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ | |
| conda config --set show_channel_urls yes | |
| conda clean -i | |
| _BREAK_INFO=" 设置Conda源成功: 清华大学镜像!" | |
| ;; | |
| 4) | |
| conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main | |
| conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/r | |
| conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/msys2 | |
| conda config --set show_channel_urls yes | |
| conda clean -i | |
| _BREAK_INFO=" 设置Conda源成功: 中科大镜像!" | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| is_to_set=0 | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| is_to_set=0 | |
| ;; | |
| esac | |
| else | |
| _BREAK_INFO=" conda尚未安装!" | |
| fi | |
| } | |
| function py_subitem_set_source_pip(){ | |
| if command -v pip &>/dev/null; then | |
| local is_to_set=1 | |
| local url="" | |
| local host="" | |
| _BREAK_INFO=" 设置pip镜像源成功!" | |
| print_items_list pip_sources_list[@] " ⚓ pip镜像列表" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 选择镜像源: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) | |
| url="https://pypi.org/simple" | |
| host="pypi.org" | |
| ;; | |
| 2) | |
| url="https://mirrors.aliyun.com/simple" | |
| host="mirrors.aliyun.com" | |
| ;; | |
| 3) | |
| url="https://mirrors.cloud.tencent.com/pypi/simple" | |
| host="mirrors.cloud.tencent.com" | |
| ;; | |
| 4) | |
| url="https://pypi.tuna.tsinghua.edu.cn/simple" | |
| host="pypi.tuna.tsinghua.edu.cn" | |
| ;; | |
| 5) | |
| url="https://pypi.mirrors.ustc.edu.cn/simple" | |
| host="pypi.mirrors.ustc.edu.cn" | |
| ;; | |
| 9) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入镜像源地址: \n ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && url=$INPUT | |
| ;; | |
| 0) | |
| echo -e "\n$TIP 返回主菜单 ..." | |
| _IS_BREAK="false" | |
| is_to_set=0 | |
| ;; | |
| *) | |
| _BREAK_INFO=" 请输入正确选项!" | |
| is_to_set=0 | |
| ;; | |
| esac | |
| if [[ ${is_to_set} -eq 1 ]]; then | |
| # if [[ -f "/etc/pip.conf" ]]; then | |
| # sed -i "s|index-url=.*|index-url=${url}|g" /etc/pip.conf | |
| # else | |
| # echo "index-url=${url}" > /etc/pip.conf | |
| # fi | |
| [[ -n $url ]] && pip config set global.index-url $url | |
| [[ -n $host ]] && pip config set global.trusted-host $host | |
| pip config set global.timeout 30 | |
| pip config set global.disable-pip-version-check true | |
| _BREAK_INFO=" 设置pip镜像源成功: ${url}" | |
| fi | |
| else | |
| _BREAK_INFO=" pip尚未安装!" | |
| fi | |
| } | |
| function py_subitem_install_python(){ | |
| print_items_list py_vesions_list[@] " ⚓ Python版本列表" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入你要安装选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) python_update_to_latest ;; | |
| 2) python_install_version 3.12.7 ;; | |
| 3) python_install_version 3.11 ;; | |
| 4) python_install_version 3.10 ;; | |
| 5) python_install_version 3.9 ;; | |
| 9) | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 选择Python版本: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| if [[ "$INPUT" == "0" ]]; then | |
| _BREAK_INFO=" 取消安装Python ..." | |
| else | |
| python_install_version $INPUT | |
| fi | |
| ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" ;; | |
| *) _BREAK_INFO=" 请输入正确选项!" ;; | |
| esac | |
| } | |
| function py_subitem_install_pipenv(){ | |
| if command -v pipenv &>/dev/null; then | |
| _BREAK_INFO=" pipenv已安装,无需重新安装!" | |
| else | |
| sys_update && app_install pipenv | |
| _BREAK_INFO=" pipenv安装成功!" | |
| fi | |
| } | |
| function py_subitem_install_miniforge(){ | |
| if command -v conda &>/dev/null; then | |
| _BREAK_INFO=" 系统已安装conda!" | |
| else | |
| local file="Miniforge3-$(uname)-$(uname -m).sh" | |
| local url="https://github.com/conda-forge/miniforge/releases/latest/download/$file" | |
| url=$(get_proxy_url $url) | |
| _BREAK_INFO=" miniForge安装成功!" | |
| if command -v curl &>/dev/null; then | |
| curl -L -O "${url}" && bash ${file} | |
| elif command -v wget &>/dev/null; then | |
| wget "${url}" && bash ${file} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| fi | |
| fi | |
| } | |
| function py_subitem_install_miniconda(){ | |
| if command -v conda &>/dev/null; then | |
| _BREAK_INFO=" 系统已安装conda!" | |
| else | |
| local file="Miniconda3-latest-$(uname)-$(uname -m).sh" | |
| local url="https://repo.anaconda.com/miniconda/$file" | |
| url=$(get_proxy_url $url) | |
| # check_ip_china | |
| # [[ $_IS_CN -eq 1 ]] && url="${URL_PROXY}${url}" | |
| _BREAK_INFO=" miniConda安装成功!" | |
| if command -v curl &>/dev/null; then | |
| curl -L -O "${url}" && bash ${file} | |
| elif command -v wget &>/dev/null; then | |
| wget "${url}" && bash ${file} | |
| else | |
| _BREAK_INFO=" 请先安装curl或wget!" | |
| fi | |
| fi | |
| } | |
| function py_subitem_install_dash(){ | |
| _BREAK_INFO=" dash安装成功!" | |
| if command -v pip &>/dev/null; then | |
| pip install dash | |
| elif command -v conda &>/dev/null; then | |
| conda install dash | |
| else | |
| _BREAK_INFO=" conda或pip未安装!" | |
| fi | |
| } | |
| function py_subitem_install_julia(){ | |
| _BREAK_INFO=" Julia安装成功!" | |
| if command -v julia &>/dev/null; then | |
| _BREAK_INFO=" julia已安装!" | |
| else | |
| if ! command -v jill &>/dev/null; then | |
| # echo -e "\n$TIP 先安装jill ..." | |
| if command -v pip &>/dev/null; then | |
| pip install jill | |
| else | |
| echo -e "$ERROR jill未安装, 请先安装pip!" | |
| fi | |
| fi | |
| if command -v jill &>/dev/null; then | |
| echo -e "\n$TIP 安装Julia ..." | |
| jill install | |
| else | |
| _BREAK_INFO=" jill未安装, Julia安装失败!" | |
| fi | |
| fi | |
| } | |
| function py_subitem_install_gunicorn(){ | |
| _BREAK_INFO=" gunicorn安装成功!" | |
| if command -v gunicorn &>/dev/null; then | |
| _BREAK_INFO=" gunicorn已安装!" | |
| else | |
| if command -v pip &>/dev/null; then | |
| pip install gunicorn greenlet eventlet gevent | |
| elif command -v conda &>/dev/null; then | |
| conda install gunicorn greenlet eventlet gevent | |
| else | |
| _BREAK_INFO=" pip或conda未安装!" | |
| fi | |
| fi | |
| } | |
| function py_subitem_install_hypercorn(){ | |
| _BREAK_INFO=" hypercorn安装成功!" | |
| if command -v hypercorn &>/dev/null; then | |
| _BREAK_INFO=" hypercorn已安装!" | |
| else | |
| if command -v pip &>/dev/null; then | |
| pip install hypercorn | |
| elif command -v conda &>/dev/null; then | |
| conda install hypercorn | |
| else | |
| _BREAK_INFO=" pip或conda未安装!" | |
| fi | |
| fi | |
| } | |
| while true; do | |
| _IS_BREAK="true" | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1 ) py_subitem_install_python ;; | |
| 2 ) py_subitem_install_pipenv ;; | |
| 3 ) py_subitem_install_miniforge ;; | |
| 4 ) py_subitem_install_miniconda ;; | |
| 5 ) py_subitem_set_source_pip ;; | |
| 6 ) py_subitem_set_source_conda ;; | |
| 31) py_subitem_install_dash ;; | |
| 32) py_subitem_install_julia ;; | |
| 33) py_subitem_install_gunicorn ;; | |
| 34) py_subitem_install_hypercorn ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| function caddy_install(){ | |
| if command -v caddy >/dev/null 2>&1; then | |
| echo -e "\n$TIP Caddy已安装: $(caddy --version)" | |
| return 0 | |
| fi | |
| # 准备目录和主页文件 | |
| # mkdir -p /home/web/{caddy,html} | |
| local dir_root=${1:-'/home/caddy_data'} | |
| local dir_main=${dir_root}'/caddy' | |
| local dir_html=${dir_root}'/html' | |
| local dir_logs=${dir_root}'/log' | |
| echo -e "$PRIGHT 1.创建配置文件目录 ... " | |
| [[ -d "${dir_root}" ]] || mkdir -p "${dir_root}" | |
| [[ -d "${dir_main}" ]] || mkdir -p "${dir_main}" | |
| [[ -d "${dir_html}" ]] || mkdir -p "${dir_html}" | |
| [[ -d "${dir_logs}" ]] || mkdir -p "${dir_logs}" | |
| echo -e "$PRIGHT 2.切换至当前目录到: ${dir_root} ... " | |
| cd "$dir_main" | |
| echo -e "$PRIGHT 3.下载主页和默认配置文件 ... " | |
| local url_caddy_index=$(get_proxy_url 'https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/scripts/caddy/index.html') | |
| local url_caddy_conf=$(get_proxy_url 'https://raw.githubusercontent.com/lmzxtek/qiqtools/refs/heads/main/scripts/caddy/default.conf') | |
| [[ -f "${dir_html}/index.html" ]] || curl -sSL -o ${dir_html}/index.html $url_caddy_index || wget -qO ${dir_html}/index.html $url_caddy_index | |
| [[ -f "${dir_main}/default.conf" ]] || curl -sSL -o ${dir_main}/default.conf $url_caddy_conf || wget -qO ${dir_main}/default.conf $url_caddy_conf | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| case "$ID" in | |
| ubuntu|debian|raspbian) | |
| echo -e "$PRIGHT 4.开始安装Caddy ... " | |
| sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl && \ | |
| curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \ | |
| curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list && \ | |
| sudo apt update && sudo apt install -y caddy | |
| ;; | |
| centos|rhel|almalinux|rocky|fedora) | |
| echo -e "$PRIGHT 4.开始安装Caddy ... " | |
| dnf install 'dnf-command(copr)' | |
| dnf copr enable @caddy/caddy | |
| dnf install caddy | |
| ## For RHEL/CentOS 7 | |
| # yum install yum-plugin-copr | |
| # yum copr enable @caddy/caddy | |
| # yum install caddy | |
| ;; | |
| # alpine) ;; | |
| arch|manjaro) | |
| pacman -Syu caddy | |
| ;; | |
| # opensuse|suse|opensuse-tumbleweed) ;; | |
| # iStoreOS|openwrt|ImmortalWrt|lede) ;; | |
| # FreeBSD) ;; | |
| *) echo -e "$WARN 不支持的发行版: $ID" && return ;; | |
| esac | |
| else | |
| echo -e "$WARN 无法确定操作系统。" | |
| return | |
| fi | |
| echo -e "$PRIGHT 5.完成安装Caddy. " | |
| } | |
| # 更新域名信息 | |
| function caddy_new_caddyfile(){ | |
| local dir_caddy=${1:-'/home/caddy_data/caddy'} | |
| if [ -z "$(find ${dir_caddy} -name "*.conf")" ]; then | |
| echo -e "${WARN} No *.conf files found in ${dir_caddy}" | |
| else | |
| echo -e " >>> Join all *.conf files into: /etc/caddy/Caddyfile" | |
| caddy_cfg_backup | |
| find ${dir_caddy} -name "*.conf" -exec cat {} + > /etc/caddy/Caddyfile | |
| cd /etc/caddy | |
| caddy fmt --overwrite | |
| cd - &>/dev/null | |
| fi | |
| } | |
| ## 重新加载Caddy,使新的配置文件生效 | |
| function caddy_reload(){ | |
| caddy_install; | |
| cd /etc/caddy; | |
| # caddy_new_caddyfile; | |
| caddy reload; | |
| cd - &>/dev/null ; | |
| } | |
| ## 备份Caddy配置信息 | |
| function caddy_cfg_backup(){ | |
| local path_cfg='/etc/caddy/Caddyfile' | |
| if [ ! -f "${path_cfg}" ]; then | |
| echo -e "$WARN Caddy配置文件不存在($path_cfg)。" | |
| return 1 | |
| fi | |
| cp "${path_cfg}" "${path_cfg}.bak" | |
| echo -e "$WARN 成功备份Caddy配置文件: ($path_cfg).bak" | |
| } | |
| # 更换站点域名 | |
| function caddy_alter_domain(){ | |
| local domain_new=$1 | |
| local domain_old=$2 | |
| local dir_caddy=${3:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain_new}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入新域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| domain_new=$INPUT | |
| fi | |
| [[ -z "$domain_new" ]] && echo -e "$WARN 新域名不能为空。" && return 1 | |
| if [[ -z "${domain_old}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入需要替换的域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| domain_old=$INPUT | |
| fi | |
| [[ -z "$domain_old" ]] && echo -e "$WARN 要替换的域名不能为空。" && return 1 | |
| mv ${dir_caddy}/$domain_old.conf ${dir_caddy}/$domain_new.conf | |
| sed -i "s/$domain_old/$domain_new/g" ${dir_caddy}/$domain_new.conf | |
| echo -e "\n${BOLD}└─ 更换域名成功: ${PLAIN}$domain_old -> $domain_new\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使反代生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| } | |
| # 删除站点域名 | |
| function caddy_del_domain(){ | |
| local domain_new=$1 | |
| local dir_caddy=${2:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain_new}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入要删除的域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| domain_new=$INPUT | |
| fi | |
| [[ -z "$domain_new" ]] && echo -e "$WARN 新域名不能为空。" && return 1 | |
| if [[ -f "${dir_caddy}/$domain_new.conf" ]] ; then | |
| echo -e "$INFO 删除站点 $domain_new ..." | |
| rm -f ${dir_caddy}/$domain_new.conf | |
| echo -e "\n$TIP 删除域名成功: $domain_new\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使反代生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| else | |
| echo -e "$WARN 站点${domain_new}的域名配置文件不存在: ${dir_caddy}/${domain_new}.conf)" | |
| fi | |
| } | |
| function caddy_domain_list(){ | |
| local dir_caddy=${1:-'/home/caddy_data/caddy'} | |
| # ls -t /home/web/caddy | grep -v "default.conf" | sed 's/\.[^.]*$//' | |
| local dm_list=$(ls -t ${dir_caddy} | grep -v "default.conf" | sed 's/\.[^.]*$//') | |
| # clear | |
| echo -e "$PRIGHT 站点列表\n${PLAIN}============================" | |
| echo "${list[@]}" | tr ' ' '\n' | nl -w2 -s'. ' | |
| num=0 | |
| for dm_file in $dm_list; do | |
| num+=1 | |
| printf " (%2d) %-s\n" ${num} "$dm_file" | |
| done | |
| echo -e "\n${PLAIN}============================\n" | |
| # echo "${dm_list[@]}" | |
| } | |
| # 清空站点域名 | |
| function caddy_clean_all_domain(){ | |
| local dir_caddy=${1:-'/home/caddy_data/caddy'} | |
| if [ -z "$(find ${dir_caddy} -name "*.conf")" ]; then | |
| echo -e "${WARN} 配置文件目录没有站点配置文件 in ${dir_caddy}" | |
| else | |
| echo -e " >>> Join all *.conf files into: /etc/caddy/Caddyfile" | |
| rm -f ${dir_caddy}/$domain_new.conf | |
| echo -e "\n$TIP 成功删除全部域名: $domain_new\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使反代生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| fi | |
| } | |
| # 添加域名反代 | |
| function caddy_add_reproxy(){ | |
| local domain="$1" | |
| local ip="$2" | |
| local port="$3" | |
| local to_check=${4:-1} | |
| local dir_caddy=${5:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入需反代的域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的域名不能为空。" && return 1 | |
| domain=$INPUT | |
| fi | |
| if [[ -z "${ip}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入反代的目标IP(默认: 127.0.0.1): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="127.0.0.1" | |
| ip=$INPUT | |
| fi | |
| if [[ -z "${port}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入反代的目标端口(默认: 3000): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=3000 | |
| port=$INPUT | |
| fi | |
| if [[ ${to_check} -eq 1 ]] ; then | |
| echo -e '' | |
| echo -e "${BOLD}└─ 请确认反代信息是否有误: ${PLAIN}\n" | |
| echo -e "${BOLD} 域名: ${PLAIN}$domain" | |
| echo -e "${BOLD} 反代: ${PLAIN}$ip:$port" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 以上信息正确吗?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="Y" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 反代信息有误!" | |
| return 1 | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误[Y/n],请重试!" | |
| return 1 | |
| ;; | |
| esac | |
| fi | |
| cat > "${dir_caddy}/${domain}.conf" << EOF | |
| $domain { | |
| reverse_proxy $ip:$port | |
| encode gzip | |
| } | |
| EOF | |
| echo -e "\n${BOLD}└─ ${GREEN}添加反代成功: ${RED}${domain}${PLAIN} -> $ip:${BLUE}${port}${PLAIN}\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使反代生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| } | |
| # 添加负载均衡 | |
| function caddy_add_url_balance(){ | |
| local domain=$1 | |
| local dir_caddy=${1:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入需反代的域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的域名不能为空。" && return 1 | |
| domain=$INPUT | |
| fi | |
| local url_list=() | |
| echo -e "\n$WORKING 按顺序输入需要进行负载均衡的链接: \n" | |
| while true; do | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入负载均衡的链接(IP:PORT),直接回车结束输入:: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && break | |
| url_list+=("$INPUT") | |
| done | |
| if [ ${#url_list[@]} -eq 0 ]; then | |
| echo -e "$WARN 负载均衡目标链接列表为空,返回。" | |
| return -1 | |
| fi | |
| local strategy='least_conn' | |
| echo -e "${BOLD}└─ 请选择负载均衡策略: ${PLAIN}\n" | |
| echo -e " 1. 轮询(Round Robin)(默认)" | |
| echo -e " 2. IP哈希(Source Hash)" | |
| echo -e " 3. 最少连接(Least Connections)" | |
| echo -e " 4. 权重随机(Random)" | |
| print_items_list "${url_list[@]}" " ⚓ 负载均衡链接列表" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 以上信息正确吗?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) strategy='least_conn';; | |
| 2) strategy='round_robin';; | |
| 3) strategy='ip_hash';; | |
| 4) | |
| strategy='random' | |
| print_items_list "${url_list[@]}" " ⚓ 负载均衡链接列表" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请按序输入每个链接的权重值(1-100): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误,返回!" | |
| return 1 | |
| ;; | |
| esac | |
| if [[ ${to_check} -eq 1 ]] ; then | |
| echo -e '' | |
| echo -e "${BOLD}└─ 请确认负载均衡数据是否有误: ${PLAIN}\n" | |
| echo -e "${BOLD} 域名: ${PLAIN}$domain" | |
| print_items_list "${url_list[@]}" " ⚓ 负载均衡链接列表" | |
| echo -e '' | |
| echo -e "${BOLD} 负载均衡策略: ${strategy} ${PLAIN}\n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 以上信息正确吗?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="Y" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 信息有误,直接返回!" | |
| return 1 | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误[Y/n],请重试!" | |
| return 1 | |
| ;; | |
| esac | |
| fi | |
| cat > "${dir_caddy}/${domain}.conf" << EOF | |
| $domain { | |
| reverse_proxy "${list[*]}" { | |
| lb_policy ${strategy} | |
| health_uri /health | |
| health_interval 10s | |
| health_timeout 2s | |
| } | |
| } | |
| EOF | |
| echo -e "\n${BOLD}└─ 添加负载均衡成功: ${PLAIN}$domain \n" | |
| print_items_list "${url_list[@]}" " ⚓ 负载均衡链接列表" | |
| echo -e "" | |
| ## 刷新Caddy配置信息,并重启Caddy,使反代生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| } | |
| # 添加重定向 | |
| function caddy_add_url_redirect(){ | |
| local domain=$1 | |
| local redirurl=$2 | |
| local dir_caddy=${3:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输重定向域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的域名不能为空。" && return 1 | |
| domain=$INPUT | |
| fi | |
| if [[ -z "${redirurl}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输重定向的目标链接: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的目标链接不能为空。" && return 1 | |
| redirurl=$INPUT | |
| fi | |
| if [[ ${to_check} -eq 1 ]] ; then | |
| echo -e '' | |
| echo -e "${BOLD}└─ 请确认重定向信息是否有误: ${PLAIN}\n" | |
| echo -e "${BOLD} 域名: ${PLAIN}$domain" | |
| echo -e "${BOLD} 链接: ${PLAIN}$redirurl" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 以上信息正确吗?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="Y" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 重定向信息有误!" | |
| return 1 | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误[Y/n],请重试!" | |
| return 1 | |
| ;; | |
| esac | |
| fi | |
| cat > "${dir_caddy}/${domain}.conf" << EOF | |
| $domain { | |
| redir $redirurl{uri} | |
| } | |
| EOF | |
| echo -e "\n${BOLD}└─ 添加重定向成功: ${PLAIN}$domain -> $redirurl\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使重定向生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| } | |
| # 静态网站 | |
| function caddy_add_static_web(){ | |
| local domain=$1 | |
| local abspath=$2 | |
| local dir_caddy=${3:-'/home/caddy_data/caddy'} | |
| if [[ -z "${domain}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输重定向域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的域名不能为空。" && return 1 | |
| domain=$INPUT | |
| fi | |
| if [[ -z "${abspath}" ]] ; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输重定向的目标链接: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && echo -e "$WARN 输入的目标链接不能为空。" && return 1 | |
| abspath=$INPUT | |
| fi | |
| if [[ ${to_check} -eq 1 ]] ; then | |
| echo -e '' | |
| echo -e "${BOLD}└─ 请确认重定向信息是否有误: ${PLAIN}\n" | |
| echo -e "${BOLD} 域名: ${PLAIN}$domain" | |
| echo -e "${BOLD} 路径: ${PLAIN}$abspath" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 以上信息正确吗?[Y/n]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="Y" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 静态站点信息有误!" | |
| return 1 | |
| ;; | |
| *) | |
| echo -e "\n$WARN 输入错误[Y/n],请重试!" | |
| return 1 | |
| ;; | |
| esac | |
| fi | |
| cat > "${dir_caddy}/${domain}.conf" << EOF | |
| $domain { | |
| root * $abspath | |
| encode gzip | |
| file_server | |
| } | |
| EOF | |
| echo -e "\n${BOLD}└─ 添加重定向成功: ${PLAIN}$domain -> $redirurl\n" | |
| ## 刷新Caddy配置信息,并重启Caddy,使静态站点生效 | |
| caddy_new_caddyfile | |
| caddy_reload | |
| } | |
| function get_valid_domain() { | |
| local domain | |
| local regex='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$' | |
| read -p " └─ 请输入域名: " domain | |
| if [[ $domain =~ $regex ]]; then | |
| # echo -e "Valid domain" | |
| echo $domain | |
| else | |
| # echo -e "$WARN Invalid domain: $domain" | |
| echo '' | |
| fi | |
| } | |
| # Caddy管理 | |
| MENU_CADDY_ITEMS=( | |
| "1|安装Caddy|$WHITE" | |
| "2|卸载Caddy|$WHITE" | |
| "3|更新Caddy|$WHITE" | |
| "4|重启Caddy|$WHITE" | |
| "5|查看状态|$YELLOW" | |
| "6|站点列表|$CYAN" | |
| "7|重置配置|$WHITE" | |
| "…………………………|$WHITE" | |
| "21|添加反代|$YELLOW" | |
| "22|添重定向|$WHITE" | |
| "23|添静态站|$WHITE" | |
| "24|负载均衡|$CYAN" | |
| "25|修改域名|$WHITE" | |
| "26|删除站点|$RED" | |
| "27|清空站点|$WHITE" | |
| "28|容器管理|$BLUE" | |
| ) | |
| function caddy_management_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| local num_split=$MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ Caddy管理 " $num_split 0 0 | |
| split_menu_items MENU_CADDY_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| while true; do | |
| _IS_BREAK='true' | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) caddy_install ;; | |
| 2) echo -e "\n$TIP Caddy卸载暂未实现 ..." ;; | |
| 3) echo -e "\n$TIP Caddy更新暂未实现 ..." ;; | |
| 4) caddy_reload ;; | |
| 5) systemctl status caddy ;; | |
| 6) caddy_domain_list ;; | |
| 7) caddy_new_caddyfile && caddy_reload ;; | |
| 21) caddy_add_reproxy && caddy_domain_list ;; | |
| 22) caddy_add_url_redirect && caddy_domain_list ;; | |
| 23) caddy_add_static_web && caddy_domain_list ;; | |
| 24) caddy_add_url_balance && caddy_domain_list ;; | |
| 25) caddy_domain_list && caddy_alter_domain && caddy_domain_list ;; | |
| 26) caddy_domain_list && caddy_del_domain && caddy_domain_list ;; | |
| 27) caddy_domain_list && caddy_clean_all_domain && caddy_domain_list ;; | |
| # 28) docker_management_menu && _IS_BREAK="false" && continue ;; | |
| 28) docker_management_menu && _IS_BREAK="false" && break ;; | |
| # 28) docker_management_menu && _IS_BREAK="false" ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK='false' && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 容器部署管理 | |
| MENU_DOCKER_DEPLOY_ITEMS=( | |
| "1|RustDesk|$WHITE" | |
| "2|DeepLX|$WHITE" | |
| "3|AKTools|$CYAN" | |
| "4|SubLinkX|$WHITE" | |
| "5|Lucky|$WHITE" | |
| "6|IPTVa|$WHITE" | |
| "7|IPTVd|$WHITE" | |
| "8|Docker-win|$WHITE" | |
| "9|Docker-mac|$WHITE" | |
| "10|WeChat(web)|$WHITE" | |
| "………………………|$WHITE" | |
| "21|Dash.|$WHITE" | |
| "22|MyIP|$WHITE" | |
| "23|Neko|$WHITE" | |
| "24|IT-Tools|$YELLOW" | |
| "25|Stirling PDF|$WHITE" | |
| ) | |
| function docker_deploy_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| local num_split=$MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ Docker部署 " $num_split 0 0 | |
| split_menu_items MENU_DOCKER_DEPLOY_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| function dc_set_domain_reproxy(){ | |
| local port=$1 | |
| if command -v caddy >/dev/null 2>&1; then | |
| # echo -e "\n$TIP 检测到系统已安装Caddy,是否给${dc_desc}添加域名反代? ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 系统已安装Caddy,是否添加域名反代?[y/N]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="N" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| local domain=$(get_valid_domain) | |
| [[ -n "$domain" ]] && caddy_add_reproxy "${domain}" '127.0.0.1' $port 0 | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 取消域名反代!" | |
| ;; | |
| *) echo -e "\n$WARN 输入错误,不进行域名反代!" ;; | |
| esac | |
| else | |
| echo -e "\n$TIP 系统已未安装Caddy,不进行域名反代 \n" | |
| fi | |
| } | |
| function dc_deploy_ittools(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45380 | |
| local dc_name='ittools' | |
| local dc_imag=corentinth/it-tools:latest | |
| local dc_desc="IT-Tools常用工具箱" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| ports: | |
| - '$dc_port:80' | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_deeplx(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45188 | |
| local dc_name='deeplx' | |
| local dc_imag=ghcr.io/owo-network/deeplx:latest | |
| local dc_desc="DeepLX(Free API)" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| ports: | |
| - '$dc_port:1188' | |
| restart: always | |
| # environment: | |
| # - TOKEN=helloworld | |
| # - AUTHKEY=xxxxxxx:fx | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_sublinkx(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45088 | |
| local dc_name='sublinkx' | |
| local dc_imag=jaaksi/sublinkx | |
| local dc_desc="SubLinkX" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/db" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| ports: | |
| - '$dc_port:8000' | |
| restart: always | |
| volumes: | |
| - $LFLD/db:/app/db | |
| - $LFLD/template:/app/template | |
| - $LFLD/logs:/app/logs | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_aktools(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45088 | |
| local dc_name='aktools' | |
| local dc_imag=registry.cn-shanghai.aliyuncs.com/akfamily/aktools:1.8.95 | |
| local dc_desc="AKTools" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/db" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| SITE_PASSWORD='' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入网站密码: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && SITE_PASSWORD=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| environment: | |
| - SITE_PASSWORD=$SITE_PASSWORD | |
| ports: | |
| - '$dc_port:8080' | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_rustdesk(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45115 | |
| local dc_name='rustdesk' | |
| local dc_imag=rustdesk/rustdesk-server-s6:latest | |
| local dc_desc="RustDesk-Server" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| # local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| # read -rp "${CHOICE}" INPUT | |
| # [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| HOST_ADDRESS='127.0.0.1' | |
| PANEL_APP_PORT_HBBR='' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入IP/域名: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && PANEL_APP_PORT_HBBR=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - "${fdat}:/data" | |
| environment: | |
| - "RELAY=${HOST_ADDRESS}:${PANEL_APP_PORT_HBBR}" | |
| - "ENCRYPTED_ONLY=1" | |
| ports: | |
| - "21115:21115" | |
| - "21116:21116" | |
| - "21116:21116/udp" | |
| - "21117:21117" | |
| - "21118:21118" | |
| - "21119:21119" | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_lucky(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45661 | |
| local dc_name='lucky' | |
| local dc_imag=gdy666/lucky | |
| local dc_desc="Lucky" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - "${fdat}:/goodluck" | |
| network_mode: host | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_iptva(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45455 | |
| local dc_name='iptva' | |
| local dc_imag=youshandefeiyang/allinone | |
| local dc_desc="IPTv(Allinone)" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - "${fdat}:/downloads" | |
| ports: | |
| - '$dc_port:35455' | |
| privileged: true | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_iptvd(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45427 | |
| local dc_name='iptvd' | |
| local dc_imag=doubebly/doube-itv:latest | |
| local dc_desc="IPTv(doubebly)" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - "${fdat}:/downloads" | |
| ports: | |
| - '$dc_port:5000' | |
| privileged: true | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_spdf(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45427 | |
| local dc_name='spdf' | |
| local dc_imag=frooodle/s-pdf:latest | |
| local dc_desc="Stirling PDF" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - $fdat:/usr/share/tesseract-ocr/5/tessdata | |
| - $lfld/extraConfigs:/configs | |
| - $lfld/logs:/logs | |
| ports: | |
| - '$dc_port:8080' | |
| privileged: true | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_myip(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45966 | |
| local dc_name='myip' | |
| local dc_imag=ghcr.io/jason5ng32/myip:latest | |
| local dc_desc="MyIP-IP Checking" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| ports: | |
| - '$dc_port:18966' | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_dashdot(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=44009 | |
| local dc_name='dashdot' | |
| local dc_imag=mauricenino/dashdot:latest | |
| local dc_desc="Dash." | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| privileged: true | |
| ports: | |
| - '$dc_port:3001' | |
| volumes: | |
| - /:/mnt/host:ro | |
| restart: unless-stopped | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_wechat(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45800 | |
| local dc_vnc=45900 | |
| local dc_name='wechat' | |
| local dc_imag=ricwang/docker-wechat:latest | |
| local dc_desc="WeChat(web)" | |
| local urlgit='' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入VNC端口(默认为:${dc_vnc})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_vnc=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| volumes: | |
| - ${fdat}:/root/downloads | |
| - /dev/snd:/dev/snd | |
| - ${lfld}/.xwechat:/root/.xwechat | |
| - ${lfld}/xwechat_files:/root/xwechat_files | |
| ports: | |
| - "$dc_port:5800" | |
| - "$dc_vnc:5900" | |
| environment: | |
| - LANG=zh_CN.UTF-8 | |
| - USER_ID=0 | |
| - GROUP_ID=0 | |
| - WEB_AUDIO=1 | |
| - TZ=Asia/Shanghai | |
| privileged: true | |
| restart: unless-stopped | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_neko(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=45427 | |
| local dc_name='neko' | |
| local dc_imag=m1k1o/neko:microsoft-edge | |
| # local dc_imag=m1k1o/neko:firefox | |
| # local dc_imag=m1k1o/neko:chromium | |
| local dc_desc="Neko-Browser" | |
| local urlgit='https://neko.m1k1o.net/#/getting-started/quick-start' | |
| local domain='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) && cd $lfld | |
| [[ -f "$fyml" ]] || touch $fyml | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| brkernel='microsoft-edge' | |
| echo -e "" | |
| echo -e "$PRIGHT 1.Edge(dafault)" | |
| echo -e "$PRIGHT 2.Firefox" | |
| echo -e "$PRIGHT 3.Chromium" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择浏览器内核(默认为:Edge)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) brkernel='microsoft-edge' ;; | |
| 2) brkernel='firefox' ;; | |
| 3) brkernel='chromium' ;; | |
| *) echo -e "\n$WARN 输入错误[Y/n],设置为默认Edge浏览器内核" ;; | |
| esac | |
| local memsize=2 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入内存大小(默认为:${memsize})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && memsize=$INPUT | |
| local pssuser=neko | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入登录密码(默认为:${pssuser})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && pssuser=$INPUT | |
| local pssadmin=admin | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入管理员密码(默认为:${pssadmin})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && pssadmin=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: m1k1o/neko:${brkernel} | |
| image: $dc_imag | |
| shm_size: "${memsize}gb" | |
| environment: | |
| NEKO_SCREEN: 1920x1080@30 | |
| NEKO_PASSWORD: ${pssuser} | |
| NEKO_PASSWORD_ADMIN: ${pssadmin} | |
| NEKO_EPR: 52000-52100 | |
| NEKO_ICELITE: 1 | |
| ports: | |
| - '${dc_port}:8080' | |
| - "52000-52100:52000-52100/udp" | |
| restart: always | |
| EOF | |
| docker-compose up -d | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $urlgit ]] && content+="\nGitHub : $urlgit " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_docker_win(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=48006 | |
| local dc_name='docker_win' | |
| local dc_imag=dockurr/windows | |
| local dc_desc="Docker(win)" | |
| local domain='' | |
| local urlgit='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入VNC监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| macver='2025' | |
| echo -e "" | |
| echo -e "$PRIGHT 1.2025(Windows Server 2025)" | |
| echo -e "$PRIGHT 2.2022(Windows Server 2022)" | |
| echo -e "$PRIGHT 3.2019(Windows Server 2019)" | |
| echo -e "$PRIGHT 4.win11(Windows 11)" | |
| echo -e "$PRIGHT 5.win10(Windows 10)" | |
| echo -e "$PRIGHT 6.tiny11(Tiny 11)" | |
| echo -e "$PRIGHT 7.tiny10(Tiny 10)" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择Windows版本(默认为: Win2025)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) macver='2025' ;; | |
| 2) macver='2022' ;; | |
| 3) macver='2019' ;; | |
| 4) macver='win11' ;; | |
| 5) macver='win10' ;; | |
| 6) macver='tiny11' ;; | |
| 7) macver='tiny10' ;; | |
| *) echo -e "\n$WARN 输入错误[Y/n],设置为默认2025" ;; | |
| esac | |
| local lang="Chinese" | |
| echo -e "\n" " 可选择的语言 " | |
| echo -e " " " 1.Chinese " | |
| echo -e " " " 2.English " | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择Windows语言(默认为: Chinese)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) lang='Chinese' ;; | |
| 2) lang='English' ;; | |
| *) echo -e "\n$WARN 输入错误[Y/n],设置为${lang}" ;; | |
| esac | |
| local numcpu=4 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入CPU核心数(默认为:${numcpu})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && numcpu=$INPUT | |
| local memsize=4 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入内存大小(默认为:${memsize}GB)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && memsize=$INPUT | |
| local disksize=30 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入硬盘大小(默认为:${disksize}GB)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && disksize=$INPUT | |
| local user='dd' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入登录账户(默认为:${user})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && user=$INPUT | |
| local pass='dd543212345' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入登录密码(默认为:${pass})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && pass=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| cap_add: | |
| - NET_ADMIN | |
| devices: | |
| - /dev/kvm | |
| environment: | |
| VERSION: "${macver}" | |
| LANGUAGE: "${lang}" | |
| CPU_CORES: "${numcpu}" | |
| RAM_SIZE: "${memsize}" | |
| DISK_SIZE: "${disksize}" | |
| USERNAME: "${user}" | |
| PASSWORD: "${pass}" | |
| volumes: | |
| - $lfld/$dc_name/dcwin_disk:/storage | |
| - $lfld/$dc_name/dcwin_share:/shared | |
| ports: | |
| - ${dc_port}:8006 | |
| - 5000:5000 | |
| - 3389:3389/tcp | |
| - 3389:3389/udp | |
| stop_grace_period: 2m | |
| restart: unless-stopped | |
| EOF | |
| local CHOICE=$(echo -e "\n${BOLD}└─ ${dc_name}配置文件已生成是否启动容器?[y/N]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="N" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| docker-compose up -d | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "$TIP 手动启动容器: " | |
| echo -e "$TIP 配置目录: ${lfld}" | |
| echo -e "$TIP 配置文件: ${fyml}" | |
| echo -e "$TIP 运行命令: docker-compose up -d " | |
| ;; | |
| *) echo -e "\n$WARN 输入错误!" ;; | |
| esac | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $dc_desc ]] && content+="\nGitHub : # ${urlgit} " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| function dc_deploy_docker_mac(){ | |
| local base_root="/home/dcc.d" | |
| local dc_port=48009 | |
| local dc_name='docker_mac' | |
| local dc_imag=dockurr/macos | |
| local dc_desc="Docker(mac)" | |
| local domain='' | |
| local urlgit='' | |
| local lfld="$base_root/$dc_name" | |
| local fdat="$base_root/$dc_name/data" | |
| local fyml="$lfld/docker-compose.yml" | |
| local fcfg="$lfld/${dc_name}.conf" | |
| ([[ -d "$fdat" ]] || mkdir -p $fdat) | |
| [[ -f "$fyml" ]] || touch $fyml | |
| cd $lfld | |
| echo -e "\n $TIP 现在开始部署${dc_desc} ... \n" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入VNC监听端口(默认为:${dc_port})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && dc_port=$INPUT | |
| macver='sonoma' | |
| echo -e "" | |
| echo -e "$PRIGHT 1.sonoma(MacOS Sonoma)" | |
| echo -e "$PRIGHT 2.ventura(MacOS Ventura)" | |
| echo -e "$PRIGHT 3.monterey(MacOS Monterey)" | |
| echo -e "$PRIGHT 4.big-sur(MacOS Big Sur)" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择MacOS版本(默认为: sonoma)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) macver='sonoma' ;; | |
| 2) macver='ventura' ;; | |
| 3) macver='monterey' ;; | |
| 4) macver='big-sur' ;; | |
| *) echo -e "\n$WARN 输入错误[Y/n],设置为默认sonoma" ;; | |
| esac | |
| # local lang="Chinese" | |
| # echo -e "\n" " 可选择的语言 " | |
| # echo -e " " " 1.Chinese " | |
| # echo -e " " " 2.English " | |
| # local CHOICE=$(echo -e "\n${BOLD}└─ 请选择Windows语言(默认为: Chinese)]: ${PLAIN}") | |
| # read -rp "${CHOICE}" INPUT | |
| # [[ -z "$INPUT" ]] && INPUT=1 | |
| # case "${INPUT}" in | |
| # 1) lang='Chinese' ;; | |
| # 2) lang='English' ;; | |
| # *) echo -e "\n$WARN 输入错误[Y/n],设置为${lang}" ;; | |
| # esac | |
| local numcpu=4 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入CPU核心数(默认为:${numcpu})]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && numcpu=$INPUT | |
| local memsize=8 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入内存大小(默认为:${memsize}GB)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && memsize=$INPUT | |
| local disksize=42 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入硬盘大小(默认为:${disksize}GB)]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -n "$INPUT" ]] && disksize=$INPUT | |
| # local user='dd' | |
| # local CHOICE=$(echo -e "\n${BOLD}└─ 请输入登录账户(默认为:${user})]: ${PLAIN}") | |
| # read -rp "${CHOICE}" INPUT | |
| # [[ -n "$INPUT" ]] && user=$INPUT | |
| # local pass='dd543212345' | |
| # local CHOICE=$(echo -e "\n${BOLD}└─ 请输入登录密码(默认为:${pass})]: ${PLAIN}") | |
| # read -rp "${CHOICE}" INPUT | |
| # [[ -n "$INPUT" ]] && pass=$INPUT | |
| cat > "$fyml" << EOF | |
| services: | |
| ${dc_name}: | |
| container_name: ${dc_name} | |
| image: $dc_imag | |
| cap_add: | |
| - NET_ADMIN | |
| devices: | |
| - /dev/kvm | |
| environment: | |
| VERSION: "${macver}" | |
| LANGUAGE: "${lang}" | |
| CPU_CORES: "${numcpu}" | |
| RAM_SIZE: "${memsize}" | |
| DISK_SIZE: "${disksize}" | |
| volumes: | |
| - $lfld/$dc_name/dcmac_disk:/storage | |
| - $lfld/$dc_name/dcmac_share:/shared | |
| ports: | |
| - ${dc_port}:8006 | |
| - 5000:5000 | |
| - 3389:3389/tcp | |
| - 3389:3389/udp | |
| stop_grace_period: 2m | |
| restart: unless-stopped | |
| EOF | |
| local CHOICE=$(echo -e "\n${BOLD}└─ ${dc_name}配置文件已生成是否启动容器?[y/N]: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT="N" | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| docker-compose up -d | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "$TIP 手动启动容器: " | |
| echo -e "$TIP 配置目录: ${lfld}" | |
| echo -e "$TIP 配置文件: ${fyml}" | |
| echo -e "$TIP 运行命令: docker-compose up -d " | |
| ;; | |
| *) echo -e "\n$WARN 输入错误!" ;; | |
| esac | |
| dc_set_domain_reproxy $dc_port | |
| local content='' | |
| content+="\nService : ${dc_name}" | |
| content+="\nContainer : ${dc_name}" | |
| [[ -n $WAN4 ]] && content+="\nURL(IPV4) : http://$WAN4:$dc_port" | |
| [[ -n $WAN6 ]] && content+="\nURL(IPV6) : http://[$WAN6]:$dc_port" | |
| [[ -n $domain ]] && content+="\nDomain : $domain " | |
| [[ -n $dc_desc ]] && content+="\nDescription : $dc_desc " | |
| [[ -n $dc_desc ]] && content+="\nGitHub : # ${urlgit} " | |
| echo -e "\n$TIP ${dc_desc}部署信息如下:\n" | |
| echo -e "$content" | tee $fcfg | |
| cd - &>/dev/null # 返回原来目录 | |
| } | |
| #================================ | |
| while true; do | |
| _IS_BREAK="true" | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择要部署的容器: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1 ) dc_deploy_rustdesk ;; | |
| 2 ) dc_deploy_deeplx ;; | |
| 3 ) dc_deploy_aktools ;; | |
| 4 ) dc_deploy_sublinkx ;; | |
| 5 ) dc_deploy_lucky ;; | |
| 6 ) dc_deploy_iptva ;; | |
| 7 ) dc_deploy_iptvd ;; | |
| 8 ) dc_deploy_docker_win ;; | |
| 9 ) dc_deploy_docker_mac ;; | |
| 10) dc_deploy_wechat ;; | |
| 21) dc_deploy_dashdot ;; | |
| 22) dc_deploy_myip ;; | |
| 23) dc_deploy_neko ;; | |
| 24) dc_deploy_ittools ;; | |
| 25) dc_deploy_spdf ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| # 0) docker_management_menu && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号以选择你想使用的功能!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # Docker管理 | |
| MENU_DOCKER_MANAGE_ITEMS=( | |
| "1|安装容器|$WHITE" | |
| "2|卸载容器|$WHITE" | |
| "3|清理容器|$WHITE" | |
| "4|重启服务|$CYAN" | |
| "11|状态查看|$WHITE" | |
| "12|容器列表|$YELLOW" | |
| "13|镜像列表|$WHITE" | |
| "14|网络列表|$WHITE" | |
| "………………………|$WHITE" | |
| "31|站点部署|$YELLOW" | |
| "32|站点管理|$WHITE" | |
| "33|设置dcc|$WHITE" | |
| ) | |
| function docker_management_menu(){ | |
| function print_sub_item_menu_headinfo(){ | |
| clear | |
| # print_menu_head $MAX_SPLIT_CHAR_NUM | |
| local num_split=$MAX_SPLIT_CHAR_NUM | |
| print_sub_head "▼ Docker管理 " $num_split 0 0 | |
| split_menu_items MENU_DOCKER_MANAGE_ITEMS[@] | |
| # print_main_menu_tail $num_split | |
| print_sub_menu_tail $num_split | |
| } | |
| # 设置docker-compose快捷命令 | |
| function docker_set_1ckl(){ | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入要设置的快捷命令[默认为: dcc] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| local tcmd=$INPUT | |
| [[ -z $INPUT ]] && tcmd="dcc" | |
| if [[ -x "$(command -v $tcmd)" ]] ; then | |
| echo -e "$WARN 快捷命令${tcmd}已存在,请更换其他命令。" | |
| local tpath=$(which $tcmd) | |
| echo -e "\n$TIP ${tcmd} -> $tpath" | |
| return 1 | |
| fi | |
| # rm -rf `which $tcmd` | |
| tpath=/usr/local/bin/docker-compose | |
| chmod a+x $tpath | |
| ln -s $tpath /usr/bin/$tcmd | |
| } | |
| ## 显示Docker版本信息 | |
| function docker_show_info() { | |
| echo -e "\n${BOLD} ┌─ Docker版本信息${PLAIN} ────────" | |
| if [[ ! -x "$(command -v docker)" ]] ; then | |
| echo -e "$WARN Docker环境未安装。" | |
| else | |
| docker --version | |
| fi | |
| if [[ ! -x "$(command -v docker-compose)" ]] ; then | |
| echo -e "$WARN Docker-compose未安装。" | |
| else | |
| docker-compose --version | |
| fi | |
| echo -e "${BOLD} └─────────────────────────${PLAIN}" | |
| # docker images | |
| } | |
| function docker_show_containers() { | |
| # docker_show_info | |
| echo -e "\n${BOLD} ┌─ Docker容器列表${PLAIN} ────────" | |
| docker ps -a | |
| echo -e "${BOLD} └─────────────────────────${PLAIN}" | |
| } | |
| function docker_show_images() { | |
| # docker_show_info | |
| echo -e "\n${BOLD} ┌─ Docker镜像列表${PLAIN} ────────" | |
| docker images | |
| echo -e "${BOLD} └─────────────────────────${PLAIN}" | |
| } | |
| function docker_show_networks() { | |
| # docker_show_info | |
| echo -e "\n${BOLD} ┌─ Docker容器网络${PLAIN} ────────" | |
| docker network ls | |
| echo -e "${BOLD} └─────────────────────────${PLAIN}" | |
| } | |
| # Docker清理不用的镜像和网络 | |
| function docker_clean() { | |
| docker_show_info | |
| [[ ! -x "$(command -v docker)" ]] && echo -e "$WARN Docker环境未安装,无需卸载。" && return 1 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否清理镜像和网络?[Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT='Y' | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| docker system prune -af --volumes | |
| echo -e "$TIP Docker清理完成" | |
| ;; | |
| [Nn] | [Nn][Oo]) echo -e "$WARN Docker清理取消 " && return 1 ;; | |
| *) echo -e " 错误输入..." && return 1 ;; | |
| esac | |
| } | |
| # Docker卸载 | |
| function docker_uninstall() { | |
| docker_show_info | |
| [[ ! -x "$(command -v docker)" ]] && echo -e "$WARN Docker环境未安装,无需卸载。" && return 1 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否真要卸载Docker?[Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT='Y' | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| docker rm $(docker ps -a -q) && docker rmi $(docker images -q) && docker network prune | |
| remove docker docker-ce docker-compose > /dev/null 2>&1 | |
| echo -e "$TIP Docker环境卸载完成" | |
| ;; | |
| [Nn] | [Nn][Oo]) echo -e "$WARN 卸载取消 " && return 1 ;; | |
| *) echo -e " 错误输入..." && return 1 ;; | |
| esac | |
| } | |
| function docker_install_official() { | |
| check_sys_virt | |
| if [[ "$VIRT" =~ "LXC" ]]; then | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 检测到${RED}LXC${PLAIN}服务器,不建议安装Docker。是否继续?[Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT='Y' | |
| case "$INPUT" in | |
| [Yy] | [Yy][Ee][Ss]) ;; | |
| [Nn] | [Nn][Oo]) echo -e "$WARN 安装取消 " && return 1 ;; | |
| *) echo -e " 错误输入..." && return 1 ;; | |
| esac | |
| fi | |
| echo -e "\n $WORKING 开始安装Docker ...\n" | |
| if [ -f "/etc/alpine-release" ]; then | |
| apk update | |
| apk add docker docker-compose | |
| rc-update add docker default | |
| service docker start | |
| else | |
| curl -fsSL https://get.docker.com | sh && ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin | |
| systemctl start docker | |
| systemctl enable docker | |
| fi | |
| } | |
| function docker_install(){ | |
| docker_show_info | |
| if command -v docker &>/dev/null; then | |
| echo '' | |
| echo -e "$PRIGHT Docker已安装 ..." | |
| generate_separator "=" 40 | |
| docker --version | |
| docker-compose --version | |
| generate_separator "=" 40 | |
| echo '' | |
| else | |
| echo -e "" | |
| echo -e "$PRIGHT Docker安装选项" | |
| generate_separator "=" 40 | |
| echo -e " 1.Official(官方)" | |
| echo -e " 2.LinuxMirrors(大陆)" | |
| echo -e " 3.LinuxMirrors(教育)" | |
| echo -e " 4.LinuxMirrors(海外)" | |
| echo -e " 0.返回" | |
| generate_separator "=" 40 | |
| _IS_BREAK='true' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择安装源?(默认官方): ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "$INPUT" ]] && INPUT=1 | |
| case "${INPUT}" in | |
| 1) docker_install_official ;; | |
| 2) bash <(curl -sSL https://linuxmirrors.cn/docker.sh) ;; | |
| 3) bash <(curl -sSL https://linuxmirrors.cn/docker.sh) -edu;; | |
| 4) bash <(curl -sSL https://linuxmirrors.cn/docker.sh) -abroad;; | |
| 0) _IS_BREAK='false' ;; | |
| *) echo -e "\n$WARN 输入错误,返回!" ;; | |
| esac | |
| fi | |
| } | |
| function docker_enable_ipv6(){ | |
| echo -e "\n $TIP 开启容器IPv6网络" | |
| local CONFIG_FILE="/etc/docker/daemon.json" | |
| local REQUIRED_IPV6_CONFIG='{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64"}' | |
| app_install jq | |
| # 检查配置文件是否存在,如果不存在则创建文件并写入默认设置 | |
| if [ ! -f "$CONFIG_FILE" ]; then | |
| echo "$REQUIRED_IPV6_CONFIG" | jq . > "$CONFIG_FILE" | |
| systemctl restart docker | |
| else | |
| # 使用jq处理配置文件的更新 | |
| local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") | |
| # 检查当前配置是否已经有 ipv6 设置 | |
| local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq '.ipv6 // false') | |
| # 更新配置,开启 IPv6 | |
| if [[ "$CURRENT_IPV6" == "false" ]]; then | |
| UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {ipv6: true, "fixed-cidr-v6": "2001:db8:1::/64"}') | |
| else | |
| UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq '. + {"fixed-cidr-v6": "2001:db8:1::/64"}') | |
| fi | |
| # 对比原始配置与新配置 | |
| if [[ "$ORIGINAL_CONFIG" == "$UPDATED_CONFIG" ]]; then | |
| echo -e "${TIP} 当前已开启ipv6访问" | |
| else | |
| echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" | |
| systemctl restart docker | |
| fi | |
| fi | |
| } | |
| function docker_disable_ipv6(){ | |
| echo -e "\n $TIP 关闭容器IPv6网络" | |
| local CONFIG_FILE="/etc/docker/daemon.json" | |
| app_install jq | |
| # 检查配置文件是否存在 | |
| if [ ! -f "$CONFIG_FILE" ]; then | |
| echo -e "${gl_hong}配置文件不存在${gl_bai}" | |
| return | |
| fi | |
| # 读取当前配置 | |
| local ORIGINAL_CONFIG=$(<"$CONFIG_FILE") | |
| # 使用jq处理配置文件的更新 | |
| local UPDATED_CONFIG=$(echo "$ORIGINAL_CONFIG" | jq 'del(.["fixed-cidr-v6"]) | .ipv6 = false') | |
| # 检查当前的 ipv6 状态 | |
| local CURRENT_IPV6=$(echo "$ORIGINAL_CONFIG" | jq -r '.ipv6 // false') | |
| # 对比原始配置与新配置 | |
| if [[ "$CURRENT_IPV6" == "false" ]]; then | |
| echo -e "${TIP}当前已关闭ipv6访问" | |
| else | |
| echo "$UPDATED_CONFIG" | jq . > "$CONFIG_FILE" | |
| sytemctl restart docker | |
| echo -e "${TIP}已成功关闭ipv6访问" | |
| fi | |
| } | |
| function docker_manage_ipv6(){ | |
| generate_separator "=" 40 | |
| echo -e " 1.开启容器IPv6网络" | |
| echo -e " 2.关闭容器IPv6网络" | |
| echo -e " 0.返回" | |
| generate_separator "=" 40 | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) docker_enable_ipv6 ;; | |
| 2) docker_disable_ipv6 ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && return ;; | |
| *) _BREAK_INFO=" 请输入有效的选项序号!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| } | |
| function docker_add_1panel_v4v6(){ | |
| echo -e "\n $TIP 添加1panel-v4v6之前,请先确保1Panel面板中开启了bridge网络的IPv6." | |
| docker network create --driver=bridge \ | |
| --subnet=172.16.10.0/24 \ | |
| --gateway=172.16.10.1 \ | |
| --ip-range=172.16.10.0/16 \ | |
| --subnet=2408:400e::/48 \ | |
| --gateway=2408:400e::1 \ | |
| --ip-range=2408:400e::/64 \ | |
| 1panel-v4v6 | |
| echo -e "\n $TIP 添加1panel-v4v6完成.\n" | |
| } | |
| function docker_service_restart(){ | |
| if ! systemctl status ${{app_name} > /dev/null 2>&1; then | |
| systemctl stop docker && systemctl start docker | |
| else | |
| echo -e "\n$TIP 系统未安装docker服务!" | |
| fi | |
| } | |
| function docker_get_id(){ | |
| local head=${1:-'ID'} | |
| local dc_id='' | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 输入${head}: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| if [[ -n $INPUT ]]; then | |
| local dc_id=$INPUT | |
| else | |
| echo -e "\n$WARN 请输入有效的ID!" | |
| fi | |
| echo "${dc_id}" | |
| } | |
| function docker_images_rm_all(){ | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否删除所有镜像? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 删除所有镜像 ..." | |
| docker rmi -f $(docker images -q) | |
| echo -e "\n$TIP 删除所有镜像成功!" | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 取消删除所有镜像!" | |
| ;; | |
| *) _BREAK_INFO=" 输入错误!" && _IS_BREAK="true" ;; | |
| esac | |
| } | |
| function docker_containers_rm_all(){ | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否删除所有容器? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 删除所有容器 ..." | |
| docker rm $(docker ps -a -q) | |
| echo -e "\n$TIP 删除所有容器成功!" | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 取消删除所有容器!" | |
| ;; | |
| *) _BREAK_INFO=" 输入错误!" && _IS_BREAK="true" ;; | |
| esac | |
| } | |
| function docker_containers_stop_all(){ | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 是否停止所有容器? [Y/n] ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| [[ -z "${INPUT}" ]] && INPUT=Y # 回车默认为Y | |
| case "${INPUT}" in | |
| [Yy] | [Yy][Ee][Ss]) | |
| echo -e "\n$TIP 停止所有容器 ..." | |
| docker stop $(docker ps -q) | |
| echo -e "\n$TIP 停止所有容器成功!" | |
| ;; | |
| [Nn] | [Nn][Oo]) | |
| echo -e "\n$TIP 取消停止所有容器!" | |
| ;; | |
| *) _BREAK_INFO=" 输入错误!" && _IS_BREAK="true" ;; | |
| esac | |
| } | |
| function docker_network_list(){ | |
| local dc_name='' | |
| local dc_items_list=( | |
| "1.删除网络" | |
| "2.清理网络" | |
| "3.删除所有" | |
| "4.开启IPv6" | |
| "5.关闭IPv6" | |
| "6.添加1panel-v4v6" | |
| "0.返回" | |
| ) | |
| while true; do | |
| clear | |
| docker_show_networks | |
| print_items_list dc_items_list[@] " ⚓ 网络操作" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) dc_name=$(docker_get_id '网络名') && [[ -n ${dc_name} ]] && docker network rm $dc_name ;; | |
| 2) docker network prune ;; # 清理网络 | |
| 3) docker_images_rm_all ;; | |
| 4) docker_enable_ipv6 ;; | |
| 5) docker_disable_ipv6 ;; | |
| 6) docker_add_1panel_v4v6 ;; | |
| 0) echo -e "\n$TIP 返回 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入有效选项!" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| function docker_images_list(){ | |
| local dc_name='' | |
| local dc_items_list=( | |
| "1.删除镜像" | |
| "2.获取镜像" | |
| "3.更新镜像" | |
| "4.删除所有" | |
| "0.返回" | |
| ) | |
| while true; do | |
| clear | |
| docker_show_images | |
| print_items_list dc_items_list[@] " ⚓ 镜像操作" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) dc_name=$(docker_get_id '镜像名') && [[ -n ${dc_name} ]] && docker images rm $dc_name ;; | |
| 2) dc_name=$(docker_get_id '镜像名') && [[ -n ${dc_name} ]] && docker pull $dc_name ;; | |
| 3) dc_name=$(docker_get_id '镜像名') && [[ -n ${dc_name} ]] && docker pull $dc_name ;; | |
| 4) docker_images_rm_all ;; | |
| 0) echo -e "\n$TIP 返回 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入有效选项!" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| function docker_containers_list(){ | |
| local dc_id='' | |
| local dc_items_list=( | |
| "1.删除容器" | |
| "2.停止容器" | |
| "3.重启容器" | |
| "4.查看容器" | |
| "5.删除所有" | |
| "6.停止所有" | |
| "0.返回" | |
| ) | |
| while true; do | |
| clear | |
| docker_show_containers | |
| print_items_list dc_items_list[@] " ⚓ 容器操作" | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请选择: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) dc_id=$(docker_get_id "容器ID") && [[ -n ${dc_id} ]] && docker stop $dc_id && docker rm $dc_id ;; | |
| 2) dc_id=$(docker_get_id "容器ID") && [[ -n ${dc_id} ]] && docker stop $dc_id ;; | |
| 3) dc_id=$(docker_get_id "容器ID") && [[ -n ${dc_id} ]] && docker restart $dc_id ;; | |
| 4) dc_id=$(docker_get_id "容器ID") && [[ -n ${dc_id} ]] && docker stats $dc_id ;; | |
| 5) docker_containers_rm_all ;; | |
| 6) docker_containers_stop_all ;; | |
| 0) echo -e "\n$TIP 返回 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入有效选项!" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| while true; do | |
| _IS_BREAK="true" | |
| print_sub_item_menu_headinfo | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1 ) docker_install ;; | |
| 2 ) docker_uninstall ;; | |
| 3 ) docker_clean ;; | |
| 4 ) docker_service_restart ;; | |
| 11) clear && docker_show_info && docker_show_containers && docker_show_images && docker_show_networks ;; | |
| 12) docker_containers_list ;; | |
| 13) docker_images_list ;; | |
| 14) docker_network_list ;; | |
| 31) docker_deploy_menu && _IS_BREAK="false" && break ;; | |
| 32) caddy_management_menu && _IS_BREAK="false" && break ;; | |
| # 31) docker_deploy_menu && _IS_BREAK="false" ;; | |
| # 32) caddy_management_menu && _IS_BREAK="false" && continue ;; | |
| # 32) caddy_management_menu && _IS_BREAK="false" ;; | |
| 33) docker_set_1ckl && _IS_BREAK="true" ;; | |
| xx) sys_reboot ;; | |
| 0) echo -e "\n$TIP 返回主菜单 ..." && _IS_BREAK="false" && break ;; | |
| *) _BREAK_INFO=" 请输入有效的选项序号!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| # 定义主菜单数组 | |
| MENU_MAIN_ITEMS=( | |
| "1|基本信息|$MAGENTA" | |
| "2|性能测试|$WHITE" | |
| "3|系统更新|$WHITE" | |
| "4|系统清理|$GREEN" | |
| "………………………|$WHITE" | |
| "11|系统工具|$GREEN" | |
| "12|服务工具|$YELLOW" | |
| "13|常用软件|$WHITE" | |
| "14|其他脚本|$BLUE" | |
| "21|Caddy管理|$WHITE" | |
| "22|Docker管理|$YELLOW" | |
| "23|Python管理|$CYAN" | |
| ) | |
| ## ====================================================== | |
| function main_menu(){ | |
| function print_main_menu(){ | |
| clear | |
| # 调用拆分函数 | |
| print_menu_head $MAX_SPLIT_CHAR_NUM | |
| split_menu_items MENU_MAIN_ITEMS[@] 0 | |
| print_main_menu_tail $MAX_SPLIT_CHAR_NUM | |
| } | |
| while true; do | |
| print_main_menu | |
| local CHOICE=$(echo -e "\n${BOLD}└─ 请输入选项: ${PLAIN}") | |
| read -rp "${CHOICE}" INPUT | |
| case "${INPUT}" in | |
| 1) print_system_info ;; | |
| 2) system_test_menu ;; | |
| 3) sys_update ;; | |
| 4) sys_clean ;; | |
| 11) system_tools_menu ;; | |
| 12) service_tools_menu ;; | |
| 13) commonly_tools_menu ;; | |
| 14) other_scripts_menu ;; | |
| 21) caddy_management_menu ;; | |
| 22) docker_management_menu ;; | |
| 23) python_management_menu ;; | |
| xx) sys_reboot ;; | |
| 00) script_update ;; | |
| 0) echo -e "\n$WARN 退出脚本!${RESET}" && _IS_BREAK="false" && exit 0 ;; | |
| *) _BREAK_INFO=" 请输入正确的数字序号!" && _IS_BREAK="true" ;; | |
| esac | |
| case_end_tackle | |
| done | |
| } | |
| function script_update(){ | |
| cd ~ &>/dev/null | |
| local fname='qiq.sh' | |
| echo -e "\n $TIP 检测更新中,请稍等..." | |
| local url_update=$(get_proxy_url $URL_UPDATE) | |
| local url_script=$(get_proxy_url $URL_SCRIPT) | |
| bash <(wget --no-check-certificate -qO- $url_update) | |
| echo -e "\n$TIP 脚本下载 ...\n" | |
| curl -SL -o ${fname} $url_script && \ | |
| chmod +x ${fname} && \ | |
| echo -e "$TIP 脚本已更新至最新版本!\n" | |
| _IS_BREAK="true" | |
| case_end_tackle && _IS_BREAK="false" | |
| ./${fname} && _IS_BREAK="false" && exit 1; | |
| # _IS_BREAK="false" && exit 1 && ./${fname} ; | |
| } | |
| #================= | |
| # 设置qiq快捷命令 | |
| # set_qiq_alias 1 | |
| set_qiq_alias | |
| # 初始化全局变量 | |
| init_global_vars | |
| # 检测系统IP地址 | |
| check_ip_status | |
| # 显示主菜单 | |
| main_menu |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment