速查指南

用户管理

group

# 查看用户groups
groups user_name

# 添加group
sudo usermod -aG newgroup username

user

# adduser添加用户
sudo adduser

# useradd添加用户
# -d 用户默认home目录
# -s 用户默认shell
sudo useradd -m -d /data/users/zhangsan zhangsan -s /bin/bash

# 修改密码
sudo passwd

# 修改所有和组
sudo chown -R <user_name>[:<user_group>] <file_path>

# 修改用户home目录
# -d (--home):指定用户的新家目录路径
# -m (--move):移动文件
sudo usermod -m -d /新的路径 用户名

pwgen

# 安装
sudo apt install pwgen

# - `-D '!#$%&()*+,-.=?@^_|/'`:指定允许的特殊字符。
# - `-N 3`:确保每个密码至少包含三种不同的字符类别(例如,大写字母、小写字母和数字)。
# - `-C 8,32`:设置密码长度在8到32个字符之间。
# - `12`:生成一个12个字符的密码。
pwgen -D '!#$%&()*+,-.=?@^_|/' -N 3 -C 8,32 12

ssh

# ~/.ssh/config
Host home-svc
    HostName svc.insvc.cn # 192.168.111.101
    User k
    ForwardAgent yes
    ForwardX11 yes
    ForwardX11Trusted yes
    IdentityFile ~/.ssh/volcengine-livepro-test

网络

查看局域网中IP使用情况

sudo apt install arp-scan
sudo arp-scan --interface=eno1 192.168.0.0/24

# `arp -n` 命令会列出系统当前的 ARP 缓存表,并显示 IP 地址与对应的 MAC 地址的映射关系。
arp -nl

代理配置

Github代理配置

# ~/.ssh/config
Host github.com
   HostName github.com
   User git
   # 走 HTTP 代理
   ProxyCommand socat - PROXY:192.168.0.52:%h:%p,proxyport=7890
   # 走socket5
   ProxyCommand nc -X 5 -x 192.168.0.52:7891 %h %p
# ~/.bashrc
function github_on() {
    cat "${HOME}/.ssh/config" >"${HOME}/.ssh/config_back" # 先备份
    config=$(cat ${HOME}/.ssh/config_back | sed 's/\# ProxyCommand/ProxyCommand/g')
    echo -e "${config}" >"${HOME}/.ssh/config" && echo -e "\033[36mGithub 已上代理!\033[0m"
}
function github_off() {
    cat "${HOME}/.ssh/config" >"${HOME}/.ssh/config_back" # 先备份
    config=$(cat ${HOME}/.ssh/config_back | sed 's/    ProxyCommand/    \# ProxyCommand/g')
    echo -e "${config}" >"${HOME}/.ssh/config" && echo -e "\033[33mGithub 停止代理!\033[0m"
}


# 测试代理是否通
ssh -T git@github.com

http代理

# NO_PROXY支持泛域名匹配,也就是你用.inner.com代表所有的二级域名都不经过代理,但是通配符.inner.com就没效果。
# 0.0.0.0/0表示所有ipv4直接访问不走代理
# ::/0表示所有ipv6直接访问不走代理
function proxy {
  export http_proxy=http://127.0.0.1:7890
  export https_proxy=http://127.0.0.1:7890
  export NO_PROXY=.insvc.cn,localhost,0.0.0.0/0,::/0
  # 实测发现,apt等需要no_proxy
  export no_proxy=.insvc.cn,localhost,0.0.0.0/0,::/0
  echo -e '\033[36mhttp 开启代理!\033[0m'
}
function unproxy {
  unset http_proxy;
  unset https_proxy;
  echo -e '\033[33mhttp 停止代理!\033[0m'
}

apt代理

# eg: 文件 /etc/apt/apt.conf.d/90curtin-aptproxy
Acquire::http::Proxy "http://192.168.0.52:7890";
Acquire::https::Proxy "http://192.168.0.52:7890";

远端使用本机代理

# 使用ssh的-R远程端口转发,将远端的某个端口数据转发给本地的某个端口,
# 可以用于共享本地的代理到远端

# 比如:我本地7890端口有个http代理服务器,我上到阿里云上,需要用代理,并且不想重新配置clash等软件,那么直接
ssh -R <remote_proxy_port>:127.0.0.0:7890 <remote_user>@<remote_host>

# 这样ssh过去之后,可以直接用http_proxy=http://localhost:<remote_proxy_port>代理了。

# 如果要长时间维持这个链接的话可以使用autossh
sudo apt-get install autossh
autossh -R 8888:127.0.0.1:7890 user@remote-server

docker代理

docker代理

clash配置

文件准备:

  • clash-linux:我是从https://storage.monocloud.co/client/Linux/Clash/Clash.for.Windows-0.20.39-x64-linux.tar.gz下载,然后翻出来的。
  • config.yml:从已有的clash客户端拷贝:
  • Country.mmdb:从下载clash-linux的地方找一下。 配置
# 首先将config.yml Country.mmdb文件传到 ~/.config/clash 中

# 直接运行./clash-linux即可
./clash-linux

网络

curl

# 下载到remove-url指定路径
curl -o <local-path> <remote-url>

# 指定dns解析
curl --resolve example.com:80:192.168.0.50 https://example.com

# 使用http代理
curl -x http://<host>:<port> <test_url>

# 使用sock5代理
curl -x socks5h://<host>:<port> <test_url>

# -s(--silent)表示静默输出,不显示进度条、错误信息或额外输出。
# -L(--location)表示跟随HTTP 3xx重定向,如果服务器返回了301 Moved Permanently或者302 Found等重定向相应,curl会自动跟随目标URL。
curl -sL google.com

# verbose: 启用详细模式,可以查看是否走了代理
curl -v google.com

# 指定请求类型
curl -X POST \
	-H "Content-Type: application/json" \
	-d '{"key1":"value1", "key2":123, "nested":{"a":"b"}}' \
	<test_url>

手动设置网络连接信息

# /etc/netplan/*.yaml
# This is the network config written by 'subiquity'
network:        
  ethernets: 
    eno1:       
		addresses:
				- 192.168.0.211/24
		gateway4: 192.168.0.1
		nameservers:                                                           
			addresses: [8.8.8.8, 8.8.4.4, 119.29.29.29]
  version: 2

# 新版本gateway4没掉了需要替换成
		routes:
			- to: default
			  via: 192.168.0.1

# 随后重载网络配置信息
sudo netplan apply

