我的笔记

本项目基于 mdbook 框架,主要是用作笔记的功能,记录一些重要的内容,以方便我在不同的机器上使用 Copy+Paste 魔法。

因为是笔记的原因,所以我不会写得太详细,目的是达到我自己能看懂,并且里面很多的配置都是直接复制我的生产环境配置。

非常荣幸你能看到我的笔记。

使用 Wiringpi

官方文档 📝

wiringpi

一、安装 wiringpi

安装 wiringpi:

cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

测试是否安成功:

gpio -v

二、基础命令

查看 GPIO 状态:

gpio readall

设置 GPIO 14 号引脚为输出,并且输出高电平:

gpio mode 15 out
gpio write 15 1

还原 GPIO 14 状态:

gpio write 15 0
gpio mode 15 in

三、调用<wiringpi.h>

我们写一个 fan.c 的程序,该程序用于控制树莓派的 GPIO 14。

#include <signal.h>
#include <wiringPi.h>

#define Fan 14

int isLoop = 1;

void breakLoop(int signal) {
    isLoop = 0;
}

int main(void) {
    signal(SIGINT, breakLoop);
    signal(SIGTERM, breakLoop);
    signal(SIGHUP, breakLoop);

    wiringPiSetupGpio();
    pinMode(Fan, OUTPUT);
    digitalWrite(Fan, HIGH);

    while (isLoop);

    digitalWrite(Fan, LOW);
    pinMode(Fan, INPUT);
    return 0;
}

编译代码:

gcc -Wall -o fan fan.c -lwiringPi

执行代码:

./fan

使用 Init

官方文档 📝

init

一、配置 init 服务

进入配置文件:

vim /etc/init.d/your_service

添加服务内容:

#!/bin/sh /etc/rc.common

START=99
STOP=10

# commands to launch application
start() {
    echo start
}

# commands to kill application
stop() {
    ps | awk '/[y]our_service/{print $1}'
}

# start application after boot
boot() {
    start
}

给予执行权限:

chmod u+x /etc/init.d/your_service

二、使用 init 服务

运行脚本:

/etc/init.d/your_service start

开机自启任务:

/etc/init.d/your_service enable

关闭开机自启:

/etc/init.d/your_service disable

使用 Vim

一、安装 Vim

opkg update
opkg install vim-full vim-runtime

二、配置 Vim

进入配置文件

vim /usr/share/vim/vimrc

配置内容可参考 Linux-Vim

使用 Uhttp

官方文档 📝

uhttp

一、安装 uhttpd

opkg update
opkg install uhttpd

二、基本配置模板

进入配置文件:

vim /etc/config/uhttpd

在已有模板后添加以下内容:

config uhttpd 'profile'
    option listen_http '8080'
    option home '/root/profile'

三、重启 uhttpd

/etc/init.d/uhttpd restart

使用 Mosquitto

一、安装 Mosquitto

进入 OpenWrt 控制台,执行以下命令:

opkg install mosquitto-ssl

安装完成后我们先关闭 Mosquitto 服务,因为我们需要修改配置文件:

/etc/init.d/mosquitto stop

二、配置 Mosquitto

修改配置文件:

vim /etc/mosquitto/mosquitto.conf

配置文件的位置可能有所不同,你可以打开 /etc/init.d/mosquitto 查看配置文件的位置,如:

#!/bin/sh /etc/rc.common
# Basic init script for mosquitto
# April 2012, OpenWrt.org
# Provides support for the luci-app-mosquitto package, if installed

START=80
USE_PROCD=1
TCONF=/tmp/mosquitto.generated.conf
CONF_WATCH=/etc/mosquitto/mosquitto.conf

然后清空配置文件,添加以下内容:

listener 1883 0.0.0.0

persistence true

log_type debug
log_dest file /etc/mosquitto/data/mosquitto.log

allow_anonymous false
password_file /etc/mosquitto/data/passwords.txt

可以发现,我们在配置文件中指定了密码文件和日志的位置。

我们先创建一个 data 目录:

mkdir -p /etc/mosquitto/data

使用以下命令创建密码文件,根据提示输入密码即可:

mosquitto_passwd -c /etc/mosquitto/data/passwords.txt username

然后再使用以下命令创建一个空的日志文件:

touch /etc/mosquitto/data/mosquitto.log

最后给予密码文件和日志文件写入权限:

chmod 777 /etc/mosquitto/data/passwords.txt
chmod 777 /etc/mosquitto/data/mosquitto.log

三、启动 Mosquitto

启动 Mosquitto 服务:

/etc/init.d/mosquitto start

四、测试 Mosquitto

我们可以使用 MQTT 客户端测试 Mosquitto 服务是否正常运行,这里我已 ubuntu 为例。

安装 MQTT 客户端:

sudo apt install mosquitto-clients

订阅主题:

mosquitto_sub -h 192.168.10.1 -t test -u username -P password

发布消息:

mosquitto_pub -h 192.168.10.1 -t test -u username -P password -m "Hello, World!"

其他配置及常用命令

更新包:

opkg update

查看系统信息:

cat /proc/cpuinfo

查看已连接的 WiFi 设备:

cat /tmp/dhcp.leases

查看主机 ip 地址:

ip r|grep 'default' | awk '{print $7}'

查看主机网关地址:

ip r|grep 'default' | awk '{print $3}'

删除某个进程:

kill $(ps|awk '/[m]qtt/{print $1}')

快捷键

一、系统快捷键

1.1 编辑类

快捷键作用
Cmd + C复制
Cmd + V粘贴
Cmd + X剪切
Cmd + Z撤销
Cmd + S保存
Cmd + A全选
Cmd + F查找

1.2 窗口类

快捷键作用
Cmd + H隐藏当前窗口
Cmd + Q退出应用
Cmd + W关闭当前窗口
Cmd + Ctrl + FFn + F切换全屏
Cmd + M最小化窗口
Cmd + N新建窗口
Cmd + Tab切换窗口

1.3 截图类

快捷键作用
Cmd + Shift + 3截取全屏
Cmd + Shift + 4截取指定区域
Cmd + Shift + 4 + 空格截取窗口
Cmd + Shift + 5截取屏幕录像

1.4 光标移动

快捷键作用
Cmd + ←行首
Cmd + →行尾
Cmd + ↑文件顶部
Cmd + ↓文件底部
Cmd + Delete删除光标前字符
Option + ←移动光标到单词左边
Option + →移动光标到单词右边

1.4 其他

快捷键作用
Cmd + Space打开 Spotlight
Cmd + Option + Esc强制退出应用

二、应用快捷键

2.1 Finder

快捷键作用
Cmd + N新建窗口
Cmd + Shift + N新建文件夹
Cmd + Delete移动到废纸篓
Cmd + Shift + Delete清空废纸篓
Cmd + Option + L打开下载文件夹
Cmd + Option + P显示/隐藏路径栏

2.2 Safari

快捷键作用
Cmd + T新建标签
Cmd + W关闭标签
Cmd + R刷新页面
Cmd + L定位地址栏

使用 NVM

一、安装 NVM

使用 homebrew 安装 nvm:

brew install nvm

二、配置 NVM

~/.zshrc~/.bashrc 中添加以下内容:

export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"  # This loads nvm
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"  # This loads nvm bash_completion

三、使用 NVM

关于如何使用 nvm,请参考 Windows/使用 NVM

使用 Homebrew

Homebrew 是 macOS 上的软件包管理器,可以帮助你安装和管理软件包。它是一个非常强大的工具,可以帮助你快速安装软件包,而不需要手动下载和安装。

一、安装 xcode-select

在安装 Homebrew 之前,你需要安装 xcode-select,它是 macOS 上的一个命令行工具,可以帮助你安装开发工具,如git、make、gcc等。

xcode-select --install

二、安装 Homebrew

安装 Homebrew 非常简单,只需要在终端中运行以下命令即可:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

三、配置 Homebrew

安装完成后,你需要配置 Homebrew,以便它可以正常工作。首先,你需要将 Homebrew 的路径添加到你的 PATH 环境变量中,正常情况下,如果你是使用 zsh,那么你可以将以下命令添加到你的 ~/.zshrc 文件中:

eval "$(/opt/homebrew/bin/brew shellenv)"

四、使用 Homebrew

检查 Homebrew 是否安装成功:

brew --version

检查系统是否正常:

brew doctor

更新 Homebrew:

brew update

升级 Homebrew:

brew upgrade

五、常用命令

nvm

brew install nvm

htop

brew install htop

wget

brew install wget

使用 Oh-My-Posh

官方文档 📝

oh-my-posh

一、安装

通过 homebrew 安装 oh-my-posh

brew install romkatv/powerlevel10k/oh-my-posh

二、配置

.zprofile 中添加以下内容:

# Oh-my-posh
eval "$(oh-my-posh init zsh --config $(brew --prefix oh-my-posh)/themes/amro.omp.json)"

更改 cache 位置,新建一个 ~/.cache 目录,oh-my-ppsh 会在这个目录下缓存一些文件:

mkdir ~/.cache

其他配置及常用命令

一、Git 无法提交

问题描述:在提交代码时,出现如下错误:

warning: unable to access '/Users/cael/.config/git/ignore': Permission denied
warning: unable to access '/Users/cael/.config/git/attributes': Permission denied

这主要是由于权限问题导致的,可以通过以下命令解决:

sudo chown -R cael:(id -gn $USER) /Users/cael/.config

修改 HOST

Windows 上的 HOST 文件位于:

C:\Windows\System32\drivers\etc\hosts

使用 GO

一、安装 GO

前往 Golang 官网 下载最新版本的 Golang 安装包。

二、设置代理

使用 go env 命令设置代理:

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct

使用管理员打开设置全局的环境变量:

setx /M HTTP_PROXY "http://127.0.0.1:7890"
setx /M HTTPS_PROXY "http://127.0.0.1:7890"

使用 WSL

一、卸载和安装

查看 WSL 信息:

wsl --status

查看已安装的 WSL 发行版:

wsl --list --verbose

查看可使用的 WSL 发行版:

wsl --list --online

安装某个 WSL 发行版:

wsl --install Ubuntu

卸载某个 WSL 发行版:

wsl --unregister Ubuntu

启动某个 WSL 发行版:

wsl -d Ubuntu

停止某个 WSL 发行版:

wsl --terminate Ubuntu

重启某个 WSL 发行版:

wsl --shutdown Ubuntu

停止所有 WSL 发行版:

wsl --shutdown

设置默认的 WSL 发行版:

wsl --set-default Ubuntu

二、文件系统

WSL 与 Windows 共享文件系统,可以通过 \\wsl$ 访问 WSL 文件系统。

查看 WSL 文件系统:

explorer.exe \\wsl$

在 WSL 中访问 Windows 文件系统:

cd /mnt/c

在 Windows 中访问 WSL 文件系统:

cd \\wsl$\Ubuntu

三、WSL 与 Windows 交互

在 WSL 中执行 Windows 命令:

cmd.exe /c echo hello

在 WSL 中启动 Windows 程序:

explorer.exe .

在 Windows 中执行 WSL 命令:

ls | wsl grep .md

四、WSL 配置文件

官方文档 📝

WSL Configuration

某个 WSL 发行版的配置文件:

vim /etc/wsl.conf

参考配置:

[boot]
systemd=true
command = service nginx start

[automount]
enabled = true

全局 WSL 配置文件:

notepad ~/.wslconfig

参考配置:

[wsl2]
memory=4GB
firewall=true
autoProxy=true
dnsTunneling=true
networkingMode=mirrored

五、备份和恢复

备份 WSL 发行版:

wsl --export Ubuntu ubuntu.tar