# 如何要是设置wifi的话:
network:
    ethernets:
        eno1:
            dhcp4: true
    version: 2
    wifis:
        wlp4s0:
            access-points:
                "K-Main":
                    hidden: true # 对于隐藏网络非常重要
                    password: yourpassword
            dhcp4: false
            addresses:
              - 192.168.111.222/24
            routes:
              - to: default
                via: 192.168.111.1
            nameservers:
              addresses: [192.168.111.1, 8.8.8.8, 8.8.4.4, 119.29.29.29]

查看IP

# 通常使用
ifconfig
# 或者新的指令, apt install iproute2
ip addr show

# 获取网关
ip route show default

手动释放IP/ 重新获取DHCP IP

# 手动释放当前获取的IP,无论是静态设置还是动态设置
# eth0是指网络端口,根据实际情况而定。
sudo ip addr flush dev eth0

# 释放当前DHCP租约。
sudo dhclient -r 

# 尝试获取新的DHCP租约。
sudo dhclient

flush DNS

sudo systemd-resolve --flush-caches

断点续传

sudo apt install aria2
aria2c url-to-your-things

网络测速

# 网络速度查看
iftop

远程连接

# 安装 remmina 随后执行就可以了
sudo apt install remmina remmina-plugin-rdp -y

查看自己的外部IP

curl ifconfig.me

DNS相关的配置

/etc/resolv.conf # dns配置
/etc/network # 网络interface配置,新版都是通过netplan管理网络连接的
/etc/netplan

# ubuntu24.04如果要配置dns 服务器的话
# 首先修改/etc/systemd/resolved.conf 主要是以下三项
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=1.1.1.1 1.0.0.1
Domains=~.

# 随后重启systemd-resolved服务
sudo systemctl restart systemd-resolved

# 测试
nslookup <域名>

# 如果想要强制设置某个域名通过特定DNS服务器解析
[Resolve]
DNS=192.168.111.1
Domains=gms.kaihang.net

查看端口

# ss相当于netstat,但是执行更快
# -t: 显示TCP链接
# -u: 显示UDP链接
# -l: 显示监听中的服务
# -n: 不进行DNS解析,直接显示IP和Port
# -p: 进程相关信息
ss -tulnp | grep :54112

# 还可以直接grep进程名
ss -tulnp | grep tinyproxy

# 查看端口是否可以访问
nc 127.0.0.1 6443 -v

ip指令

# 查看所有接口的地址
ip addr

# 查看路由表
ip route show

# 查看网络接口(网卡)
ip link show

# 查看arp缓存
ip neigh show

# 给网卡添加IP
ip addr add 192.168.0.50/32 dev eno1

traceroute

# 查看路由路径
traceroute <ip>

tcpdump

网络接口数据包capture:

# 仅捕获host是192.168.0.50的arp包
sudo tcpdump -i eno1 arp and host 192.168.0.50

自签名证书

安装自签名

# 安装软件
sudo apt install ca-certificates

# 将自签名证书放到目录下
sudo cp ca.crt /usr/local/share/ca-certificates/

# 将自签名证书添加CA证书列表
sudo update-ca-certificates

文件系统

文件权限

命令ls -l(我常用的是ls -alh)查看当前文件夹下的文件信息:

drwxr-xr-x 2 user group 4096 Sep 12 10:00 my_directory
-rw-r--r-- 1 user group 1234 Sep 12 09:30 my_file.txt

drwxr-xr-x为例子,逐个解释:

  • 第一个字符表示文件类型。
    • d:表示文件夹
    • -:表示普通文件
    • l:表示符号链接(symbolic link)
    • b:表示块设备(block device)
    • c:表示字符设备(character device)
  • 后9个字符表示文件权限,这些权限被分为三组,每组三个字符(rwx分别指代读、写、执行),三组按顺序分别为:所有者权限组权限其他用户权限
    • 其中rwx还可以用数字表示:r -> 4,w -> 2,x -> 1,通常使用于chmod指令,eg: chmod -R 600 ./表示递归修改当前文件夹下所有文件和文件夹权限为仅所有者可读写
    • drwxr-xr-x的权限数字为:755
    • -rw-r--r--的权限数字为:644

find查找文件

# find 查找多个后缀的文件
find /path/to/your/directory -type f \( -name "*.jpg" -o -name "*.png" \)

# 查找并删除
# 使用-delete
find /path/to/your/directory -name "通配符" -delete
# 或者使用-exec
find /path/to/your/directory -name "通配符" -exec rm {} \;

# wc -l 计算行数
find /path/to/your/directory -type f | wc -l

# 查找所有可执行文件并执行
find . -type f -executable -exec ./{} \;

# 查找忽略大小写
find . -iname "通配符"

# 查找忽略错误
find . -name "通配符" 2>/dev/null

# 限定检索层级和node类型
find . -maxdepth 1 -mindepth 1 -type f

# 修改前缀
find . -name "50_*" -exec /bin/bash -c 'mv {} $(dirname {})/latest_$(basename {} | sed "s/^50_//")' \;

grep查找文本

# grep -r 递归地搜索目录及其子目录中的文件,查找包含指定模式的行
grep -r [搜索模式] [起始目录]
# eg: grep -r "Acquire::http::Proxy" your_target_dir

# 搜索特定文件类型
grep -r --include="*.conf" [搜索模式] [起始目录]

# 排除特定目录
grep -r --exclude-dir="dir_to_exclude" [搜索模式] [起始目录]

# 额外参数:-i        忽略大小写
#          -n        显示行号
#          --include 仅包含匹配文件
#          --exclude 排除匹配文件

# 进行正则匹配
grep -oP [搜索模式] [文件路径]

批量改名

# 先安装 rename命令
apt install rename

# 批量重命名
rename 's/^latest_/pretrained_/' latest_*

文本处理

sed替换

# -i表示原地修改文件

# 替换文件中string
sed -i "s/source_str/target_str/g" your_file

# 在某行下添加
sed -i "2i\your_added_line" your_file

# 在匹配的string行下添加多行
sed -i "/pattern/a\your_added_line_0\nyour_added_line_1" your_file

# 删除匹配行
sed -i "/pattern/d"

# 删除

# 结合find处理匹配的所有文件, +表示将所有搜到的文件送给sed命令,\;表示一个一个处理
find . -name "*.cc" -type f -exec sed -i "/pattern/d" {} +

awk获取

# 获取第一个
echo "a b" | awk '{print}'

# 获取第一行
git remote | awk 'NR==1{print}'

拷贝

rsync命令

  • 非常重要:源目录包含/与不包含差异非常大。
    • /:表示把源文件夹中的所有内容同步过去
    • 不带/:表示把文件夹整个同步过去
  • -r--recursive
    • 递归复制目录及其内容。
    • 例如:rsync -r source/ destination/
  • -a--archive
    • 归档模式,等同于 -rlptgoD,表示递归复制并保留符号链接、文件权限、时间戳、组、所有者和设备文件信息。
    • 例如:rsync -a source/ destination/
  • -v--verbose
    • 显示详细的处理信息。运行时输出每个文件的处理情况。
    • 例如:rsync -av source/ destination/
  • -z--compress
    • 在传输过程中对数据进行压缩,可以减少传输的数据量。
    • 例如:rsync -az source/ destination/
  • -P
    • 显示传输进度,并保留部分传输的文件。如果传输中断,可以继续之前的传输。实际上是 --partial--progress 的组合。
    • 例如:rsync -P source/ destination/
  • --delete
    • 删除目标目录中在源目录中不存在的文件,使目标目录与源目录保持一致。
    • 例如:rsync -a --delete source/ destination/
  • -e--rsh=COMMAND
    • 指定使用的远程 shell 程序,例如使用 SSH 进行传输。
    • 例如:rsync -avz -e ssh source/ user@remote:/path/to/destination/
  • --exclude
    • 排除特定文件或目录,不同步这些内容。
    • 例如:rsync -av --exclude 'node_modules' source/ destination/
  • --include
    • --exclude 一起使用,指定要包括的文件或目录。
    • 例如:rsync -av --include '*.txt' --exclude '*' source/ destination/
  • --progress
    • 显示文件传输的进度信息。
    • 例如:rsync -av --progress source/ destination/
  • -h--human-readable
    • 以更易读的格式显示文件大小,如 1.2K2M3G
    • 例如:rsync -avh source/ destination/
  • -l--links
    • 保留符号链接,不复制符号链接指向的文件内容。
    • 例如:rsync -al source/ destination/
  • -t--times
    • 保留文件的修改时间戳。
    • 例如:rsync -at source/ destination/
  • -n--dry-run
    • 模拟运行,不实际复制文件,用于测试命令的效果。
    • 例如:rsync -avn source/ destination/
  • --checksum
    • 根据文件的校验和(而非时间戳或文件大小)判断文件是否需要更新。适用于内容频繁变化且时间戳一致的文件。
    • 例如:rsync -av --checksum source/ destination/
  • --numeric-ids
    • 保留文件数字id,即便目标盘中没有对应用户的id。
  • -H
    • 保留硬链接(Docker overlayfs 极其依赖这个!)。
  • --remove-source-files
    • 删除原始文件。
  • --ignore-existing
    • 忽略已经存在的文件。
# 拷贝并且显示进度
rsync -ah --progress /path/to/source /path/to/target

# 增量拷贝,会将./source文件夹中的数据全部拷贝到./target中,并且进行的是增量拷贝,也就是覆盖模式
rsync -av ./source ./target

# -a: 归档模式,保留所有权限、时间、链接
# -v: 显示进度
# -H: 保留硬链接(Docker overlayfs 极其依赖这个!)
# --numeric-ids: 哪怕目标盘没有对应的用户ID,也要强制保留数字ID
rsync -avH --numeric-ids --progress /data/storage/ /mnt/backup/storage_backup/

# 移动(删除原始)
rsync -avH --numeric-ids --remove-source-files --ignore-existing --progress <source_1> <source_2> <target>

拷贝软连接指向的实际文件

# 主要是增加-L选项
cp -L /path/to/soft_link ./target/

压缩文件时保留软连接而不是软连接指向的文件

# 压缩
# `-c`:此标志告诉 `tar` 创建一个新的归档。
# `-h`:此选项用于包含符号链接。如果没有此选项,`tar` 将归档符号链接本身而不是它指向的文件。
# `-f`:此选项用于指定归档文件的名称。它后面应该跟着归档文件的名称。例如,`-f archive.tar` 将创建一个名为 `archive.tar` 的归档。
tar -chf a.tar dir

#解压
tar -xf a.tar

磁盘

磁盘信息

# 查看当前挂载的磁盘和磁盘使用状况
df -h 

# 查看当前文件夹中各项大小
du -h --max-depth=1

# 查看当前磁盘读写状况

iotop

# 查看当前磁盘情况
fdisk -l
lsblk

# 查看当前磁盘的分区表和现有的标识符(如果有的话):
sudo blkid

# 想要通过UUID(磁盘标识符)进行挂载的话
# 编辑/etc/fstab,添加如下:
/dev/disk/by-uuid/6625bddb-47fa-4ff4-ab59-655a39486f6c /data/disk-1 ext4 defaults 0 1

分区

# 查看磁盘分区信息 或者
sudo fdisk -l  # or sudo lsblk

# 首先修改分区表为gpt(可选)
# sudo parted /dev/sda
# 随后执行 mklabel gpt; quit

# 选择要分区的磁盘,比如/dev/sda
sudo fdisk /dev/sda
# m: 打印帮助信息
# d: 删除分区
# n: 创建分区
# w: 写入分区信息
# q: quit

调整分区大小

# 实用parted工具
sudo parted /dev/sdb
# 进入交互式之后执行
resizepart 1
# 然后输入100%,然后quit
quit

# 在外部执行e2fsck 进行磁盘分区检测
sudo e2fsck -f /dev/sdb1

# 然后resize文件系统,就可以了.
sudo resize2fs /dev/sdb1

格式化

sudo mkfs.ext4 /dev/sdd1

查看目录挂载信息

df -h <path_to_your_dir>

创建raid

# 安装工具
sudo apt install mdadm

# 创建raid0
sudo mdadm --create --verbose /dev/md0 --level=0 --raid-devices=2 /dev/sda /dev/sdb

# 查看raid状态
cat /proc/mdstat

# 创建文件系统
sudo mkfs.ext4 /dev/md0

# 获取raid细节
sudo mdadm --detail /dev/md0

目录挂载

# 临时挂载文件夹到目标文件夹
mount --bind <source_dir> <target_dir>

# 持久化,写入到/etc/fstab
<source_dir>   <target_dir>   none   bind   0   0

U盘操作

# 挂载U盘,先查看u盘的device的设备分区
lsblk 

# 挂载
sudo mount /dev/sdxx /mnt/data

# 查看U盘设备的挂载点
lsblk
sudo umount /dev/sdxx
# 查看没有挂载点就可以拔了

ramfs/tmpfs

Linux中,ramfs是一种基于RAM的文件系统,它允许用户将数据存储在内存中。使用ramfs的好处是它提供了快速的数据访问,因为的所有操作都是在内存中完成的。另外ramfs是内核自带的文件系统之一,因此你不需要额外安装它,只用mount指令挂载即可。