恢复 WSL 发行版:

wsl --import Ubuntu ubuntu.tar

使用 SSH

一、安装 OpenSSH

如果你是 Windows 10,那么可以在 设置 -> 应用 -> 可选功能 中安装 OpenSSH 客户端和服务器。

如果你是 Windows 11,那么可以在 设置 -> 系统 -> 可选功能 中安装 OpenSSH 客户端和服务器。

请按照下图所示安装 OpenSSH ServerOpenSSH Client 可选安装,一般系统默认已经安装:

install-openssh

然后用管理员权限打开 PowerShell,运行以下命令查看 OpenSSH 服务状态:

Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'

输出内容类似如下:

Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed

Name  : OpenSSH.Server~~~~0.0.1.0
State : Installed

如果 StateInstalled,则表示 OpenSSH 服务已经安装。

二、配置 OpenSSH

管理员权限打开 PowerShell

然后设置 OpenSSH 服务自动启动:

Set-Service -Name sshd -StartupType 'Automatic'

接着启动 OpenSSH 服务:

Start-Service sshd

最后查看 OpenSSH 服务状态:

Get-Service -Name sshd

另外也可以查看 22 端口是否已经监听:

netstat -an | findstr /i ":22"

三、配置防火墙

如果你的 Windows 系统开启了防火墙,那么需要配置防火墙允许 OpenSSH 服务通过。

用管理员权限打开 PowerShell,查看防火墙规则:

Get-NetFirewallRule -Name *OpenSSH-Server* | select Name, Enabled

输出内容类似如下:

Name                  Enabled
----                  -------
OpenSSH-Server-In-TCP    True

如果 EnabledFalse,则表示防火墙规则未启用,需要启用防火墙规则:

New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

四、配置文件

官方文档 📝

OpenSSH 官方文档

如果你有其他的 SSH 配置需求,可以修改 SSH 的配置文件:

C:\Programdata\ssh\sshd_config

例如,你可以修改 SSH 的端口号:

Port 2222

还例如,我们想使用 Powershell 作为默认的 Shell,可以修改如下配置:

ForceCommand pwsh.exe

修改配置文件后,需要重启 OpenSSH 服务:

Restart-Service sshd

五、使用 SSH

在 Winddows 上使用 SSH 类似于在 Linux 或 macOS 上使用 SSH,可以参考后面 在 Linux 中使用 SSH 的文档。

在 Windows 系统中,可以使用 ssh 命令连接远程服务器,例如:

ssh username@hostname

其中 username 是远程服务器的用户名,hostname 是远程服务器的 IP 地址或域名。

如果你的远程服务器使用非默认的 SSH 端口,可以使用 -p 参数指定端口:

ssh -p port username@hostname

其中 port 是远程服务器的 SSH 端口。

如果你的远程服务器使用密钥登录,可以使用 -i 参数指定密钥文件:

ssh -i keyfile username@hostname

其中 keyfile 是密钥文件的路径。

使用 NVM

一、安装 NVM

前往 Github 下载最新的NVM

也可以通过 Winget 安装 NVM:

winget install --id CoreyButler.NVMforWindows

二、使用 NVM

查看可用的 Node

# 查看已安装的Node
nvm list installed
# 查看可用的Node
nvm list available

安装 Node

# 安装最新版本的Node
nvm install latest
# 安装指定版本的Node
nvm install 18.20.4

切换 Node 版本

# 切换到最新版本的Node
nvm use latest
# 切换到指定版本的Node
nvm use 18.20.4

卸载 Node

# 卸载指定版本的Node
nvm uninstall 18.20.4

使用 Pyenv

一、安装 Pyenv

使用 Powershell 安装:

Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

二、使用 Pyenv

查看可用的 Python

# 查看已安装的Python
pyenv global
# 查看可用的Python
pyenv install --list

安装 Python

pyenv install 3.12.0

切换 Python 版本

pyenv global 3.12.0

卸载 Python

pyenv uninstall 3.12.0

使用 Winget

一、软件类

VSCode

winget install --id Microsoft.VisualStudioCode

Chrome

winget install --id Google.Chrome

Github Desktop

winget install --id GitHub.GitHubDesktop

Bandzip

winget install --id Bandisoft.Bandizip

Drawio

winget install --id JGraph.Draw

Wireguard

winget install --id WireGuard.WireGuard

Powertoys

winget install --id Microsoft.PowerToys

Raspberry Pi Imager

winget install --id RaspberryPiFoundation.RaspberryPiImager

Docker Desktop

winget install --id Docker.DockerDesktop

Postman

winget install --id Postman.Postman

Telegram Desktop

winget install --id Telegram.TelegramDesktop

MongoDB Compass

winget install --id MongoDB.Compass.Full

二、终端类

Git

winget install --id Git.Git

Oh-My-Posh

winget install --id JanDeDobbeleer.OhMyPosh

Powershell

winget install --id Microsoft.PowerShell

NVM

winget install --id CoreyButler.NVMforWindows

Rust

winget install --id Rustlang.Rust.MSVC

NTOP

winget install --id Gsass1.NTop

NeoVim

winget install --id Neovim.Neovim

UPX

winget install --id=UPX.UPX

mkcert

winget install --id FiloSottile.Mkcert

使用 Oh My Posh

官方文档 📝

oh-my-posh

一、安装 Oh My Posh

使用 Winget 安装 Oh My Posh:

winget install --id JanDeDobbeleer.OhMyPosh

也可以使用 PowerShell 脚本安装:

Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://ohmyposh.dev/install.ps1'))

二、配置 Oh My Posh

在 PowerShell 配置文件中添加以下内容:

# Oh-My-Posh
oh-my-posh init --config "$env:POSH_THEMES_PATH/amro.omp.json" | Invoke-Expression

使用 Powershell

一、安装 Powershell

前往 Github 下载最新版本的Powershell

也可以通过 Winget 安装 Powershell:

winget install --id Microsoft.PowerShell

二、配置 Powershell

1. 允许运行脚本

使用管理员权限打开 Powershell,输入以下命令:

Set-ExecutionPolicy RemoteSigned

2. 添加 Powershell 配置文件

进入配置文件:

vim $PROFILE

添加以下内容:

# Function
function la_fun { Get-ChildItem -Force }
function git_clean_fun { git restore . ; git clean -f }
function docker_clean_fun { docker system prune -a -f }

# Set Alias
Set-Alias -Name vim -Value nvim
Set-Alias -Name ll -Value Get-ChildItem
Set-Alias -Name la -Value la_fun
Set-Alias -Name htop -Value ntop
Set-Alias -Name ifconfig -Value ipconfig
Set-Alias -Name git-clean -Value git_clean_fun
Set-Alias -Name docker-clean -Value docker_clean_fun

# Oh-My-Posh
oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH/amro.omp.json" | Invoke-Expression

# Enviroments
$env:TF_ENABLE_ONEDNN_OPTS=0
$env:TF_CPP_MIN_LOG_LEVEL=1

三、使用 Powershell:

在终端中输入以下命令启动 powershell:

pwsh

设置环境变量

一、 查看环境变量

set

二、设置临时环境变量

设置临时环境变量只在当前会话中有效,关闭当前会话后失效:

set ENV_NAME "value"

删除临时环境变量:

set ENV_NAME=

三、设置全局环境变量

设置全局环境变量需要管理员权限:

setx /M ENV_NAME "value"

删除全局环境变量:

setx /M ENV_NAME=

使用 git

一、配置 git

进入 git 配置文件:

vim ~/.gitconfig

然后添加以下内容:

[user]
    name=Cael
    email=MR-Addict@qq.com
[http]
    proxy=http://127.0.0.1:7890
[https]
    proxy=http://127.0.0.1:7890

二、首次提交模板

添加基本内容:

git init
echo "# Test" > README.md
git add README.md
git commit -m "First commit"

添加远程仓库链接:

git remote add github https://github.com/MR-Addict/Doc-Share.git

更改默认分支名为 main:

git branch -M main

推送提交到远程仓库:

git push -u github main

三、命令合集

删除本地和远程标签:

git tag -d $tag
git push origin :refs/tags/$tag

重命名本地和远程标签:

git tag $tagNew $tagOld
git tag -d $tagOld
git push origin $tagNew :$tagOld

删除本地和远程分支:

git branch -D $branch
git push origin --delete $branch

四、配置命令

查看本地配置:

git config --list

查看全局配置:

git config --global --list

编辑全局配置:

git config --global --edit

设置全局用户名:

git config --global user.name Cael

配置全局用户邮箱:

git config --global user.email MR-Addict@qq.com

设置只拉取不提交:

git config --global pull.ff only

设置默认分支为 main:

git config --global init.defaultBranch main

保存系统登录验证:

git config --system credential.helper store

重置系统登录验证:

git config --system --unset credential.helper

五、其他常用命令

查看提交记录:

git log

查看当前状态:

git status

回退版本:

git reset --hard $hash_value_of_last_commit

重置所有内容,并且删除新文件:

git restore .
git clean -f

使用 Vim

一、安装 Vim

sudo apt-get install vim -y

二、配置 Vim

注意 💥

你可以在打开vim 编辑器之后,输入下面的命令查看支持的配置文件位置:

:version

进入 vim 配置文件:

vim ~/.vimrc

添加以下内容:

syntax on

set number
set relativenumber
set tabstop=2 softtabstop=2
set shiftwidth=2
set expandtab
set smartcase
set incsearch
set nobackup
set undodir=~/.vim/undodir
set undofile
set backspace=indent,eol,start
set smartindent

let &t_SI = "\e[6 q"
let &t_EI = "\e[2 q"

注意 💥

本配置只在当前用户下有效,如果你想在 root 也有效需要重新配置

Windows 下的配置文件为 ~/AppData/Local/nvim/init.vim

三、使用 vim

命令类


强制退出:

q!

退出并保存:

qw

执行命令:

!echo hello

编辑类


在前方插入:

i

在最前端插入:

[shift]+i

在后方插入:

a

在最后端插入:

[shift]+a

在下方插入:

o

在上方插入:

[shift]+o

替换:

r+[letter]

快捷键类


删除:

v+d

复制:

v+y

粘贴:

p

搜索:

/[keyword]
# 搜索下一个
n
# 搜索上一个
N

替换:

:%s/name_1/name_2/g

清空整个文件:

:%d

使用 SSH

一、通过 Puttygen 使用 SSH

直接参考以下文章即可,这里不做详细介绍了:

参考文章 📝

How to generate public and private ssh key using putty

二、使用 ssh-keygen 配置 SSH 密钥

生成密钥,一路回车选择默认选项就好了:

ssh-keygen -t rsa -b 2048 -f piserver -C "piserver"

配置服务器,将公钥放到服务器上:

cat piserver.pub >> ~/.ssh/authorized_keys

配置连接端:

vim ~/.ssh/config

添加以下内容:

Host piserver
     HostName 192.168.10.30
     Port 22
     User cael
     IdentityFile ~/Documents/cael/ssh/piserver/piserver

三、使用 scp 复制文件

从服务器复制文件,服务器路径为/home/cael/projects/hello.py,客户端路径为当前路径:

scp cael@192.168.10.30:projects/hello.py .

向客户端传输文件,服务器路径为/home/cael/projects,客户端路径为当前路径:

scp hello.py cael@192.168.10.30:projects

复制整个文件夹到服务器,服务器路径为/home/cael/pictures,客户端路径为当前路径:

scp -r Images cael@192.168.10.30:pictures

配置 Alias

进入 sh_aliaes 配置文件

vim ~/.sh_aliases

添加以下内容:

alias la="ls -a"
alias ll="ls -l"