# ramfs无法配置大小,也无法使用swap空间。
sudo mount -t ramfs none /mnt/ramfs

# 通常使用tmpfs,tmpfs可以指定最大大小、可以动态调整内存使用、可以在内存不足时使用交换空间、内存使用更加灵活。
sudo mount -t tmpfs -o size=512M tmpfs /mnt/tmpfs

磁盘测速

sudo apt install fio # Ubuntu/Debian/WSL

# 测试写入速度
fio -name=seq-write -ioengine=libaio -iodepth=1 -rw=write -bs=1m -direct=1 -size=1G -numjobs=1 -runtime=60 -group_reporting -filename=test_seq.file

# 测试读取速度
fio -name=seq-read -ioengine=libaio -iodepth=1 -rw=read -bs=1m -direct=1 -size=1G -numjobs=1 -runtime=60 -group_reporting -filename=test_seq.file

NFS

安装

sudo apt install nfs-kernel-server nfs-common -y

服务

# 开启启动服务
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server --now

# 如果nfs卡住的话(通常情况下为远程服务器关机或者硬盘更换等)
# 可以通过一下手段重启nfs客户端
# ubuntu
sudo systemctl restart nfs-client.target

# centos
sudo systemctl enable rpcbind --now
sudo systemctl enable nfs-server --now
# 随后修改/etc/exports之后执行
sudo exportfs -a

挂载

# ubuntu
sudo apt install cifs-utils nfs-kernel-server nfs-common
# centos
yum install nfs-utils

# 如果要挂载windows的samba硬盘(windows通常通过samba分享给linux)
# 修改/etc/fstab,添加

# 挂载cifs
# Linux下的路径是/etc/samba/smb.conf中的路径加上IP,eg:\\192.168.0.211/video-talking-workspace-data
# nofail可以在磁盘断连之后不尝试重连,防止卡顿。
//192.168.0.52/f /mnt/f cifs nofail,credentials=/etc/cifs-credentials,uid=1000,gid=1000,iocharset=utf8 0 0
# - 其中后面逗号隔开的是mount执行时-o的内容,也就是一些配置信息
# - credentials指向一个记录账号密码的文件/etc/cifs-credentials
# - gid,uid表示挂载后的内容的用户和组
# - 0 0 表示dump fsck,dump表示是否备份文件系统:0不备份 1备份,fsck表示检查文件系统的顺序:0不检查,1检查文件系统(常用于root),2检查但优先级低于1

# /etc/cifs-credentials, 注意文件权限要修改为600
username=YourUsername
password=YourPassword

# 挂载nfs
nfs-server:/shared/data  /mnt/nfs   nfs  defaults  0  0


# 临时挂载
sudo mount -t nfs -o vers=4 192.168.1.100:/path/to/share /mnt/nfs_share

导出

# 修改/etc/exports文件,eg往后添加需要导出的分区
/mnt/fu07 *(ro,sync,no_root_squash)
/mnt/fu06 *(ro,sync,no_root_squash)
/mnt/fu06a *(ro,sync,no_root_squash)
/mnt/fu06b *(ro,sync,no_root_squash)

# 修改完之后执行以下指令,即可刷新nfs导出
sudo exportfs -r

查看

# **查看NFS服务器上的共享 (可选但有用)**
showmount -e 192.168.1.100

Samba

安装&启动

# 安装
sudo apt install samba

# 启动
sudo systemctl start smbd
# 自动启动
sudo systemctl enable smbd

配置

配置文件路径:/etc/samba/smb.conf

...
# 在最下面添加
[faceunity]
    comment = Home directory of user faceunity
    path = /home/faceunity
    valid users = faceunity
    browseable = yes 
    writable = yes 
    read only = no
    guest ok = no
 
[video-talking-workspace-data]
    comment = Path to the video-talking-workspace-data
    path = /data/disk-0/faceunity/Projects/video-retalking/workspace-data/data
    valid users = faceunity
    browseable = yes 
    writable = yes 
    read only = no
    guest ok = no 

添加 Samba 用户(可选)

# 创建系统用户(如果还未创建)
sudo adduser sambauser
# 为用户设置 Samba 密码
sudo smbpasswd -a sambauser

挂载

# 在上面,这里再拷贝一遍
sudo apt install cifs-utils nfs-utils
# 如果要挂载windows的samba硬盘(windows通常通过samba分享给linux)
# 修改/etc/fstab,添加

# 如何是read write的话,添加rw
\\192.168.0.52/f /mnt/f cifs credentials=/etc/cifs-credentials,uid=1000,gid=1000,iocharset=utf8,vers=3.0 0 0
# - 其中后面逗号隔开的是mount执行时-o的内容,也就是一些配置信息
# - credentials指向一个记录账号密码的文件/etc/cifs-credentials
# - gid,uid表示挂载后的内容的用户和组
# - 0 0 表示dump fsck,dump表示是否备份文件系统:0不备份 1备份,fsck表示检查文件系统的顺序:0不检查,1检查文件系统(常用于root),2检查但优先级低于1

# /etc/cifs-credentials, 注意文件权限要修改为600
username=YourUsername
password=YourPassword

# 手动挂载
sudo mount -t cifs -o username=sambauser //192.168.0.100/ShareName /mnt

软连接

ln -s [目标文件或目录] [符号链接名称]

删除特殊文件

当遇到无法通过名字删除的文件rm -r <名字>,eg:window下编写的.sh脚本,换行符是CRLF,导致创建的文件夹名字包含了\r,没法通过rm直接删除的时候,可以通过inode的方式

# 直接使用rm -- <文件名> 这个指令的含义是:-- 后面字符全部看作文件名,而不是命令。
rm -- '-S !sudo tee test'

# 查看要删除的文件或者文件夹的inode number
ls -i
# 1957 cache  3548 cache\r  3365 egl_dma_test   491 test

# 随后删除,如果是文件的话直接
find . -inum <inode号> -delete

# 如果是文件夹
find . -inum <inode号> -exec rm -r {} \;

文件夹快速跳转

脚本中常用的:pushd ${next_dir}popd

#!/bin/bash

# 在当前文件夹做一些处理
...

pushd $next_dir

# 在$next_dir做一些处理
...

# 返回pushd之前所在的文件夹
popd

autojump:一个自动记录cd到文件夹的工具,并且可以支持模糊跳转,会自动计算文件夹的权重。

# 安装
sudo apt install autojump

# ubuntu24.04还需要执行
echo '. /usr/share/autojump/autojump.sh' >> ~/.bashrc

# 各种cd
...

# 快捷跳转,示例
j fu

# 查看当前autojump状态和权重
autojump --stat

# 重置数据库
autojump --purge

命令行快速看图

sudo apt install catimg
catimg <path_to_your_img>

swap

# 修改swap
# 使用fallocate快速分配空间
sudo fallocate -l 16G <目标文件夹>/swap.img
# 修改权限
sudo chmod 600 <目标文件夹>/swap.img
# 格式化为swap
sudo mkswap <目标文件夹>/swap.img
# 启用swap
sudo swapon <目标文件夹>/swap.img

# 修改/etc/fstab永久挂载
<目标文件夹>/swap.img none  swap  sw  0 0

# swap的配置信息在/etc/fstab中,可以进行修改
# 如果要关闭swap的话,可以使用命令,但是如果要永久关闭的话,也需要注释掉/etc/fstab中的内容
sudo swapoff -a

乱码

Centos中:

# 安装中文字体
sudo yum install -y wqy-microhei-fonts wqy-zenhei-fonts
sudo localectl set-locale LANG=zh_CN.UTF-8

Vim中:

# 配置~/.vimrc
set encoding=utf-8      " Vim 内部使用的编码
set fileencoding=utf-8  " 文件保存时的编码
set termencoding=utf-8  " 终端使用的编码
set fileencodings=ucs-bom,utf-8,gbk,cp936,latin1  " 自动识别文件编码的顺序

显卡

安装英伟达驱动

首先禁止nouveau

# /etc/modprobe.d/blacklist.conf最后添加
blacklist nouveau
# option nouveau modeset=0

随后执行

sudo update-initramfs -u
sudo rmmod nouveau

# 重启之后执行,查看是否正常禁用掉了。
sudo lsmod | grep nouveau 

显卡锁帧率防止过热

nvidia-smi -pm 1 # enable persistance mode
nvidia-smi -pl 250 # set power limit to 250w
nvidia-smi -lgc 500, 500 # lock the gpu clock, 500 is generally safe, you can try higher values.

设置开机自启动:

# 写入文件:/etc/systemd/system/nvidia-power-limit.service
[Unit]
Description=nvidia-smi power limit

[Service]
ExecStart=/bin/sh -c "nvidia-smi -pm 1 > /var/log/nvidia-power-limit.log 2>&1 && sleep 2 && nvidia-smi -pl 200 >> /var/log/nvidia-power-limit.log 2>&1 || exit 1"
Type=simple
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target
# 随后执行
sudo systemctl enable --now nvidia-power-limit

更新英伟达驱动

# 先查看nvidia设备占用情况,随后杀掉对应进程,并且安装新的驱动包
lsof /dev/nvidia*

查看显卡当前状态

# 查看显卡基础状态
nvidia-smi

# 查看编解码器的状态
nvidia-smi dmon -s u
# 输出解释,以下是一个示例输出:
# gpu    sm   mem   enc   dec
# Idx     %     %     %     %
    0    100     58      0      0
    1     73     48      0      0
    2     13      2      8      6
    3      0      0      0      0
    4      0      0      0      0
    5      0      0      0      0
    6      0      0      0      0
# sm: Streaming Multiprocessor(流式多处理器)的使用率,是NVIDIA GPU 的计算核心组成部分,负责大部分并行计算任务:图形渲染、深度学习推理与训练、科学计算、其他并行处理任务
# mem: 显存占用情况
# enc:GPU编码器占用情况
# dec:GPU解码器占用情况

解除硬编/解码限制

# https://github.com/keylase/nvidia-patch

# clone下来之后执行
sudo ./patch.sh

系统相关

系统启动时间

uptime -s

系统改host

# 修改/etc/hosts
# 修改/etc/hostname
# 立即应用(好像没有生效,需要重启)。
sudo systemctl restart systemd-hostnamed

SSH

常规登录方式:

# 常规的登录方式
ssh username@ip  

简单的登录方式:

# 简单的登录方式:修改~/.ssh/config 添加如下的信息
Host my_host
    HostName 192.168.0.211
    User faceunity
    ForwardX11 yes # 可选
    ForwardX11Trusted yes # 可选

# 随后直接以下命令就可以了
ssh my_host

中文支持

# 更新源
sudo apt update && apt install locales

sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen

# 在~/.bashrc添加
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

Dockerfile:

RUN apt install -y locales && sed -i '/zh_CN.UTF-8/s/^# //g' /etc/locale.gen && locale-gen 
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN:zh
ENV LC_ALL=zh_CN.UTF-8

Ubuntu查看版本

lsb_release -a

显示CPU信息

sudo lshw -class processor

tmux基础配置

# .tmux.conf
# 设置可以用鼠标滚轮看历史 
set-window-option -g mouse on
# 修改prefix快捷键: 
set -g prefix C-a
# 取消绑定原始的prefix快捷键
unbind C-b
# 将C-a绑定上去
bind C-a send-prefix

Linux如何切换gcc编译器版本

# 直接切换gcc-11
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 10
# 直接切换gcc-12
sudo update-alternatives --install /usr/bin/gcc  gcc /usr/bin/gcc-12 20
# 

查看系统字节序

lscpu | grep "Byte Order"

update-alternatives配置

# 以python为例
# 为python3添加一个python的选项,其他应用程序的应该类似。
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1
# 运行以下命令以选择默认的python版本
sudo update-alternatives --config python

安装支持libc++的clang

sudo apt update 
sudo apt install clang libc++-dev libc++abi-dev

Ubuntu Server安装远程图形界面

安装x11

sudo apt install xorg
sudo apt install x11proto-dev x11-utils libx11-dev libxext-dev x11-xserver-utils

# x11-xserver-utils包 可以安装xrandr命令

DISPLAY概念

这里的DISPLAY的概念有点类似于虚拟显示器。通常是xorg启动的DISPLAY,xorg可以通过指令手动启动,也可以使用gdm3自动启动的xorg给的DISPLAY,但是gdm3的安全机制,会利用xhost管理可以访问某个用户开启的xorg(DISPLAY),导致其他用户用不了。

渲染设备配置

如果显卡上能够连接物理显示器或者显卡欺骗器,是最简单的,连接上去之后重启电脑,然后xrandr能够看到有设备连上,打印信息类似于:就可以正常跑了

Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
HDMI-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 598mm x 336mm
   1920x1080     60.00*+  74.97    59.94    50.00
   1600x900      60.00
   1280x1024     75.02    60.02
   1280x720      60.00    59.94    50.00
   1152x864      75.00
   1024x768      75.03    60.00
   800x600       75.00    60.32
   720x576       50.00
   720x480       59.94
   640x480       75.00    59.94    59.93