alias reboot="sudo reboot"
alias shutdown="sudo shutdown -h now"

alias git-clean="git restore . && git clean -f"
alias docker-clean="docker system prune -a -f"
alias apt-update="sudo apt-get update && sudo apt-get dist-upgrade -y"
alias apt-clean="sudo apt-get autoremove -y && sudo apt-get clean -y"

注意 💥

本配置只在当前用户下有效,如果你想在 root 也有效需要重新配置

使用 Crontab

一、配置 crontab

进入 corntab 配置文件:

crontab -e

如果你是第一次使用,crontab 可能需要你选择默认的编辑器,这边我一般会选择 vim 作为我的编辑器,因此输入 2:

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

你也可以在后面更改默认的编辑器:

select-editor

或者使用下面的命令直接更改默认编辑器:

sudo update-alternatives --set editor /usr/bin/vim.basic

查看已有任务:

crontab -l

二、contab 语法

基本格式:

* * * * * [username] command(s)
- - - - -
| | | | |
| | | | ----- Day of week  (0 - 7) (Sunday=0 or 7)
| | | ------- Month        (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour         (0 - 23)
------------- Minute       (0 - 59)

部分符号含义:

符号含义
*任意值
,分割符
-范围符
/步数符
@reboot启动事件

Crontab 在线编辑器 🎉

crontab.guru

三、示例

每两小时自动更新 apt。

* */2 * * * root apt-get update && apt-get upgrade -y

周日到周五晚 23:30 自动关机,即跳过星期六。

30 23 * * 0-5 sudo /usr/sbin/shutdown -h now

开机自动调用 wiringpi 打开风扇。

@reboot gpio mode 15 out && gpio write 15 1

Systemd 使用方法

参考文档 📝

systemd

一、常用命令

start 启动服务:

sudo systemctl start application.service

stop 停止服务:

sudo systemctl stop application.service

restart 重启服务:

sudo systemctl restart application.service

reload 重新加载配置文件,如果你的服务支持该操作的话,如 nginx

sudo systemctl reload application.service

如果你不确定你的服务是否支持重加载,那么可以使用 reload-or-restart 命令,systemd 会首先 reload,如果该服务器不支持 reload 则 restart:

sudo systemctl reload-or-restart application.service

status 用于检查当前的服务状态,包括服务器日志等:

sudo systemctl status application.service

enable 用于在机器启动时自动启动该服务器:

sudo systemctl enable application.service

disable 可以让服务在开机时停止自动启动:

sudo systemctl disable application.service

is-active 用于查询服务器是否启动:

systemctl is-active application.service

is-enable 用于查询服务是否开机自启:

systemctl is-enabled application.service

is-failed 用于查询服务是否启动失败:

systemctl is-failed application.service

注意 💥

systemd 可以自动检测服务的文件地址,因此可以省略上面的.service后缀,下同

二、系统服务

显示启动的服务:

systemctl list-units

显示所有的服务:

systemctl list-units --all

服务筛选,如仅显示未启动的服务:

systemctl list-units --all --state=inactive

三、服务配置

显示某服务的配置文件内容:

systemctl cat application.service

显示某服务的依赖:

systemctl list-dependencies application.service

修改某服务:

sudo systemctl edit --full application.service

新建某服务:

sudo systemctl edit --full --force application.service

删除某服务:

sudo rm /etc/systemd/system/application.service
sudo rm -r /etc/systemd/system/application.service.d

重启 systemd:

sudo systemctl daemon-reload

四、新建服务

新建某服务:

sudo systemctl edit --full --force application.service

服务模板:

[Unit]
After=network.target
Description=description
StartLimitBurst=5
StartLimitIntervalSec=100

[Service]
Type=simple
User=user_name
Restart=always
RestartSec=1
ExecStart=/path/to/app

[Install]
WantedBy=multi-user.target

Swap 交换空间

一、基本操作

查看运行内存和交换空间:

free

查看 swap 所在分区:

swapon

卸载 swap 分区:

swapoff $swap_location

删除 swap 分区:

sudo rm $swap_location

二、创建和挂载 swap 分区

创建空文件:

sudo dd if=/dev/zero of=/swap bs=1M count=2048 status=progress

给予权限:

sudo chmod 600 /swap

格式化 swap 分区:

sudo mkswap /swap

挂载 swap 分区:

sudo swapon /swap

持久化分区:

sudo vim /etc/fstab

末尾添加以下内容:

/swap none swap sw 0 0

三、参考视频

Linux 用户和用户组

一、管理用户

查看当前用户:

whoami

查看所有用户:

cat /etc/passwd

添加新用户:

sudo useradd -m -s /bin/sh -c "test-user" test

更改用户密码:

sudo passwd test

更改文件或者文件夹所有者:

sudo chown $user:$user $filename_or_folder

登录其他用户:

su test

删除用户:

sudo userdel test

二、管理用户组

查看所有用户组:

cat /etc/group

添加用户到其他用户组:

sudo usermod -aG sudo test

添加新用户组:

sudo groupadd test

删除用户组:

sudo groupdel test

其他配置及常用命令

查看系统 CPU:

htop

查看系统存储空间:

df -h

查看系统进程:

ps -A

结束某个进程:

kill $id

安装字体:

sudo fc-cache -fv

更新树莓派 eeprom:

sudo rpi-eeprom-update -a

查看树莓派温度:

vcgencmd measure_temp

使用 pip-review 更新 pip

pip-review --interactive

安静启动 Telegram

Telegram --startintray

解压 tar 压缩包:

tar -xvf your/tar/gz/file

设置默认编辑器:

sudo update-alternatives --config editor

查看系统内部端口使用情况:

netstat --tcp --listening --programs --numeric

配置 WiFi:

sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

设置用户默认 shell:

sudo usermod --shell /bin/sh $USER

sh 脚本出现^M 错误:

sed -i 's/\r//' $yourfile

使用 python 运行 http 服务:

python -m http.server 8080 --directory public

设置时区:

sudo timedatectl set-timezone Asia/Shanghai

sudo visudo 免密码:

username ALL=(ALL) NOPASSWD: ALL

使用 Node

官方文档 📝

node

一、安装 Node

最新的稳定版本 16:

curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E sh - && sudo apt-get install -y nodejs

最新的稳定版本 18:

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E sh - && sudo apt-get install -y nodejs

二、安装常用包

安装最新的 npm:

npm install -g npm@latest

安装最新的 yarn:

npm install -g yarn@latest

安装最新的 nodemon:

npm install -g nodemon@latest

安装最新的 hexo:

npm install -g hexo-cli@latest

使用 V2ray

参考教程 📝:

V2ray

一、在服务器上安装 V2ray

先安装依赖:

sudo apt install curl unzip

下载安装脚本:

curl -O https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh

安装 V2ray:

sudo sh install-release.sh

开启自启动 V2ray:

sudo systemctl enable v2ray

启动 V2ray:

sudo systemctl restart v2ray

查看 V2ray 状态:

sudo systemctl status v2ray

二、配置 V2ray

检查时间是否校准,和 UTC 时间要小于 60s:

timedatectl

配置 V2ray 配置文件,请设置一个安全的id,这相当于一个密码,你可以使用这个地址生成一个 UUID:

sudo vim /usr/local/etc/v2ray/config.json

添加以下内容:

{
  "log": {
    "loglevel": "warning",
    "access": "/var/log/v2ray/access.log",
    "error": "/var/log/v2ray/error.log"
  },
  "inbounds": [
    {
      "port": 1000,
      "listen": "0.0.0.0",
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "ac2f5a2a-08e8-11ee-be56-0242ac120002",
            "alterId": 0
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings": {
          "path": "/ray"
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

重启 V2ray 让配置生效:

sudo systemctl restart v2ray

查看 V2ray 监听端口:

sudo ss -lnpt | grep v2ray

三、配置 Nginx 反向代理

安装 Nginx:

sudo apt install nginx -y

添加 V2ray 配置:

sudo vim /etc/nginx/conf.d/v2ray.conf

添加以下配置:

server {
  listen 80;
  server_name  your_domain;

  index index.html;
  root /usr/share/nginx/html/;

  error_log /var/log/nginx/v2ray.error;
  access_log /var/log/nginx/v2ray.access;

  location /ray {
    proxy_redirect off;
    proxy_pass http://127.0.0.1:1000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

检查配置文件:

sudo nginx -t

重新加载 Nginx:

sudo systemctl reload nginx

至此 V2ray 服务端已经配置完成。

四、禁用 VMESS-AEAD

为了兼容 IOS,我们需要禁用 v2ray 的 VMESS-AEAD 功能:

sudo vim /etc/systemd/system/v2ray.service

添加以下环境变量到 Service:

Environment=V2RAY_VMESS_AEAD_FORCED=false

重启 Service 生效:

sudo systemctl daemon-reload

五、配置客户端

Clash

参考教程 📝:

Clash

如果你是使用 Clash,可以参考以下配置文件:

mixed-port: 7890
mode: Global
allow-lan: true
ipv6: true
log-level: info

proxies:
  - name: your_v2ray_name
    server: your_server_address
    port: 443
    type: vmess
    uuid: ac2f5a2a-08e8-11ee-be56-0242ac120002
    network: ws
    ws-opts:
      path: /ray
    alterId: 0
    cipher: auto
    tls: true

Shadowrocket

参考教程 📝:

Shadowrocket

请参考以下配置:

shadowrocket-1

其中选择 websocket 传输方式:

shadowrocket-2

使用 nginx

一、安装 nginx

更新 apt 源:

sudo apt-get update

安装 nginx:

sudo apt-get install nginx

使能 nginx:

sudo systemctl enable nginx

启动 nginx:

sudo systemctl start nginx

查看 nginx 状态:

sudo systemctl status nginx

二、使用 nginx

准备网站资源

首先我们需要准备一个可用的静态网站,这里我就使用我 GitHub 上基于 mdbook 的项目,你也可以使用自己的网站:

git clone https://github.com/mr-addict/Doc-Share.git
cd Doc-Share
mdbook build

运行mdbook build后会在当前文件夹自动编译出一个 book 文件夹,也即是我的网页内容,然后我们需要把这个网页放到 ngixn 默认的网页目录下/var/www/

sudo cp -r /home/ubuntu/Doc-Share/book /var/www/

配置网站

然后我们需要配置一下 nginx 的配置文件,nginx 将配置文件放在了两个文件夹下,分别是:

  • sites-available
  • sites-enabled

sites-available 文件夹用于放置所有的网站配置,sites-enabled 文件夹用于放置所有正在使用的网站配置。

首先我们在 sites-available 中新建一个文件:

sudo vim /etc/nginx/sites-availale/notes.conf

然后添加以下内容:

server {
    listen 80;
    listen [::]:80;
    location / {
        root /var/www/book;
        index index.html;
    }
}

完成配置后我们可以通过链接的命令,将 sites-available 中的配置文件链接到 sites-enabled 文件夹中:

sudo ln -sf /etc/nginx/sites-available/* /etc/nginx/sites-enabled/

最后我们重新启动一下 nginx 就可以在本地 80 端口http://localhost正常访问我们的网页内容了:

sudo systemctl restart nginx

三、nginx 模板

nginx 基本配置模板:

server{
  listen 80;
  listen [::]:80;
  server_name mraddict.top;

  location / {
    root /var/www/book;
    index index.html;
  }
}

nginx 基于 SSL 签证模板:

server{
  listen 80;
  listen [::]:80;
  server_name mraddict.top;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name mraddict.top;

  ssl_certificate  /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.cert.pem;
  ssl_certificate_key /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.key.pem;

  location / {
    root /var/www/book;
    index index.html;

    proxy_buffering off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

nginx 基于 SSL 签证的反向代理:

server{
  listen 80;
  listen [::]:80;
  server_name mraddict.top;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name mraddict.top;

  ssl_certificate  /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.cert.pem;
  ssl_certificate_key /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.key.pem;

  location / {
    proxy_pass http://localhost:8080;

    proxy_buffering off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

使用 MySQL

参考文档 📝:

MySQL

一、使用 MySQL

更新 apt 库:

sudo apt-get update

安装 MySQL:

sudo apt-get install mysql-server -y

二、配置 MySQL

首先先登录 MySQL:

sudo mysql

然后更改 root 密码:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_new_password';

然后退出运行安装脚本:

sudo mysql_secure_installation

三、创建新用户

进入 mysql:

sudo mysql -u root -p

创建新用户:

CREATE USER 'user_name'@'localhost' IDENTIFIED WITH mysql_native_password BY 'user_password';

授予用户权限:

GRANT CREATE, ALTER, DROP, INSERT, UPDATE, DELETE, SELECT, REFERENCES, RELOAD on *.* TO 'user_name'@'localhost' WITH GRANT OPTION;

清空权限缓存:

FLUSH PRIVILEGES;

退出然后登录新用户:

sudo mysql -u user_name -p

四、用户操作

查看所有用户:

SELECT User, Host FROM mysql.user;

删除用户:

DROP USER 'user_name'@'localhost';

更改用户密码:

ALTER USER 'user_name'@'localhost' IDENTIFIED BY 'new_password';

更改用户名和主机名:

RENAME USER 'user_name'@'host_ip' TO 'another_user_name'@'another_host_ip'

五、数据库操作

显示已有数据库:

SHOW DATABASES;

创建新的数据库:

CREATE DATABASE db_name;

使用某个数据库:

USE db_name;

删除数据库:

DROP DATABASE db_name;

重命名数据库:

RENAME TABLE old_db.table TO new_db.table;

六、Table 操作

创建 Table:

CREATE TABLE books(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50) NOT NULL,
    price INT NOT NULL,
    lang VARCHAR(50) DEFAULT "English" NOT NULL,
    author VARCHAR(60) NOT NULL
);

显示 Table 框架:

DESCRIBE books;

插入新的记录:

INSERT INTO books(title, price, lang, author) VALUE("Bible",50.00,"Hindi","Jone");

插入新列:

ALTER TABLE table_name;
ADD COLUMN column_name column_definition;

删除 Table:

DROP TABLE IF EXISTS db.table1, db.table2, db.table3;

重命名 Table:

RENAME TABLE db.table TO db.new_table;

七、允许远程连接:

进入配置文件:

sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

找到以下内容,注释掉 IP 绑定:

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
# bind-address          = 127.0.0.1
# mysqlx-bind-address   = 127.0.0.1

然后进入 MySQL,创建可以允许远程连接的用户:

CREATE USER 'user_name'@'remote_login_server_ip' IDENTIFIED BY 'user_password';

你也可以更改当前的用户:

RENAME USER 'user_name'@'localhost' TO 'user_name'@'remote_login_server_ip';

八、更改密码协议

查看当前密码协议:

SHOW VARIABLES LIKE 'validate_password%';

更改当前密码协议:

SET GLOBAL validate_password.policy=LOW;

更改用户密码:

ALTER USER 'user_name'@'localhost' IDENTIFIED BY 'new_password';

九、禁用 ONLY_FULL_GROUP_BY

进入配置文件:

sudo vim /etc/mysql/my.cnf

添加或修改以下内容:

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

使用 Docker

官方文档 📝

docker

一、安装 Docker

安装前建议先卸载旧版本的 Docker:

sudo apt-get remove docker docker-engine docker.io containerd runc

方法一:偷懒式安装 Docker

sudo apt install docker.io

方法二:将 Docker 添加到 apt 源中再安装

更新 apt 并且安装相关依赖:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release

添加 Docker 的 GPG 密钥:

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

添加 Docker 源地址:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

添加当前用户到 docker 用户组:

sudo usermod -aG docker $(whoami)

二、安装 Docker-Compose

前往 GitHub 下载对应的Docker-Compose

wget https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-linux-x86_64
sudo mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
sudo chmod u+x /usr/local/bin/docker-compose

三、配置 Docker

配置 log

进入 Docker 配置文件:

sudo vim /etc/docker/daemon.json

添加以下内容:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

服务器配置代理

进入配置文件:

sudo systemctl edit docker.service

添加以下内容:

[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1"

容器配置代理

进入配置文件:

vim ~/.docker/config.json

添加以下内容:

{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://192.168.10.4:7890",
     "httpsProxy": "http://192.168.10.4:7890",
     "noProxy": "localhost,127.0.0.1"
   }
 }
}

四、编译推送镜像

登录 dockerhub,输入 token:

docker login -u <dockrhub_username>

初次编译

编译镜像:

docker build -t <dockerhub_username>/<dockerhub_repo_name> .

推送镜像:

docker push <dockerhub_username>/<dockerhub_repo_name>

推送已有镜像

提交变更:

docker commit <existing_image> <dockerhub_username>/<dockerhub_repo_name>

推送镜像:

docker push <dockerhub_username>/<dockerhub_repo_name>

五、Docker 的镜像操作

拉取镜像:

docker pull ubuntu

显示已有镜像:

docker images

删除镜像:

docker rmi ubuntu

删除无用镜像:

docker rmi $(docker images --filter "dangling=true" -q --no-trunc)

删除所有无用的镜像、容器、网络和存储器:

docker system prune -a

六、Docker 的容器操作

显示正在运行的容器:

docker ps

显示所有容器:

docker ps -a

停止正在运行的容器:

docker stop ubuntu

重启某个容器:

docker restart ubuntu

从镜像运行容器:

docker run ubuntu

后台运行某个容器:

docker run -d ubuntu

运行某个版本的容器:

docker run -d ubuntu:18

运行结束后自动删除容器:

docker run -d -rm ubuntu

运行可交互容器:

docker run -it ubuntu

端口映射:

docker run -d -p 80:8080 ubuntu

文件映射:

docker run -d -v /opt/mydata:/var/lib/mysql ubuntu

docker-compose 运行容器:

docker-compose up -d

docker-compose 删除容器:

docker-compose down

删除容器:

docker rm $container-name-or-id

删除所有容器:

docker rm $(docker ps --filter status=exited -q)

使用 apache2

一、安装 apache2

sudo apt-get update
sudo apt-get install apache2 -y

打开 apache2 默认地址查看默认的网页内容http://localhost

二、配置 apache2

首先准备好一个网页,然后我们需要对网页进行一些配置。这里我已我的笔记网页为例/home/pi/Projects/Notes/book

新建配置文件:

sudo vim /etc/apache2/sites-available/note.conf

添加以下内容:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /home/pi/Projects/Notes/book
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

然后进入 apache 的配置文件给该目录以权限:

sudo vim /etc/apache2/apache2.conf

添加以下内容:

<Directory "/home/pi/Projects/Notes/book">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

三、使用 apache2

首先我们需要关闭默认的 apache 网页:

sudo a2dissite 000-default.conf

然后激活我们的网页:

sudo a2ensite notes.conf

最后重新启动 apache:

sudo systemctl reload apache2

然后我们就可以通过默认网址访问我们的网页了http://localhost

查看 apche2 服务:

sudo systemctl status apache2

停止 apache2 服务:

sudo systemctl stop apache2

注销 apache2 服务:

sudo systemctl disable apache2

注册 apache2 服务:

sudo systemctl enable apache2

使用 Clash 内核

一、下载 Clash

在这里我们使用 Clash 作为科学上网的代理框架,为什么使用 Clash 呢,那是因为 Clash 内核支持各种 Unix 平台的各个架构;还支持各种代理协议,像 Trojan、Vmess、Shadowsocks 等等;以及强大的分流规则,可以非常方便地自定义各种规则。

你可以到 GitHub 下载Clash 内核。如果你是树莓派 4B 32 位操作系统,那么你应该下载对应 armv7 版本的clash-linux-armv7-v1.11.0.gz,如果是树莓派 4B 64 位操作系统,那么你应该下载对应 armv7 版本的clash-linux-armv8-v1.11.0.gz

下载完成后解压文件,建议把文件名改为clash, 然后移动到/usr/local/bin/clash位置,同时给该文件以执行的权限:

wget https://github.com/Dreamacro/clash/releases/download/v1.10.6/clash-linux-armv7-v1.10.6.gz
gunzip clash-linux-armv7-v1.10.6.gz
rm -rf clash-linux-armv7-v1.10.6.gz
mv clash-linux-armv7 clash
sudo mv clash /usr/local/bin
sudo chmod a+x /usr/local/bin/clash

二、配置 Clash

Clash 配置文件的默认路径是~/.config/clash,如果你的 Home 目录不存在相应文件夹就需要你自己创建,然后把你机场提供的配置文件放到该文件下就可以了,Clash 配置文件的默认名称应该是config.yaml

mkdir ~/.config/clash
mv your/clash/config/file config.yaml
mv config.yaml ~/.config/clash

另外 Clash 还需要一个Country.mmdb 文件,Country.mmdb 是全球 IP 库,可以实现各个国家的 IP 信息解析和地理定位,没有这个文件 clash 无法正常启动,你可以前往GitHub 下载。下载完成后同样放在默认路径下就可以了~/.config/clash

三、配置终端代理

首先我们需要添加几个环境变量:

sudo vim /etc/environment

然后添加以下配置内容:

export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export no_proxy="localhost, 127.0.0.1, *edu.cn"

注意 💥

系统变量的 https_proxy 的代理地址和 http_proxy 的代理地址是一样的,因为 Clash 使用一个地址同时代理 http 和 https。另外,no_proxy 表示其中的地址不需要代理,这一点很重要,比如我们不需要代理我们的校园网地址,因此加入要*edu.cn

然后再对相应的终端应用配置代理:

为 sudo 配置代理

进入 sudo 配置文件:

sudo visudo

然后添加以下内容:

Defaults env_keep+="http_proxy https_proxy no_proxy"

为 apt 配置代理

进入 apt 配置文件:

sudo vim /etc/apt/apt.conf.d/10proxy

然后添加以下内容:

Acquire::http::Proxy "http://127.0.0.1:7890/";

为 git 配置代理

进入 git 配置文件:

vim ~/.gitconfig

然后添加以下内容:

[http]
  proxy=http://127.0.0.1:7890
[https]
  proxy=http://127.0.0.1:7890

为 pip 配置代理

进入 pip 配置文件:

vim ~/.config/pip/pip.conf

然后添加以下内容:

[global]
  proxy = http://127.0.0.1:7890
  http-proxy = http://127.0.0.1:7890
  https-proxy = http://127.0.0.1:7890
  trusted-host = pypi.python.org global.trusted-host pypi.org global.trusted-host files.pythonhosted.org

为 npm 配置代理

进入 npm 配置文件:

vim ~/.npmrc

然后添加以下内容:

proxy=http://127.0.0.1:7890
http-proxy=http://127.0.0.1:7890
https-proxy=http://127.0.0.1:7890

为 cargo 配置代理

进入 cargo 配置文件:

vim ~/.cargo/config

然后添加以下内容:

[http]
  proxy=http://127.0.0.1:7890
[https]
  proxy=http://127.0.0.1:7890

为 docker 配置代理

新建 docker 配置文件夹:

sudo mkdir -p /etc/systemd/system/docker.service.d

新建 docker 代理配置文件:

sudo vim /etc/systemd/system/docker.service.d/proxy.conf

添加以下配置:

[Service]
Environment="NO_PROXY="localhost,127.0.0.1"
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"

重启 serive 配置文件:

sudo systemctl daemon-reload

重启 docker:

sudo systemctl restart docker.service

四、使用 Clash

配置完成后需要重启树莓派让配置生效,这样配置才能生效。理论上这样一波配置后,大部分终端应用都可以正常使用了,如果你有其他的终端应用可自行参考相关文档进行配置。

重启之后在终端中输入 clash,如果输出类似以下内容那么就说明 Clash 启动成功了。

INFO[0000] Start initial compatible provider 手动选择
INFO[0000] Start initial compatible provider 节点选择
INFO[0000] Start initial compatible provider 故障切换
INFO[0000] Start initial compatible provider 自动选择
INFO[0000] HTTP proxy listening at: [::]:7890
INFO[0000] RESTful API listening at: 127.0.0.1:9090
INFO[0000] SOCKS proxy listening at: [::]:7891

你可以更新一下系统或者打开浏览器测试一下 Google,如果可以访问你就可以愉快地玩耍了!

注意 💥

在终端请不要使用ping google.com来测试,因为 ping 使用不同的协议无法被 Clash 代理,但是可以使用curl google.com

五、开机自启

既然我们都已经可以使用 Clash 了,当然要让树莓派能够开机自启 Clash 对吧。在树莓派推荐使用 crontab 作为自动任务管理器。

输入以下命令可以打开 crontab:

crontab -e

第一次使用可能需要你选择默认的编辑器,看个人喜好选择就好,然后在打开的文件末尾添加以下内容:

@reboot /usr/local/bin/clash

你也可以使用 systemd 来管理 Clash 的开机自启,首先创建一个服务文件:

sudo vim /etc/systemd/system/clash.service

然后添加以下内容:

[Unit]
After=network.target
Description=clash
StartLimitBurst=5
StartLimitIntervalSec=100

[Service]
Type=simple
User=ubuntu
Restart=always
RestartSec=1
ExecStart=/usr/local/bin/clash

[Install]
WantedBy=multi-user.target

然后开机自启:

sudo systemctl enable clash

然后启动服务:

sudo systemctl start clash

六、控制面板

GitHub 上有很多优秀的有关 Clash Dashboard 的项目,这些项目可以非常方便地帮助你查看、设置和管理你的 Clash。

从 GitHub 上克隆Clash Dashbaord到 Clash 的默认配置文件夹下。

cd ~/.config/clash
git clone https://github.com/Dreamacro/clash-dashboard.git
cd ~/.config/clash/clash-dashboard
git checkout -b gh-pages origin/gh-pages

下载完成后你需要对 Clash 的配置文件稍作修改,在 config.yaml 的头部添加或者修改以下两项:

external-ui: clash-dashboard
external-controller: 127.0.0.1:9090

然后在浏览器中输入http://127.0.0.1:9090/ui就可以看到 Clash 的控制面板了。

使用 Wireguard

一、安装 wireguard

sudo apt-get install wireguard -y

二、配置服务端

配置公钥和私钥

在服务器创建一对公钥和私钥:

wg genkey | tee private.key | wg pubkey > public.key

配置配置文件

进入配置文件:

sudo vim /etc/wireguard/wg0.conf

添加以下配置:

[Interface]
PrivateKey = your_private_key
Address = 10.0.0.1/32
ListenPort = 51820
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT && iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT && iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = client_public_key
AllowedIPs = 10.0.0.2/32

注意 💥

使用下面的命令查看你的默认网卡:

ip route list table main default

例如如果返回结果是:

default via 172.18.224.1 dev `enp4s0` proto dhcp src 172.18.224.100 metric 100

那么你需要将 eth0 改为enp4s0

三、配置客户端

配置公钥和私钥

在客户端创建一对公钥和私钥:

wg genkey | tee private.key | wg pubkey > public.key

配置配置文件

进入配置文件:

sudo vim /etc/wireguard/wg0.conf

添加以下配置:

[Interface]
PrivateKey = client_private_key
Address = 10.0.0.2/32
DNS = 114.114.114.114, 223.5.5.5

[Peer]
PublicKey = server_public_key
Endpoint = server_ip:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

四、向服务器添加客户端的公钥

获得客户端的公钥:

cat publickey

添加到客户端当中:

sudo wg set wg0 peer client_public_key allowed-ips 10.0.0.2

你也可以直接在服务端的配置文件中添加Peer

五、防火墙设置

允许端口转发

进入配置文件:

sudo vim /etc/sysctl.conf

取消注释以下内容:

net.ipv4.ip_forward=1

重启或者输入以下命令生效端口转发:

sudo sysctl -p

打开防火墙

输入以下命令查看防火墙是否启动:

sudo ufw status

如果防火墙已经启动,你可以输入以下命令开启防火墙:

ufw allow 51820/udp

注意 💥

如果你的服务器是在 VPS 上搭建的,那么你需要在你的服务商后台面板开启相应的51820的UDP端口

六、启动服务

在服务端和客户端都输入以下命令:

wg-quick up wg0

在客户端输入以下命令发送流量:

ping 10.0.0.1

然后在服务端输入以下命令查看流量:

sudo tcpdump -envi wg0

七、设置开机自启

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
systemctl status wg-quick@wg0
sudo systemctl stop wg-quick@wg0
sudo systemctl disable wg-quick@wg0

八、参考视频

使用 Oh-my-posh

官方文档 📝

oh-my-posh

一、安装字体

首先你需要安装一个Nerd 字体才能正常显示 oh-my-posh,推荐安装Hack 字体

树莓派需要先安装一个 font-manager,然后选择需要安装的字体就好了。

sudo apt install font-manager

二、安装 oh-my-posh

首先前往oh-my-posh 官方地址下载对应的版本,如果是 64 位机器就下载posh-linux-amd64

sudo wget https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/posh-linux-amd64 -O /usr/local/bin/oh-my-posh
sudo chmod +x /usr/local/bin/oh-my-posh

安装主题:

mkdir ~/.poshthemes
wget https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/themes.zip -O ~/.poshthemes/themes.zip
unzip ~/.poshthemes/themes.zip -d ~/.poshthemes
sudo chmod u+rw ~/.poshthemes/*.omp.*
rm ~/.poshthemes/themes.zip

三、配置终端

进入配置文件:

sudo vim ~/.bashrc

在最后添加以下内容:

eval "$(oh-my-posh --init --shell sh --config /home/cael/.poshthemes/amro.omp.json)"

如果是 powershell,应该进入$PROFILE,然后添加以下内容:

oh-my-posh --init --shell pwsh --config /home/cael/.poshthemes/amro.omp.json | Invoke-Expression

最后重新启动终端就可以正常使用了。

使用 Transmission

本教程介绍如何在 Ubuntu 系统上安装和使用 Transmission 客户端。

一、安装 Transmission

更新源:

sudo apt update

使用下面的命令安装 Transmission:

sudo apt install transmission-daemon -y

二、配置 Transmission

修改配置前我们需要先停止 Transmission 服务:

sudo systemctl stop transmission-daemon

然后打开配置文件:

sudo vim /etc/transmission-daemon/settings.json

我们可以修改下面几个配置:

  • rpc-username:用户名
  • rpc-password:密码,当 Transmission 重新启动时会将其加密
  • rpc-whitelist-enabled:是否启用白名单,我建议直接关闭

修改缓存大小:

sudo vim /etc/sysctl.conf

在文件末尾添加:

net.core.rmem_max = 16777216
net.core.wmem_max = 4194304

然后重新启动 Transmission 服务:

sudo systemctl start transmission-daemon

三、使用 Transmission

默认 Transmission 的 Web 界面端口是 9091,我们可以通过浏览器访问 http://localhost:9091 来使用。

使用 GitHub Actions

一、基本模板

新建配置文件:

vim .github/workflows/demo.yml

然后添加以下内容:

name: build
on:
  push:
    branches:
      - main
  pull_request:

jobs:
  Check-Python-Version:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout current branch
        uses: actions/checkout@v3

      - name: Setup python
        uses: actions/setup-python@v4
        with:
          python-version: 3.9

      - name: Check python version
        run: python --version

  Check-Windows-Powershell-Version:
    runs-on: windows-latest
    steps:
      - name: Check-Windows-Powershell-Version
        shell: powershell
        run: echo $PSVersionTable

Github Action 状态 API:

https://github.com/mr-addict/notes/actions/workflows/gh-pages.yml/badge.svg?branch=main

二、部署模板

mdbook 模板

name: pages

on:
  push:
    branches:
      - main
  pull_request:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
    steps:
      - name: checkout current branch
        uses: actions/checkout@v3
      - name: setup mdBook
        uses: peaceiris/actions-mdbook@v1
        with:
          mdbook-version: "latest"
      - name: build book
        run: mdbook build
      - name: push to gh-pages
        uses: peaceiris/actions-gh-pages@v3
        if: ${{ github.ref == 'refs/heads/main' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./book

hexo 模板

name: build

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  Deploy-Github-Pages:
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout current branch
        uses: actions/checkout@v2

      - name: Setup nodejs
        uses: actions/setup-node@v3
        with:
          node-version: "16"

      - name: Cache npm dependencies
        uses: actions/cache@v3.0.4
        with:
          path: node_modules
          key: ${{ runner.OS }}-npm-cache
          restore-keys: ${{ runner.OS }}-npm-cache

      - name: Install npm dependencies
        run: npm install

      - name: Build project
        run: npm run build

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

docker 容器模板

name: docker

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v3
        with:
          push: true
          tags: mraddict063/punch:latest

三、创建个人 Actions-Runner

部署 Runner

可以参照 Github,这边跳过。

运行 Runner:

./run.sh

将 Actions Runner 注册为开机自启任务

注册任务:

sudo ./svc.sh install

启动任务:

sudo ./svc.sh start

查看状态:

sudo ./svc.sh status

停止任务:

sudo ./svc.sh stop

注销任务:

sudo ./svc.sh uninstall

搭建 MC 服务器

配置 Dcocker 容器:

version: "3"
services:
  minecraft:
    tty: true
    stdin_open: true
    image: itzg/minecraft-server
    restart: unless-stopped
    ports:
      - 25565:25565
    environment:
      EULA: "TRUE"
      MAX_PLAYERS: 10
      DIFFICULTY: "hard"
      ONLINE_MODE: "false"
      MOTD: "Welcome to Stas MC Server!"
    volumes:
      - ./data:/data

启动容器:

docker-compose up -d

搭建 MQTT 服务器

一、配置 Docker 容器

version: "3"
services:
  mosquitto:
    image: eclipse-mosquitto
    restart: unless-stopped
    volumes:
      - ./data/config:/mosquitto/config
      - ./data/log:/mosquitto/log
    ports:
      - 1883:1883

二、添加配置文件

注意,先不要启动 docker 容器,在当前文件夹下创建映射的文件夹:

mkdir -p data/config

然后添加配置文件:

sudo vim mosquitto.conf

然后添加以下内容:

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883

#allow_anonymous false
#password_file /mosquitto/config/password.txt

然后启动 Docker 容器:

docker-compose up -d

三、添加用户

进入正在运行的容器:

docker exec -it mosquitto sh

创建一个用户:

mosquitto_passwd -c /mosquitto/config/password.txt cael

退出 Docker 容器:

exit

修改配置文件,将配置文件的最后两行取消注释:

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883

allow_anonymous false
password_file /mosquitto/config/password.txt

最后重启容器:

docker-compose restart

使用 Drone CI 服务器

Drone CI 是一个基于 go 的 CI 工具,配合 Github 或者 Gitlab 等可以实现方便的持续部署。

一、配置 Docker 容器

部署 Server

version: "3"
services:
  drone-server:
    image: drone/drone
    restart: unless-stopped
    ports:
      - 8000:80
    environment:
      - TZ=Asia/Shanghai
      - DRONE_CRON_INTERVAL=1m
      - DRONE_SERVER_PROTO=https
      - DRONE_SERVER_HOST=drone.mraddict.top

      - DRONE_USER_FILTER=MR-Addict
      - DRONE_USER_CREATE=username:MR-Addict,admin:true

      - DRONE_RPC_SECRET=e0c4fab16337ae0c7faa3706379ccac9
      - DRONE_GITHUB_CLIENT_ID=github_client_id
      - DRONE_GITHUB_CLIENT_SECRET=github_client_secret
    volumes:
      - ./data:/data

启动容器:

docker-compose up -d

部署 Runner

1. Docker Runner

version: "3"
services:
  drone-runner-docker:
    image: drone/drone-runner-docker
    restart: unless-stopped
    environment:
      - DRONE_RPC_PROTO=https
      - DRONE_RPC_HOST=drone.mraddict.top
      - DRONE_RPC_SECRET=e0c4fab16337ae0c7faa3706379ccac9
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

启动容器:

docker-compose up -d

2. SSH Runner

version: "3"
services:
  drone-runner-ssh:
    image: drone/drone-runner-ssh
    restart: unless-stopped
    environment:
      - DRONE_RPC_PROTO=https
      - DRONE_RPC_HOST=drone.mraddict.top
      - DRONE_RPC_SECRET=e0c4fab16337ae0c7faa3706379ccac9

启动容器:

docker-compose up -d

3. Exec Runner

安装 runner:

curl -L https://github.com/drone-runners/drone-runner-exec/releases/latest/download/drone_runner_exec_linux_amd64.tar.gz | tar zx
sudo install -t /usr/local/bin drone-runner-exec

添加配置文件:

sudo vim /etc/drone-runner-exec/config

配置文件内容:

DRONE_RPC_PROTO=https
DRONE_RPC_HOST=drone.mraddict.top
DRONE_RPC_SECRET=e0c4fab16337ae0c7faa3706379ccac9

安装自启服务:

sudo drone-runner-exec service install --config="/home/ubuntu/projects/drone/client/config"

启动服务:

sudo drone-runner-exec service start

关闭服务:

sudo drone-runner-exec service stop

卸载自启服务:

sudo drone-runner-exec service uninstall

二、配置 Nginx 反向代理

server{
  listen 80;
  listen [::]:80;
  server_name drone.mraddict.top;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name drone.mraddict.top;

  ssl_certificate  /etc/nginx/certs/tencent/drone.mraddict.top/drone.mraddict.top.cert;
  ssl_certificate_key /etc/nginx/certs/tencent/drone.mraddict.top/drone.mraddict.top.key;

  location / {
    proxy_pass http://localhost:8000;
    proxy_buffering off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

三、Drone CI 样例

kind: pipeline
type: docker
name: default

clone:
  disable: true

steps:
  - name: ssh
    image: appleboy/drone-ssh
    settings:
      host:
        from_secret: ssh_host
      username:
        from_secret: ssh_username
      key:
        from_secret: ssh_key
      script:
        - cd /home/ubuntu/projects/punch
        - git pull
        - docker-compose down
        - docker rmi mraddict063/punch-next
        - docker build -t mraddict063/punch-next .
        - docker image prune -f --filter label=stage=builder
        - docker-compose up -d

trigger:
  branch:
    - main
  event:
    - push
    - cron

注意 💥

请谨慎允许 pull request 使用 CI,这样会容易暴露自己设置的 secret

四、如何使用 cron

用 drone 提供的 UI 设置定时任务只能设置几个基本的时段,非常不方便,更加灵活的方式是用直接调用 API。

下面是 curl 的示例,DRONE_TOKEN 可以在个人中心找到,把 USERREPO 换成你自己的项目:

curl -X POST https://drone.example.com/api/repos/USER/REPO/cron \
-H "Authorization: Bearer DRONE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"name": "default", "expr": "0 0 */10 * * *", "branch": "main" }'

注意 💥

  • 你需要修改时区保证时间的一致性,环境变量是 TZ=Asia/Shanghai
  • drone 默认的 cron 检查间隔是一小时,非常不准确,环境变量是 DRONE_CRON_INTERVAL=1m
  • drone 使用的 cron 表达式是 6 位的,包含秒,和常规 5 位的 linux 系统 cron 不太一样

搭建 VSCode 服务器

配置 Dcocker 容器:

version: "3"
services:
  ide:
    image: lscr.io/linuxserver/code-server:latest
    environment:
      - PUID=1538
      - PGID=1538
      - TZ=Asia/Shanghai
      - PASSWORD=password
      - SUDO_PASSWORD=password
      - DEFAULT_WORKSPACE=/config/workspace
    volumes:
      - ./config:/config
    ports:
      - 8443:8443
    restart: unless-stopped

  http:
    image: nginx:latest
    restart: unless-stopped
    ports:
      - 5555:80
    volumes:
      - ./config/workspace:/usr/share/nginx/html

启动容器:

docker-compose up -d

使用 Adguard 服务器

参考文档 📝:

释放服务器 53 端口

一、释放服务器 53 端口

查看端口是否开放:

sudo lsof -i :53

进入配置 DNS 文件:

sudo vim /etc/systemd/resolved.conf

添加默认 DNS 为 1.1.1.1,同时弃用 DNS 监听端口:

[Resolve]
DNS=1.1.1.1
DNSStubListener=no

创建链接:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

二、搭建 Adguard

配置 docker-compose:

version: "3"
services:
  adguard:
    image: adguard/adguardhome
    restart: unless-stopped
    ports:
      - 53:53/tcp
      - 53:53/udp
      - 5353:3000/tcp
    volumes:
      - ./data/work:/opt/adguardhome/work
      - ./data/conf:/opt/adguardhome/conf

启动 docker:

docker-compose up -d

三、配置 Adguard

1. DNS

国外常用 DNS:

1.1.1.1
8.8.8.8
8.26.56.26
199.85.126.10
208.67.222.222

国内常用 DNS:

223.5.5.5
119.29.29.29
180.76.76.76
114.114.114.114

2. 广告过滤黑名单

2.1 国内广告过滤黑名单

Anti-Ad 黑名单:

https://anti-ad.net/easylist.txt
https://anti-ad.net/adguard.txt
https://anti-ad.net/domains.txt
https://anti-ad.net/anti-ad-for-dnsmasq.conf

通用黑名单:

https://cdn.jsdelivr.net/gh/o0HalfLife0o/list@master/ad-pc.txt
https://raw.githubusercontent.com/o0HalfLife0o/list/master/ad-pc.txt
https://cdn.jsdelivr.net/gh/o0HalfLife0o/list@master/ad-mo.txt
https://raw.githubusercontent.com/o0HalfLife0o/list/master/ad-mo.txt
https://cdn.jsdelivr.net/gh/o0HalfLife0o/list@master/ad.txt
https://raw.githubusercontent.com/o0HalfLife0o/list/master/ad.txt
https://raw.githubusercontent.com/Goooler/1024_hosts/master/hosts
https://easylist-downloads.adblockplus.org/easylistchina.txt

2.2 国外广告过滤黑名单

Easylist 黑名单:

https://easylist.to/easylist/easylist.txt
https://easylist.to/easylist/easyprivacy.txt
https://secure.fanboy.co.nz/fanboy-cookiemonster.txt

通用黑名单:

https://raw.githubusercontent.com/hl2guide/All-in-One-Customized-Adblock-List/master/aio.txt
https://adaway.org/hosts.txt
https://v.firebog.net/hosts/AdguardDNS.txt
https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt

搭建 Mongodb 数据库

一、配置 Docker 容器

配置容器:

version: "3"

services:
  mongo:
    image: mongo
    restart: unless-stopped
    ports:
      - 27017:27017
    volumes:
      - ./data:/data/db
    environment:
      - MONGO_INITDB_ROOT_USERNAME=your_username
      - MONGO_INITDB_ROOT_PASSWORD=your_password

启动容器:

docker-compose up -d

二、如何使用

mongodb 的数据库地址一般如下:

mongodb://your_username:your_password@your_server_ip_or_domain:27017/

将对应内容的修改一下即可:

  • your_username
  • your_password
  • your_server_ip_or_domain

使用 Speedtest 服务器

Speedtest 是一个测量网络速度的工具,它可以帮助你测试你的网络连接速度。你可以使用 Speedtest 客户端来测试你的网络连接速度,也可以使用 Speedtest 服务器来测试你的网络连接速度。

本服务器主要用于测量本地的网络连接速度。

配置容器:

version: "3"
services:
  speedtest:
    restart: unless-stopped
    ports:
      - 3000:3000
    image: openspeedtest/latest

最后启动容器:

docker-compose up -d

使用 Pocketbase

1. 配置 Docker 服务器

配置容器:

version: "3"
services:
  pocketbase:
    image: ghcr.io/muchobien/pocketbase:latest
    restart: unless-stopped
    ports:
      - 8090:8090
    volumes:
      - ./data/db:/pb_data
      - ./data/public:/pb_public
    healthcheck:
      test: wget --no-verbose --tries=1 --spider http://localhost:8090/api/health || exit 1
      interval: 5s
      timeout: 5s
      retries: 5

启动容器:

docker-compose up -d

二、配置 Nginx 反向代理

server{
  listen 80;
  listen [::]:80;
  server_name pocketbase.mraddict.top;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name pocketbase.mraddict.top;

  ssl_certificate  /etc/nginx/certs/cloudflare/mraddict.top/mraddict.top.cert.pem;
  ssl_certificate_key /etc/nginx/certs/cloudflare/mraddict.top/mraddict.top.key.pem;

  location / {
    proxy_pass http://localhost:8090;

    proxy_redirect off;
    proxy_buffering off;
    proxy_max_temp_file_size 0;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 64;

    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header Connection "";
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

三、如何使用

打开类似如下链接即可:

搭建 Wireguard 服务器

配置 Docker 容器:

version: "3"
services:
  wg-easy:
    image: weejewel/wg-easy
    restart: unless-stopped
    volumes:
      - ./data:/etc/wireguard
    ports:
      - 51820:51820/udp
      - 51821:51821/tcp
    environment:
      - WG_HOST=[change-this]
      - PASSWORD=[change-this]
      - WG_DEFAULT_DNS=1.1.1.1
      - WG_MTU=1420
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1

启动容器:

docker-compose up -d

搭建 NextCloud 服务器

一、配置 Docker 容器

version: "3"

services:
  nextcloud:
    image: nextcloud:latest
    restart: unless-stopped
    ports:
      - 8080:80
    environment:
      - MYSQL_HOST=mysql
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud
    volumes:
      - ./data:/var/www/html

  mysql:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=nextcloud
      - MYSQL_ROOT_PASSWORD=nextcloud
    volumes:
      - ./db:/var/lib/mysql

启动容器:

docker-compose up -d

二、修改配置文件

sudo vim data/config/config.php

在 secret 下添加信任域名trusted_domains

<?php
$CONFIG = array (
  # some config
  'secret' => '......................',
  'trusted_domains' =>
  array (
    0 => 'cloud.mraddict.one'
    1 => 'localhost',
  ),
  # some other config
);

最后重启容器:

docker-compose restart

三、配置 Nginx

如果你是使用 Nginx 的反向代理,下面是参考配置:

server{
  listen 80;
  server_name cloud.mraddict.top;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name cloud.mraddict.one;

  client_max_body_size 0;
  underscores_in_headers on;

  ssl_certificate  /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.cert.pem;
  ssl_certificate_key /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.key.pem;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 64;
    proxy_buffering off;
    proxy_redirect off;
    proxy_max_temp_file_size 0;
    add_header Strict-Transport-Security "max-age=15552000; includeSubdomains;";
    add_header Front-End-Https on;
    proxy_pass http://localhost:8080;
  }

  location /.well-known/carddav {
    return 301 $scheme://$host/remote.php/dav;
  }

  location /.well-known/caldav {
    return 301 $scheme://$host/remote.php/dav;
  }
}

搭建 Home Assistant 服务器

一、配置 Docker 容器

使用以下docker-compose.yaml

version: "3"
services:
  home:
    image: ghcr.io/home-assistant/home-assistant:stable
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./config:/config
    ports:
      - 8123:8123
    restart: unless-stopped

启动容器:

docker-compose up -d

二、修改配置文件

使用以下命令查看 Gateway:

docker network inspect home_default|grep '"Gateway": '|awk -F"\"" '{print $4}'

然后进入配置文件:

vim config/configuration.yaml

在末尾添加以下内容,注意将trusted_proxies修改为查询的网关:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.24.0.1

最后重启容器:

docker-compose restart

三、配置 Nginx 反向代理

server{
  listen 80;
  listen [::]:80;
  server_name home.mraddict.one;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name home.mraddict.one;

  ssl_certificate  /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.cert.pem;
  ssl_certificate_key /etc/nginx/certs/cloudflare/mraddict.one/mraddict.one.key.pem;

  location / {
    proxy_pass http://localhost:8123;
    proxy_buffering off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

Wlan 操作

显示所有WiFi接口:

netsh wlan show interfaces

查看WiFi信息:

netsh wlan show profiles

连接WiFi网络:

netsh wlan connect name=WiFiname [ssid=WiFiName]

断开网络连接:

netsh wlan disconnect

更新网络WiFi信息:

netsh wlan set profileparameter name=[WiFiName] connectionmode=manual[auto]
```<style>
  .scroll-to-top {
    font-size: 2.5rem;
    width: 3.2rem;
    height: 3.2rem;
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    padding: 0.75rem;
    bottom: 4rem;
    right: calc(1.25rem + 90px + var(--page-padding));
    z-index: 999;
    cursor: pointer;
    border: none;
    color: var(--bg);
    background: var(--fg);
    border-radius: 50%;
  }
  .scroll-to-top.hidden {
    display: none;
  }
  .scroll-to-top i {
    transform: translateY(-2px);
  }
  @media (min-width: 1080px) {
    .scroll-to-top {
      display: flex;
    }
  }
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
  <i class="fa fa-angle-up"></i>
</button>
<script>
  const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
  window.addEventListener("scroll", () => {
    const button = document.querySelector(".scroll-to-top");
    button.classList.toggle("hidden", window.scrollY < 200);
  });
</script>

PowerShell 基础

获取命令帮助:

Get-Help Select-Object

查找命令:

Get-command *printer*

清空终端输出:

  • clear
  • cls
  • Ctrl + L

查看命令的别名原始内容:

Get-Alias gal

终端输出:

Write-Host "Hello world"
echo "Hello world"

格式化输出:

Get-ChildItem | Format-Wide
Get-ChildItem | Format-List *

控制输出:

Get-ChildItem | Out-String
Get-ChildItem | Out-Default
Get-ChildItem | Out-Null
Get-ChildItem | Out-File

处理元素:

Remove-Item
Copy-Item
Get-Content
New-Item
Move-Item

获取PW执行权限:

Get-ExecutionPolicy --list
Set-Executionpolicy RemoteSigned
```<style>
  .scroll-to-top {
    font-size: 2.5rem;
    width: 3.2rem;
    height: 3.2rem;
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    padding: 0.75rem;
    bottom: 4rem;
    right: calc(1.25rem + 90px + var(--page-padding));
    z-index: 999;
    cursor: pointer;
    border: none;
    color: var(--bg);
    background: var(--fg);
    border-radius: 50%;
  }
  .scroll-to-top.hidden {
    display: none;
  }
  .scroll-to-top i {
    transform: translateY(-2px);
  }
  @media (min-width: 1080px) {
    .scroll-to-top {
      display: flex;
    }
  }
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
  <i class="fa fa-angle-up"></i>
</button>
<script>
  const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
  window.addEventListener("scroll", () => {
    const button = document.querySelector(".scroll-to-top");
    button.classList.toggle("hidden", window.scrollY < 200);
  });
</script>

Powershell 变量和PSDrive

一、变量

创建变量:

$true
$false
$null
$Hello="Hello World"
$Hello.Length
$Hello | Get-Member
$Hello.GetType()

查看变量的类型:

Get-TypeData *IP*

定义变量类型:

[IPAddress]"192.168.4.1"
$myIP = [IPAddress]"192.168.4.1"

二、PSDrive

PSDrive:

Get-PSDrive

操作PSDrive:

cd Variable:
cd Env:
echo $Env:Windir
cd C:

HELLO WORLD

一、示例

USE sql_store;

SELECT *
FROM customers
-- WHERE customer_id = 1
ORDER BY first_name

二、知识点

  • USE使用 DB
  • SELECT选择 Column
  • FROM选择 Table
  • WHERE筛选
  • ORDER BY排序
  • --注释

SELECT

一、示例

USE sql_store;

SELECT
	first_name,
	last_name,
	points,
    (points + 10) * 10 AS "discount factor"
FROM customers
ORDER BY points

二、知识点

  • SELECT 可以有多个参数筛选列
  • SELECT 可以换行
  • SELECT 可以使用别名AS
  • SELECT 可以使用四则运算和括号产生新的列

WHERE

一、示例

USE sql_store;

SELECT *
FROM customers
-- WHERE points > 3000
-- WHERE state = 'VA'
-- WHERE state != 'VA'
WHERE birth_date > '1990-01-01'

二、知识点

  • WHERE 可以使用逻辑运算符
  • SQL 的时间格式是YYYY-MM-DD HH-MM-SS

AND-OR-NOT

一、示例

USE sql_store;

SELECT *
FROM customers
-- WHERE points > 3000 AND birth_date > '1990-01-01'
-- WHERE points > 3000 OR birth_date > '1990-01-01'
-- WHERE birth_date > '1990-01-01' OR (points > 1000 AND state = 'VA')
WHERE NOT (birth_date > '1990-01-01' OR points > 1000)

二、知识点

  • 逻辑运算符 AND 优先级更高
  • 逻辑运算符可以通过括号改变运算顺序

Bash 初识

查看系统支持的shell:

cat /etc/shells

查看当前使用的shell:

which bash

用户输入

例子:

echo -n "Input your favourite fruit:"
read fruit
echo "Your favourite fruit is $fruit"

将读取到的内容放在变量中:

read -p "Input your name:" name
echo "Your name is $name"

-s 参数用于隐藏输入:

read -s -p "Input your passwrod:" password
echo "Your password is $password"

-a 参数用于将输入保存到数组中:

echo -n "Input your hobbies:"
read -a hobbies
echo "Your hoddies are $hobbies"

在不指定变量的情况下,read 会将输入保存到 REPLY 变量中:

read -p "Input your age:"
echo "Your age is $REPLY"
```<style>
  .scroll-to-top {
    font-size: 2.5rem;
    width: 3.2rem;
    height: 3.2rem;
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    padding: 0.75rem;
    bottom: 4rem;
    right: calc(1.25rem + 90px + var(--page-padding));
    z-index: 999;
    cursor: pointer;
    border: none;
    color: var(--bg);
    background: var(--fg);
    border-radius: 50%;
  }
  .scroll-to-top.hidden {
    display: none;
  }
  .scroll-to-top i {
    transform: translateY(-2px);
  }
  @media (min-width: 1080px) {
    .scroll-to-top {
      display: flex;
    }
  }
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
  <i class="fa fa-angle-up"></i>
</button>
<script>
  const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
  window.addEventListener("scroll", () => {
    const button = document.querySelector(".scroll-to-top");
    button.classList.toggle("hidden", window.scrollY < 200);
  });
</script>

变量和注释

Comments are lines that exist in computer programs that are ignored by compilers and interpreters.

# This is a comment

When you reference a variable in bash it is important not to put spaces around the equals sign.

# User variable
name="Cael"
echo "My name is $name"
echo "My name is ${name}_bank"

System variables are mostly in Capitals.

# System variable
echo Our shell name is $BASH
echo Our shell version is $BASH_VERSION
echo Our home directory is $HOME
echo Our current directory is $PWD

if 操作符

[] 用于条件判断,() 用于数学运算:

num=10

if [ $num -eq 10 ]
then
    echo "$num equals to 10"
else
    echo "$num not equals to 10"
fi

if [ $num == 10 ]
then
    echo "$num equals to 10"
else
    echo "$num not euqals to 10"
fi

**(())用于数学运算和条件判断,[[]]**用于字符串比较:

num=9
if [[ $num == 10 ]]
then
    echo "$num equals to 10"
else
    echo "$num not equals to 10"
fi

if (( $num >= 10 ))
then
    echo "$num is not smaller than 10"
else
    echo "$num is smaller than 10"
fi

elif 用于多条件判断,也可以用于嵌套的条件判断:

num=8
if [[ $num = 10 ]]
then
    echo "$num equals to 10"
elif [[ $num < 10 ]]
then
    echo "$num less than 10"
else
    echo "$num bigger than 10"
fi

cat 命令

cat 命令用于连接文件并打印到标准输出设备上:

echo "Hello world" > hello.txt
read -p "Enter your current emotions:"
echo $REPLY >> hello.txt
cat -e hello.txt # put $ at ther end of line

从标准输入读取内容并写入文件:

echo -n "Enter current season, press CTR+D to finish input:"
cat > hello.txt
cat -e hello.txt # put $ at ther end of line

将两个文件合并到一个文件:

cat file1.txt file2.txt >> file3.txt
```<style>
  .scroll-to-top {
    font-size: 2.5rem;
    width: 3.2rem;
    height: 3.2rem;
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    padding: 0.75rem;
    bottom: 4rem;
    right: calc(1.25rem + 90px + var(--page-padding));
    z-index: 999;
    cursor: pointer;
    border: none;
    color: var(--bg);
    background: var(--fg);
    border-radius: 50%;
  }
  .scroll-to-top.hidden {
    display: none;
  }
  .scroll-to-top i {
    transform: translateY(-2px);
  }
  @media (min-width: 1080px) {
    .scroll-to-top {
      display: flex;
    }
  }
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
  <i class="fa fa-angle-up"></i>
</button>
<script>
  const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
  window.addEventListener("scroll", () => {
    const button = document.querySelector(".scroll-to-top");
    button.classList.toggle("hidden", window.scrollY < 200);
  });
</script>

rm 命令

删除文件:

rm [file]

删除文件夹:

# remove empty directory
rmdir [dir_name]
# remove non-empty directory
rm -f [dir_name]

编辑当前的环境变量:

vim ~/.profile

编辑系统的环境变量:

vim ../etc/environment
```<style>
  .scroll-to-top {
    font-size: 2.5rem;
    width: 3.2rem;
    height: 3.2rem;
    display: none;
    align-items: center;
    justify-content: center;
    position: fixed;
    padding: 0.75rem;
    bottom: 4rem;
    right: calc(1.25rem + 90px + var(--page-padding));
    z-index: 999;
    cursor: pointer;
    border: none;
    color: var(--bg);
    background: var(--fg);
    border-radius: 50%;
  }
  .scroll-to-top.hidden {
    display: none;
  }
  .scroll-to-top i {
    transform: translateY(-2px);
  }
  @media (min-width: 1080px) {
    .scroll-to-top {
      display: flex;
    }
  }
</style>
<button type="button" aria-label="scroll-to-top" class="scroll-to-top hidden" onclick="scrollToTop()">
  <i class="fa fa-angle-up"></i>
</button>
<script>
  const scrollToTop = () => window.scroll({ top: 0, behavior: "smooth" });
  window.addEventListener("scroll", () => {
    const button = document.querySelector(".scroll-to-top");
    button.classList.toggle("hidden", window.scrollY < 200);
  });
</script>

执行参数

$0 是脚本的名字,$1 是第一个参数,$2 是第二个参数,以此类推:

echo $0 $1 $2

$@ 是所有参数的列表:

echo $@

$# 是参数的个数:

echo $#

文件检测

检测文件是否存在:

echo -e "Enter the name of the file: \c"
read file_name

if [ -f $file_name ]
then
    echo "$file_name exists"
else
    echo "$file_name not exists"
fi

检测目录是否存在:

read -p "Enter a directory name:" dir_name

if [ -d $dir_name ]
then
    echo "Directory exists"
else
    echo "Directory not exists"
fi

检测文件是否为空:

read -p "Entry the name of an existing file:" file_name
if [ -s $file_name ]
then
    echo "File is not empty"
else
    echo "File is empty"
fi

检测文件是否可执行:

read -p "Entry the name of an existing file:" file_name
if [ -x $file_name ]
then
    echo "$file_name is executable"
else
    echo "$file_name is not executable"
fi

Hello world

示例

print 输出:

print("Hello world")

标准输出:

io.write("Size of string ", #"String", ".\n")

变量

一、数字型 Number

Lua 数值的最大值:

print(9223372036854775807 + 1)

Lua 数值的精度为 13 位:

print(1.9999999999999 + 0.00000000000001)

二、布尔型 Boolean

isLogin = true
print(type(isLogin))

三、空型 Nil

print(type(madeupvar))

四、字符型 String

字符拼接:

age = 15
name = "cael"
print('Hello ' .. name .. ", you are're " .. age .. " now.")

多行字符:

longString = [[
This is a multi line string,
which you can print as many as lines you want.
]]
print(longString)

字符长度:

local quote = "I changed my password everywhere to 'incorrect.' That way when I forget it,it always reminds me, 'Your password is incorrect.'"
io.write("Quote Length : ", string.len(quote), "\n")

字符替换:

local quote = "I changed my password everywhere to 'incorrect.' That way when I forget it,it always reminds me, 'Your password is incorrect.'"
io.write("Replace I with me : ", string.gsub(quote, "I", "me"), "\n")

查找字符:

local quote = "I changed my password everywhere to 'incorrect.' That way when I forget it,it always reminds me, 'Your password is incorrect.'"
io.write("Index of password : ", string.find(quote, "password"), "\n")

字符大写或小写:

local quote = "I changed my password everywhere to 'incorrect.' That way when I forget it,it always reminds me, 'Your password is incorrect.'"
io.write("Quote Upper : ", string.upper(quote), "\n")
io.write("Quote Lower : ", string.lower(quote), "\n")

运算符

一、四则运算符

io.write("5 + 3 = ", 5 + 3, "\n")
io.write("5 - 3 = ", 5 - 3, "\n")
io.write("5 * 3 = ", 5 * 3, "\n")
io.write("5 / 3 = ", 5 / 3, "\n")
io.write("5.2 % 3 = ", 5 % 3, "\n")

二、关系运算符

local age = 13
if age < 16 then
  io.write("You can go to school", "\n")
elseif (age >= 16) and (age < 18) then
  io.write("You can drive", "\n")
else
  io.write("You can vote", "\n")
end

三、逻辑运算符

或运算符:

local age = 13
if (age < 14) or (age > 67) then io.write("You shouldn't work\n") end

且运算符:

local canVote = age > 18 and true or false
io.write("Can I Vote : ", tostring(canVote), "\n")

循环

一、while 循环

local i = 1
while (i <= 10) do
  io.write(i)
  i = i + 1
  if i == 8 then break end
end

二、repeat 循环

repeat
  io.write("Enter your guess : ")
  local guess = io.read()
until tonumber(guess) == 15

三、for 循环

简单循环:

for i = 1, 10, 1 do
  io.write(i)
end
print()

遍历循环:

local months = {
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December"
}
for key, value in pairs(months) do
  io.write(key, ":", value, "\n")
end

函数

一、基本用法

local function getSum(num1, num2)
  return num1 + num2
end
print(string.format("5 + 2 = %d", getSum(5, 2)))

二、多个返回值

local function splitStr(theString)

  local stringTable = {}
  local i = 1
  for str in string.gmatch(theString, "[^%s]+") do
    stringTable[i] = str
    i = i + 1
  end
  return stringTable, i
end

local splitStrTable, numOfStr = splitStr("The Turtle")
for j = 1, numOfStr do
  print(string.format("%d : %s", j, splitStrTable[j]))
end

三、参数数目未知

local function getSumMore(...)
  local sum = 0
  for key, value in pairs { ... } do
    sum = sum + value
  end
  return sum
end

io.write("Sum : ", getSumMore(1, 2, 3, 4, 5, 6), "\n")

四、函数变量

local doubleIt = function(x) return x * 2 end
print(doubleIt(4))

五、函数闭包

local function outerFunc()
  local i = 0
  return function()
    i = i + 1
    return i
  end
end

local getI = outerFunc()
print(getI())
print(getI())

Math

一、常用函数

示例:

io.write("floor(2.345) : ", math.floor(2.345), "\n")
io.write("ceil(2.345) : ", math.ceil(2.345), "\n")
io.write("max(2, 3) : ", math.max(2, 3), "\n")
io.write("min(2, 3) : ", math.min(2, 3), "\n")
io.write("sqrt(64) : ", math.sqrt(64), "\n")

输出:

floor(2.345) : 2
ceil(2.345) : 3
max(2, 3) : 3
min(2, 3) : 2
sqrt(64) : 8

二、Random 函数

随机生成 0-1 的随机数:

io.write("math.random() : ", math.random(), "\n")

随机生成 1-10 的随机数:

io.write("math.random(10) : ", math.random(10), "\n")

浮点数格式化:

print(string.format("Pi = %.5f", math.pi))

Table

一、基础用法

通过索引获取 Table,下标从 1 开始:

local aTable = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
print(aTable[1])

将 Table 转换为字符:

local aTable = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
print(table.concat(aTable, ", "))

去除 Table 的某个元素:

local aTable = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
print(table.concat(aTable, ", "))
table.remove(aTable, 1)
print(table.concat(aTable, ", "))

在 Table 中插入某个元素:


local aTable = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
print(table.concat(aTable, ", "))
table.insert(aTable, 1)
print(table.concat(aTable, ", "))

给 table 排序:

local aTable = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
print(table.concat(aTable, ", "))
table.sort(aTable, function(a, b) return a > b end)
print(table.concat(aTable, ", "))

二、二维 Table

local aMultiTable = {}
for i = 0, 9 do
  aMultiTable[i] = {}
  for j = 0, 9 do
    aMultiTable[i][j] = tostring(i) .. tostring(j)
  end
end
for i = 0, 9 do
  for j = 0, 9 do
    io.write(aMultiTable[i][j], " , ")
  end
  print()
end

Class

一、Class 基础

Animal = { height = 0, weight = 0, name = "No Name", sound = "No Sound" }
function Animal:new(height, weight, name, sound)
  setmetatable({}, Animal)
  self.height = height
  self.weight = weight
  self.name = name
  self.sound = sound
  return self
end

function Animal:toString()
  local animalStr = string.format("%s weighs %.1f lbs, is %.1f in tall and says %s",
    self.name, self.weight, self.height, self.sound)
  return animalStr
end

local spot = Animal:new(10, 15, "Spot", "Roof")
print(spot:toString())

二、Class 继承

Animal = { height = 0, weight = 0, name = "No Name", sound = "No Sound" }
function Animal:new(height, weight, name, sound)
  setmetatable({}, Animal)
  self.height = height
  self.weight = weight
  self.name = name
  self.sound = sound
  return self
end

function Animal:toString()
  local animalStr = string.format("%s weighs %.1f lbs, is %.1f in tall and says %s",
    self.name, self.weight, self.height, self.sound)
  return animalStr
end

local spot = Animal:new(10, 15, "Spot", "Roof")
print(spot:toString())

Cat = Animal:new()
function Cat:new(height, weight, name, sound, favFood)
  setmetatable({}, Cat)
  self.height = height
  self.weight = weight
  self.name = name
  self.sound = sound
  self.favFood = favFood
  return self
end

function Cat:toString()
  local catStr = string.format("%s weighs %.1f lbs, is %.1f in tall, says %s and loves %s",
    self.name, self.weight, self.height, self.sound, self.favFood)
  return catStr
end

local fluffy = Cat:new(10, 15, "Fluffy", "Meow", "Tuna")
print(fluffy:toString())

Hello world

一、安装 typescript

npm install -g typescript

二、配置 ts 解释器

生成配置文件:

tsc --init

替换以下配置内容:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "rootDir": "./src",
    "outDir": "./dist",
    "removeComments": true,
    "noEmitOnError": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true
  }
}

三、Hello-world

新建src/hello.ts,并替换以下内容:

let message: string = "Hello world!";
console.log(message);

编译文件:

tsc

Types

一、Built-In Types

内置的一些数据类型,包括数字型,字符型,布尔型和任意型:

let sales: number = 123_456_789;
let course: string = "Typescript";
let is_published: boolean = true;
let level: any;
level = 1;
level = "One";

二、Array

数组:

let numbers: number[] = [1, 2, 3];
numbers.forEach((item) => console.log(item.toString()));

三、Tuples

用于自定义一个数组,具有给定的数据类型:

let user: [number, string] = [1, "Cael"];
user.forEach((item) => console.log(item));

四、Enum

Enum 用于将相关联的变量组合成一个数据自定义的类型:

const enum Size {
  Small = 1,
  Medium,
  Large,
}
let mySize: Size = Size.Medium;
console.log(mySize);

Function

一、示例

function calculateTax(income: number, taxYear: number = 2022): number {
  if (taxYear < 2024) return income * 1.05;
  return income;
}
console.log(calculateTax(10_000, 2022));

二、知识点

  • 函数需要返回值
  • 函数参数可以指定类型
  • 函数参数可设置默认值

Object

一、示例

let employee: {
  readonly id: number;
  name: string;
  retire: (date: Date) => void;
} = {
  id: 1,
  name: "cael",
  retire: (date: Date) => {
    console.log(date);
  },
};

employee.retire(new Date());

二、知识点

  • 对象的参数可以使用 readonly 设置为默认
  • 对象可以传入函数

Type Aliases

一、示例

type Employee = {
  readonly id: number;
  name: string;
  retire: (date: Date) => void;
};

let employee: Employee = {
  id: 1,
  name: "cael",
  retire: (date: Date) => {
    console.log(date);
  },
};

employee.retire(new Date());

二、知识点

  • 使用 type 声明对象的别名

Union Type

一、示例

function KgToLbs(weight: number | string): number {
  if (typeof weight === "number") return weight * 2.2;
  else return parseInt(weight) * 2.2;
}
console.log(KgToLbs(20));

二、知识点

  • 使用 | 给变量两个范围
  • 使用 typeof 判断变量类型