DP-0 disconnected (normal left inverted right x axis y axis)
DP-1 disconnected (normal left inverted right x axis y axis)
DP-2 disconnected (normal left inverted right x axis y axis)
DP-3 disconnected (normal left inverted right x axis y axis)
DP-4 disconnected (normal left inverted right x axis y axis)
DP-5 disconnected (normal left inverted right x axis y axis)

如果没有物理设备,或者服务器没法直接在显卡上插设备,可以使用nvidia-xconfig修改/etc/X11/xorg.conf来实现。下面指令会扫描所有可用设备,如果服务器是多显卡,不想为所有显卡创建device,可以去修改/etc/X11/xorg.conf删除多余的Device、Monitor等。增加了--only-one-x-screen参数之后只给一个显卡配置xscreen

# 使用以下命令可以配置xorg.conf
# 命令参数解析
# -a:自动检测并添加可用的显示设备配置。
# --allow-empty-initial-configuration:允许生成的配置文件即使没有检测到任何显示设备也能创建。这样,即使没有实际连接显示器,仍然可以生成一个基础的配置文件。
# --use-display-device="DP-0":指定使用的显示设备,这里设置为 DP-0。这告诉 NVIDIA 驱动程序优先考虑此接口,即使没有物理显示器连接。
# --connected-monitor="DP-0":指定连接的显示器,这里也设置为 DP-0。此参数告诉 NVIDIA 驱动程序将 DP-0 视为连接的显示器。
# --custom-edid="DP-0:/home/$USER/edid-2.bin":指定一个自定义的 EDID(扩展显示标识数据)文件,用于模拟显示器的能力。这个文件包含了显示器的分辨率、刷新率等信息。
# --only-one-x-screen 只给一个显卡配置xscreen
sudo nvidia-xconfig -a --allow-empty-initial-configuration --use-display-device="DP-0" --connected-monitor="DP-0" --custom-edid="DP-0:/home/$USER/edid-2.bin" --only-one-x-screen
# 这样搞完之后,因为想要使用较大的虚拟显示器。
# 需要修改/etc/X11/xorg.conf
Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    Option         "AllowEmptyInitialConfiguration" "True"
    Option         "UseDisplayDevice" "DP-0"
    Option         "CustomEDID" "DP-0:/home/yangkaihang/edid-2.bin"
    Option         "ConnectedMonitor" "DP-0"
    SubSection     "Display"
        Depth       24
        Virtual     3840 2160 # 这个地方是关键,虽然足够大了,但是还有问题,部分渲染会导致结果出错。
    EndSubSection
EndSection

# 按需配置,配置完之后重启video_retalking_xorg服务,如果启动了的话
sudo systemctl restart video_retalking_xorg

# 启动之后xrandr应该显示
# $ xrandr
# Screen 0: minimum 8 x 8, current 3840 x 2160, maximum 32767 x 32767

手动开启xorg

手动开启xorg并且建立DISPLAY的socket,以下是建立到0,文件是/tmp/.X11-unix/X0

Xorg -dpi 96 -noreset -nolisten tcp +extension GLX +extension RANDR +extension RENDER +extension DOUBLE-BUFFER -config /etc/X11/xorg.conf -logfile xorg-10.log -verbose :0

service的形式:

[Unit]
Description=Video Retalking's Xorg service
After=display-manager.service
 
[Service]
ExecStart=Xorg -dpi 96 -noreset -nolisten tcp +extension GLX +extension RANDR +extension RENDER +extension DOUBLE-BUFFER -config /etc/X11/xorg.conf -logfile /var/log/video_retalking_xorg-111.log -verbose :111
Type=simple
Restart=always
RestartSec=5
User=root
 
[Install]
WantedBy=multi-user.target

安装桌面环境

Gnome: Gnome是Ubuntu:20.04默认的桌面环境,会比较重。

sudo apt install ubuntu-desktop
sudo apt install gnome-shell

安装RDP服务器

# 安装开源rdp服务
sudo apt install xrdp

# 设置xrdp默认使用xfce
echo xfce4-session > ~/.xsession

# 设置xrdp使用xubuntu会话
# 打开并编辑/etc/xrdp/startwm.sh 注释掉以下两行,并且添加为
# test -x /etc/X11/Xsession && exec /etc/X11/Xsession
# exec /bin/sh /etc/X11/Xsession
startxfce4

# 随后重启xrdp服务。
sudo systemctl restart xrdp

# 给xrdp添加ssl-cert权限
sudo adduser ssl-cert xrdp

# 并且开放3389端口
sudo ufw allow 3389

随后Windows可以直接使用RDP客户端(远程桌面)进行链接。

X11-Forwarding

X11-Forwarding的方式可以使得windows通过ssh直接用windows本机的display(比如[[IT知识/OS/Windows/实用指令#支持远端X11|vcxsrv]])调用远端的图形程序。操作方式:

# windows上参照vcxsrv的教程安装

# linux服务上安装好X11之后,通过以下方式连接

ssh -Y user@host
# 随后可以打印一下display,看到之后就可以实用图形程序了
echo $DISPLAY

通过IP的方式连接vcxsrv

我的理解,这种方式是最底层的直接连接方式,ssh -Y的方式也是在这种基本方式上封装的。

# windows端开启vcxsrv,并且防火墙开放对应端口,据说是6000(对应0.0)
# 正常方式ssh连接 server,随后在server中
export DISPLAY=<your_windows_ip>:0.0

# 随后可以直接使用图形程序了

容器内进一步映射

services:
  some_service:
	...
    environment:
      - TZ=Asia/Shanghai
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
      - DISPLAY=<your_windows_ip>:0.0
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    network_mode: host
    tty: true
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix:ro
      - /dev/dri:/dev/dri:ro
      - /etc/OpenCL/vendors:/etc/OpenCL/vendors:ro
      - /etc/vulkan:/etc/vulkan:ro
    ...

动态链接库

查看系统已经缓存的共享库列表,显示/etc/ld.so.cache文件中缓存的所有共享库的路径和名称:

ldconfig -p

查看某个动态库或者可执行程序链接的动态库和地址:

ldd <可执行文件或共享库>

systemd

systemd是大多数现代Linux发行版的初始化系统,用于管理启动时的服务的启动。通常配置文件存在于/etc/systemd中。

自定义

Q&A

.wants和.requires文件夹

通常可能在/etc/systemd/system中除了.service文件之外,还有相应的.wants或者.requires文件夹,这些文件夹表示服务的依赖,里面一般是其他服务的符号链接,其中.wants表示该服务想要这些服务启动,但启动失败服务仍能正常启动(属于软依赖),但是.requires硬依赖,如果依赖的服务没有正常启动,该服务也启动不了。

APT

常用指令

# 查看apt-key
sudo apt-key list
# 如果查到了,执行下面命令删除
sudo apt-key del <查到的GPG密钥>

# 查看 apt-add-repository
# 通常在,/etc/apt/sources.list或/etc/apt/sources.list.d中,删除即可

sudo apt update

# 同步代码 eg: locales
sudo apt source locales
# cd 到源码目录,随后编译
sudo dpkg-buildpackage -us -uc

# 锁定软件版本
sudo apt-mark hold <your_package>

系统救砖

一般在更新了不对的系统库libc6libc-bin之后,系统每个指令都会出现segment fault,这个时候就需要进行救砖了。

  1. 找个U盘,并且写入对应系统版本的镜像(ubuntu server就行)
  2. 随后从U盘启动,并且进入安装流程。
  3. 在安装流程的任意时候,按ctrl + alt + F2/F3/F4进入tty模式。
  4. 随后按照如下执行:
# 随后将系统盘挂载到`/mnt`中:
mount /dev/sd? /mnt/

# 然后绑定虚拟文件系统:
sudo mount --bind /dev/ /mnt/dev
sudo mount --bind /run/ /mnt/run
sudo mount --bind /usr /mnt/usr
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

# 切换根目录到/mnt
sudo chroot /mnt

# 修复核心包
sudo apt update 
sudo apt install --reinstall libc6 libc-bin # 这两个东西真的是坑...
sudo dpkg --configure -a
sudo apt --fix-broken install

	# 重启系统
sudo reboot

进程状态分析

  • 首先安装iotopstrace
sudo apt install iotop strace

# 1. 首先通过top或者htop找到需要查看进程的pid
# 2. 随后利用ps -aux | grep <pid>查看进程的状态

# 举个例子,我想查看的进程是4216
ps -aux | grep 4216

SSH剪贴板共享

ssh远程连接时,使得xclip共享本地的剪贴板,从而使得vim等软件的复制可以直接复制到本机剪贴板中。

剪贴板(clipboard)是X11服务器管理的资源,剪贴板和选择缓冲区(selection buffers)是由X服务器(Xorg、Xwayland、vcxsrv等)维护的,而xclipxsel这些工具是通过X11协议与X服务器通信来读写剪贴板。

所以如果通过ssh连接服务器,想要在服务器中拷贝时(比如lvim配置clipboard)直接将数据拷贝到本机的剪贴板中,需要在本机开启X11 server(windows下使用vcxsrv,配置方式见[[IT知识/OS/Windows/实用指令#支持远端X11|安装方式]]),然后ssh登录的时候使用X11Forwarding

# 直接使用ssh指令
ssh -Y <server>

# 配置~/.ssh/config
Host home
    HostName 192.168.111.222
    User k
    ForwardAgent yes
    ForwardX11 yes
    ForwardX11Trusted yes
# 然后直接 ssh home就行了

lvim配置剪贴板

lvim安装

CTRL-Z

CTRL-Z可以将在前台运行的程序临时挂起到后台,从而执行别的命令。

操作命令
挂起当前进程Ctrl + Z
查看后台任务jobs
继续后台运行bgbg %n
恢复到前台fgfg %n
让任务脱离终端disown -h %n
让新任务在后台运行command &
让任务后台运行并不受终端影响nohup command &

pwgen

这个工具是用来生成强密码的:

# 安装
sudo apt install pwgen
# 随机生成两个16位的密码
pwgen -s 16 2

zip

# 压缩当前文件夹下所有内容
zip -r test.zip ./

# 排除特定文件:排除所有隐藏文件(包括子文件夹中的,实测*/.*表示所有递归层)
zip -r test.zip ./ -x ".*" -x "*/.*"

# 解压文件
unzip test.zip

# 仅查看压缩包中文件名和路径
unzip -l test.zip

# 测试压缩包是否完整
zip -T test.zip

# 保留软连接
zip -y test.zip ./

Bash脚本语法

命令行参数解析

VERSION=""
# 如果需要OPTARG,则需要加上:
while getopts "v:a" opt; do
  case "$opt" in
	a)
	  echo "A"
    v)
      VERSION="$OPTARG"
      ;;
    *)
      echo "Usage: $0 [-v <VERSION>: input version tag]"
      exit 1
      ;;
  esac
done

执行

./script.sh:将创建一个新的shell进程执行该脚本,所以内部修改环境变量和改变的工作路径,在脚本执行结束之后将会消除。 . script.sh/source script.sh:在当前shell中执行脚本,修改的环境变量和改变的路径将会对当前shell生效。

脚本配置

# 设置执行的shell
#!/bin/bash

# 设置出错中断执行
set -e

# 设置打印执行的指令
set -x

条件语句

常用条件

  • 整数比较
    • -eq:等于
    • -ne:不等于
    • -gt:大于
    • -lt:小于
    • -ge:大于或等于
    • -le:小于或等于
  • 字符串比较
    • ===:等于
    • !=:不等于
    • -z:字符串为空
    • -n:字符串不为空
  • 文件检查
    • -e:文件存在
    • -f:文件存在且是普通文件
    • -d:文件存在且是目录
    • -r:文件存在且可读
    • -w:文件存在且可写
    • -x:文件存在且可执行
    • -L:软连接
# 判断是否为空
if [ -z "$1" ]; then
	echo "参数为空"
	exit 1
fi

# 判断是否是文件夹
if [ -d "$1" ]; then
	echo "为文件夹"
else
	echo "不是文件夹"
	exit 1
fi

# 数字比较
if [ $a -eq $b ]; then
	echo "equal"
	exit 1
fi

# 并列判断
if [ -n "${major}" && -n "${minor}" && -n "${patch}" ]; then

fi

条件取反

# 比如判断路径是否是文件夹
if [ -d /path/to/your_dir ]; then
	echo -e "/path/to/your_dir is directory."
fi

# 如果想要判断不是文件夹使用!
if [ ! -d /path/to/your_dir ]; then
	echo -e "/path/to/your_dir is not a directory."
fi

一行脚本判断

[ -d "your_path" ] && rm -r your_path

判断命令执行结果

# 举个例子:检查mount点是否已经mount了,用于避免mount指令重复执行
if findmnt /mnt/storage_server/my_mount_point &> /dev/null; then
	# /mnt/storage_server/my_mount_point已经mount了,执行一些操作
	echo -e "/mnt/storage_server/my_mount_point has already been mounted."
else
	# mount it.
	echo -e "Mounted."
fi

循环语句

遍历文件内容

# 替换AddressSanitizer结果为代码文件:行号
# 其中asan_result.txt 可执行程序stderr重定向'./executable 2>./asan_result.txt'获取
grep -oP '(?<=\/)[\w.]+\+0x[0-9a-f]+' ./asan_result.txt | while IFS='+' read -r LIB_NAME OFFSET; do
    if [ -e "$LIB_DIR/$LIB_NAME" ]; then
      LINE=$(addr2line -e $LIB_DIR/$LIB_NAME $OFFSET)
      LINE=$(echo $LINE | sed 's/\//\\\//g')
      sed -i -E "/$LIB_NAME\\+$OFFSET/s/(#[0-9]+\\s0x[0-9a-f]+).*/\\1  $LINE/" ./asan_result.txt
    fi
done

遍历文件夹

# 处理一级子文件/文件夹
# for path in /path/to/your_target/*;do
# 处理一级子文件夹
# for path in /path/to/your_target/*/;do
# 递归处理所有子文件夹
# for path in /path/to/your_target/**/;do
	if [ -d $path ];then
		echo "processing directory $path"
	elif [ -f $path ];then
		echo "processing file $path"
	fi
done

时间

获取

# 获取当前时间
date

# 获取格式化的时间
date +%Y%m%d_%H%M%S

# 获取根据时间命名的文件
file_name=output_log_$(date +%Y%m%d_%H%M%S).txt

时区

# 老版本的可以通过修改环境变量,这个也是docker中常用的
export TZ=Asia/Shanghai

# Ubuntu24.04则通过timedatectl工具
timedatectl # 打印当前系统的时区设置

# 列出所有可用的时区
timedatectl list-timezones

# 找到需要的时区之后,可以通过以下指令设置时区
sudo timedatectl set-timezone Asia/Shanghai

文件

路径获取

使用pwd或者realpath

# 当前文件夹的绝对路径
CUR_PATH=$(pwd)
CUR_PATH=$(realpath ./)

# 某个文件夹的绝对路径
DIR_PATH=$(cd your_dir && pwd)
DIR_PATH=$(realpath your_dir)

# 某个文件所在的文件夹
FILE_DIR_PATH=$(cd $(dirname your_file) && pwd)
FILE_DIR_PATH=$(dirname $(realpath your_file))

重定向

文本重定向到文件通常使用>>>,其中>重定向会覆盖原始文件>>则会往文件后添加内容

字符串操作

«< (Here String)

<<<操作符称作"Here String“操作符,用于将单行字符串直接输入给需要文件输入的指令。 比如: cat <<< "testing"

«(Here Document)

<<操作符称作”Here Document“操作符,用于将多行字符串输入给需要文件输入的指令,使用第一个字符串作为结尾字符。

# EOF作为结尾字符
cat << EOF
I am just testing.
Please input EOF as single line to stop it.
EOF

read

read指令将输入直接读到变量中,eg:

read USER PASSWD <<< "test 123456"
echo $USER $PASSWD # will print test 123456

tee

# 多行文本指令写入文件
# 中间可以用环境变量 ${YOUR_ENV}
# tee默认是覆盖
tee <your_target_file> <<EOF
这里写多行文本
你就写吧
但是文本中不能包含E_O_F这个词,否则会直接结束
EOF
# 就是结束符EOF

# 文件后添加需要加 -a 参数
tee -a <your_target_file> <<EOF

文件后添加的文本
EOF

正则匹配

#!/bin/bash

version="v1.2.3-beta+build123"
regex="^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z]+[0-9]*)?(\+.*)?$"

if [[ $version =~ $regex ]];then
  major="${BASH_REMATCH[1]}"
  minor="${BASH_REMATCH[2]}"
  patch="${BASH_REMATCH[3]}"
  metadata="${BASH_REMATCH[4]}"
  build="${BASH_REMATCH[5]}"
  # 去掉+和-
  metadata="${metadata#-}"
  build="${build#+}"

  echo "Major: $major"
  echo "Minor: $minor"
  echo "Patch: $patch"
  echo "Metadata: $metadata"
  echo "Build: $build"
fi

函数定义

# 常规定义
my_function() {
    echo "The first parameter is: $1"
    echo "The second parameter is: $2"
}
# 使用function关键字
function my_function {
    echo "The first parameter is: $1"
    echo "The second parameter is: $2"
}

命令行参数

# `$#`获取命令行参数数量,只有参数的数量
if [ "$#" -eq 0 ]; then
    echo "No arguments provided."
    exit 1
fi

# `$@`:参数会被逐个处理,每个参数保留独立的字符串形式。常用于传递所有参数给另一个脚本
# `$*`:所有参数被合并为一个字符串,参数之间仅由空格分隔

脚本嵌套

假如有一个functions.sh脚本,另一个脚本需要引用其中的function,需要在另一个脚本中source ./functions.sh,执行

# functions.sh
#!/bin/bash
echo "Test"
exit -1
function test() {
...
}

# caller.sh
source ./functions.sh
# or . ./functions.sh

# 通过source或者.执行的脚本,会在遇到exit -1,直接退出caller.sh,source的逻辑有点类似于c的include

定时任务 (Cron)

Cron 是 Linux 下的定时任务守护进程。

常用命令

# 编辑当前用户的 cron 表
crontab -e

# 列出当前用户的 cron 表
crontab -l

# 删除当前用户的 cron 表
crontab -r

语法格式

# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 日 (1 - 31)
# │ │ │ ┌───────────── 月 (1 - 12)
# │ │ │ │ ┌───────────── 星期 (0 - 7) (0和7都是周日)
# │ │ │ │ │
# * * * * * <command to execute>

常用示例

# 每分钟执行一次
* * * * * /path/to/script.sh

# 每 5 分钟执行一次
*/5 * * * * /path/to/script.sh

# 每天凌晨 3:30 执行
30 3 * * * /path/to/script.sh

# 每周日凌晨 4:00 执行
0 4 * * 0 /path/to/script.sh

# 工作日 (周一至周五) 早上 9:00 执行
0 9 * * 1-5 /path/to/script.sh

# 重启时执行
@reboot /path/to/script.sh

输出重定向

Cron 任务的输出(stdout 和 stderr)默认会发送邮件给用户。通常建议重定向到文件或丢弃。

# 重定向标准输出和标准错误到 /dev/null (丢弃)
* * * * * /path/to/script.sh > /dev/null 2>&1

# 重定向日志到文件
* * * * * /path/to/script.sh >> /var/log/myscript.log 2>&1

任务挂起

# 
nohup <your_command> > logs.txt 2>&1 &