- -P
- 输出解析符号链接后的物理路径
- -L
- 输出保留符号链接的逻辑路径(默认)
pwd我在哪儿?
pwd -P通过符号链接进入时显示真实路径
按任务分类的 Linux 命令,从文件和权限到网络、systemd 和文本处理。每条都附常用参数、可复制的示例和 macOS 差异说明。
最后核对:2026-10-18,依据 GNU coreutils 9.x、util-linux、procps-ng、iproute2、systemd 和 bash 5.2 手册;macOS 说明依据 macOS 26 的 man 手册页。
读取文件、翻阅日志、在终端中编辑并比较不同版本。
cat /etc/os-release输出文件内容
cat part1.txt part2.txt > whole.txt拼接文件
cat -A script.sh | head找出隐藏的制表符和 Windows 的 ^M 换行符
macOS/BSD: macOS 的 cat 没有 -A;用 cat -vet 可得到相同的显示效果。
tac access.log | head最新的日志行在前
macOS/BSD: macOS 没有此命令;请用 tail -r file。
less /var/log/syslog阅读日志
journalctl -u nginx | less -S长行不换行显示
head -n 20 data.csv表头和前几行数据
head -c 512 file.bin | xxd查看二进制文件的开头
macOS/BSD: macOS 的 head 不接受负数。
tail -n 50 app.log最后 50 行
tail -F /var/log/nginx/access.log跟踪会被轮转的日志
tail -n +2 data.csv跳过 CSV 的表头行
sudo nano /etc/hosts编辑系统文件
屏幕底部的快捷键栏会列出按键;^ 表示 Ctrl,M- 表示 Alt。
vim +42 app.py打开并定位到第 42 行
diff -u old.conf new.conf易读的改动视图
diff -rq dir1/ dir2/两个目录树之间哪些文件不同
diff <(sort a.txt) <(sort b.txt)排序后再比较,借助进程替换
make 2>&1 | tee build.log观看构建过程并保留日志
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf追加到属于 root 的文件(sudo echo >> 会失败,因为重定向由 shell 执行)
printf '%s\n' "$var"安全地输出变量,即使它以 -n 开头
printf '%-12s %6.2f\n' disk 93.5对齐的列
不同 shell 中 echo -e 和 echo -n 的行为不一致;printf 在哪里都一样。
column -t -s, data.csv | less -S把简单的 CSV 当表格阅读
mount | column -t对齐以空白分隔的输出
xxd image.png | head十六进制与 ASCII 并排显示
hexdump -C file.bin | head标准格式的十六进制转储
xxd 属于 vim 软件包;hexdump 在 util-linux 中(较新的 Debian/Ubuntu 上在 bsdextrautils 中)。
strings -n 8 firmware.bin | less查找版本字符串、URL 和路径
在 Linux 上属于 binutils。
查看和修改谁可以读取、写入和执行文件。
ls -l deploy.sh-rwxr-x--- 1 alice devs 812 Oct 18 09:12 deploy.sh
第一个字符表示类型(- 文件,d 目录,l 符号链接)。接下来是三组三位:所有者、所属组、其他所有人。r=4、w=2、x=1,所以 rwxr-x--- 就是 750。
chmod 644 index.html所有者可读写,其他人只读:普通文件
chmod 755 deploy.sh所有者全部权限,其他人可读可执行:脚本和目录
chmod 600 ~/.ssh/id_ed25519私钥仅自己可读;权限过宽时 ssh 会拒绝使用
chmod +x script.sh让脚本可执行
chmod go-w file去掉所属组和其他人的写权限
chmod -R u=rwX,go=rX site/大写 X 只给目录和本来就有执行权限的文件设置执行权限
find site/ -type d -exec chmod 755 {} +正确的修复,第 1 步:目录设为 755
find site/ -type f -exec chmod 644 {} +第 2 步:文件设为 644
危险: 这会让机器上的每个用户、每个被攻破的服务都能写入整个目录树,把所有文件标记为可执行,而且 ~/.ssh 为 777 时 OpenSSH 会拒绝使用其中的密钥。如果用在 /etc 或 /usr 上,可能会弄坏 sudo 乃至整个系统。请改用 chown 修正所有权,或者使用下面两条 find 命令。
sudo chown -R www-data:www-data /var/www/site把网站根目录交给 Web 服务器用户
sudo chown "$USER": file.txt接管 root 创建的文件
危险: 在 /、/usr 或 /etc 上执行 sudo chown -R 会清除 sudo、passwd 和各种服务所依赖的 setuid 位和所有权;恢复通常只能重装系统。请仔细核对路径。
chgrp -R developers /srv/shared把共享文件夹交给团队组
umask显示当前掩码,通常是 0022
umask 077在当前 shell 中新文件为 600,新目录为 700
掩码用于去掉权限位:文件从 666 开始,目录从 777 开始,所以 022 得到 644 和 755。
sudo systemctl restart nginx执行一条管理命令
sudo !!用 sudo 重新运行上一条命令
sudo -u postgres psql以服务用户身份运行
su - deploy以 deploy 身份登录并加载其环境
sudo su -root 没有设置密码时获得 root shell(sudo -i 效果相同)
setfacl -m u:alice:rw report.xlsxalice 可读写,且不改变所属组
getfacl report.xlsx显示所有条目
setfacl -R -m g:devs:rwX /srv/app让某个组获得整个目录树的访问权限
ls -l 权限字符串末尾的 + 表示文件带有 ACL。
sudo chattr +i /etc/resolv.conf在去掉 -i 之前,任何人(包括 root)都无法修改或删除它
lsattr /etc/resolv.conf显示属性;i 表示不可更改
支持 ext4、XFS、Btrfs。如果即使是 root 也出现“Operation not permitted”,请检查 lsattr。
查看正在运行什么、停止它,以及在后台运行任务。
ps aux | grep [n]ginx[n] 技巧可以把 grep 自身排除在结果之外
ps aux --sort=-%mem | head占用内存最多的进程
ps -o pid,ppid,etime,cmd -p 1234进程已经运行了多久
macOS/BSD: macOS 的 ps 没有 --sort;请用 ps aux -m(按内存)或 ps aux -r(按 CPU)。
pstree -p带 PID
pstree -p 1234某个进程派生了哪些子进程
top -b -n 1 | head -20可以直接贴进工单的快照
macOS/BSD: macOS 的 top 是另一个程序:用 top -o cpu 或 top -o mem 排序。
htop -u www-data只看某个用户的进程
安装方法:apt install htop / dnf install htop。
pgrep -a nginxPID 和命令行
pgrep -f 'python manage.py runserver'按参数匹配某个脚本
macOS/BSD: 在 macOS 上,-a 表示“包括祖先进程”;请用 pgrep -lf 查看名称和参数。
pkill -f "node server.js"停止某个 Node 应用
pkill -HUP nginx发送重新加载信号
pgrep -af node结束进程前先预览 -f 会匹配到什么
模式是正则表达式,只要名称中任意位置匹配即可;pkill node 也会命中 nodejs-helper。请先用 pgrep 预览。
kill 1234礼貌地停止
kill -9 1234TERM 被忽略时的最后手段
kill %1结束当前 shell 的作业 1
先用普通的 kill 并等几秒:-9 会跳过清理,可能留下临时文件、锁和写了一半的数据。
killall firefox所有 Firefox 进程
在 Linux 上它属于 psmisc 软件包。
jobs列出当前 shell 中的作业及其编号
bg %1在后台恢复作业 1
fg %1把它调回前台
Ctrl+Z 会挂起前台程序(在执行 bg 或 fg 之前它会停止运行)。
./long-export.sh > export.log 2>&1 &启动后立即返回提示符
wait在脚本中等待后台作业完成
nohup ./server > server.log 2>&1 &关闭 SSH 会话后依然运行
对于需要长期运行的程序,systemd 服务(见“服务与日志”)或 tmux 更可靠。
disown -h %1忘了用 nohup:先用 bg 放到后台,再 disown
tmux new -s deploy新建一个命名会话
tmux attach -t deploySSH 断开后重新连接
用包管理器安装。GNU screen 是较老的替代品(Ctrl+A d 分离,screen -r 重新连接)。
nice -n 19 tar -czf backup.tgz /data不影响其他任务的后台备份
sudo renice -n -5 -p 1234提高正在运行的进程的优先级
nice 值范围是 -20(优先级最高)到 19(最低)。只有 root 能设为 0 以下。
timeout 30s curl -s https://example.com/health30 秒后放弃
timeout -s KILL 5m ./job.sh五分钟后强制结束
达到时间限制时以状态码 124 退出。
watch -n 2 df -h观察磁盘空间被占满的过程
watch -d 'ss -s'-d 会高亮显示变化的部分
sudo lsof -i :8080谁在监听 8080 端口
sudo lsof +L1仍被打开的已删除文件(磁盘已满但 du 显示不出来)
lsof -p 1234某个进程打开的所有文件
sudo fuser -vm /mnt/usb为什么 umount 提示“target is busy”
sudo fuser -v 8080/tcp占用某个 TCP 端口的进程
危险: fuser -k 会不加提示地结束所有使用目标的进程;对挂载点使用时,其中可能包括你自己的 shell。
time ./build.shreal = 实际耗时,user + sys = CPU 时间
strace -f -e trace=openat ./app 2>&1 | grep -v ENOENT它实际打开了哪些文件?
sudo strace -p 1234卡住的进程在等什么?
操作系统版本、内核、CPU、内存、硬件、时间和负载。
uname -r例如 6.8.0-45-generic
uname -m该下载哪个版本的二进制文件:x86_64 还是 aarch64
cat /etc/os-release所有 systemd 时代发行版都有的 NAME、VERSION_ID、ID
lsb_release -aDebian/Ubuntu 上的替代方法(如已安装)
macOS/BSD: macOS:sw_vers。
hostnamectl主机名、操作系统、内核、虚拟化
sudo hostnamectl set-hostname web01重命名这台机器
uptime过去 1、5、15 分钟的平均负载
负载是正在运行或等待运行的进程数。请与 CPU 数(nproc)对比:4 核机器负载为 4 表示已满负荷。
free -h看“available”列,而不是“free”列
macOS/BSD: macOS:vm_stat,或 top -l 1 | grep PhysMem。
Linux 会把空闲内存用作磁盘缓存,所以健康的机器上“free”看起来也很低。“available”才是程序还能用到的内存。
lscpu型号、插槽、核心、线程、特性标志
make -j"$(nproc)"用上所有可用核心
macOS/BSD: macOS:sysctl -n hw.ncpu 和 sysctl -n machdep.cpu.brand_string。
lspci -k | grep -A3 -i vga显卡及正在使用的驱动
lsusb系统到底有没有识别到这个 USB 设备?
sudo dmidecode -t memory | grep -i size每个插槽上安装的内存
sudo lshw -short每个设备一行
sudo dmesg -T | tail -30刚刚发生了什么(插入 USB、磁盘错误)
sudo dmesg -T | grep -i 'out of memory'是不是 OOM killer 结束了你的应用?
grep MemAvailable /proc/meminfo可用内存(单位 kB)
grep -c ^processor /proc/cpuinfo逻辑 CPU 数量
cat /proc/1234/status单个进程的状态和内存
vmstat 1 5r = 运行队列,si/so = 换页,wa = 等待 I/O
iostat -xz 1每块磁盘的利用率(%util)和延迟(await)
iostat 来自 sysstat 软件包。
date '+%Y-%m-%d %H:%M:%S'用于日志的时间戳
date +%s自 1970-01-01 UTC 起的秒数
date -d @1700000000时间戳转日期(GNU)
date -d '2 days ago' +%F相对日期(GNU)
macOS/BSD: macOS 的 date 没有 -d。时间戳转日期用 date -r 1700000000,“2 天前”用 date -v-2d,解析日期用 date -j -f '%Y-%m-%d' 2026-10-18 +%s。
timedatectl本地时间、UTC、时区,NTP 是否已同步?
timedatectl list-timezones | grep America查找时区名称
sudo timedatectl set-timezone America/Toronto修改时区
剩余空间、空间被谁占用、分区、挂载与格式化。
df -h所有已挂载的文件系统
df -h .当前目录所在的文件系统
df -i明明还有空闲字节却提示“No space left”?可能是 inode 用完了
macOS/BSD: 在 macOS 上,-T 是按类型筛选,而不是显示类型。
du -sh /var/log单个文件夹的大小
du -h -d 1 | sort -h各子文件夹大小,最大的排在最后(GNU 和 macOS 通用)
sudo du -xh -d 1 / | sort -h | tail最大的几个顶层目录
macOS/BSD: macOS 的 du 有 -d,但没有 --max-depth。
sudo ncdu -x /用方向键浏览,按 d 删除
安装方法:apt install ncdu / dnf install ncdu。
lsblk磁盘、分区、大小、挂载点
lsblk -f哪个分区是 ext4/xfs,以及它的 UUID
macOS/BSD: macOS:diskutil list。
sudo blkid /dev/sdb1UUID 和 TYPE,用于 /etc/fstab
findmnt挂载树及挂载选项
findmnt -T /var/lib/docker这个路径位于哪个文件系统
sudo findmnt --verify重启前检查 /etc/fstab 是否有错误
sudo mount /dev/sdb1 /mnt/usb挂载 U 盘(目录必须已存在)
sudo mount -o remount,rw /把只读的根分区改为可写
sudo mount -t nfs nas:/export /mnt/nas挂载 NFS 共享
sudo umount /mnt/usb执行后即可安全拔出
sudo umount -l /mnt/nas延迟卸载:立即分离,不再占用时再清理
“target is busy”表示有进程(往往是停留在该目录中的你自己的 shell)正在使用它:用 fuser -vm 或 lsof 找出来。
UUID=3f6c... /data ext4 defaults,nofail 0 2每个文件系统一行;nofail 让磁盘缺失时也能继续开机
sudo mount -a立即挂载 fstab 中的所有条目:重启前先测试
fstab 中的一个笔误就可能让下次开机进入紧急模式。编辑后务必运行 sudo mount -a(或 findmnt --verify)。
sudo fdisk -l所有磁盘及其分区
sudo parted /dev/sdb print分区表类型(gpt/msdos)和布局
危险: 写入分区表(fdisk 中的 w、parted 中的 mklabel)会让该磁盘上的现有数据无法访问。请先用 lsblk 确认设备名;/dev/sda 和 /dev/sdb 很容易对调。
sudo mkfs.ext4 -L data /dev/sdb1带卷标的 ext4
sudo mkfs.vfat -F 32 /dev/sdc1FAT32 格式,让其他设备也能读取 U 盘
危险: 会立即擦除目标上的文件系统,如果设备未挂载则不会有任何确认。请用 lsblk -f 核对设备;把 /dev/sda1 错写成 /dev/sda,或者选错磁盘,都会毁掉整块磁盘的数据。
sudo fsck -f /dev/sdb1强制完整检查一个未挂载的分区
危险: 切勿对以读写方式挂载的文件系统运行 fsck:可能会损坏它。请先卸载;如果是根文件系统,请从救援介质启动。
sudo dd if=ubuntu.iso of=/dev/sdX bs=4M status=progress conv=fsync制作可启动 U 盘(把 sdX 换成整块磁盘,而不是分区)
dd if=/dev/zero of=test.img bs=1M count=100创建一个 100 MB 的文件
危险: dd 会不加询问地覆盖 of= 指定的目标。把 if= 和 of= 写反,或者选错 /dev/sdX,都会抹掉那块磁盘。运行前用 lsblk 再确认一次。
macOS/BSD: macOS:先执行 diskutil unmountDisk,再以 /dev/rdiskN(来自 diskutil list)为目标,使用 bs=4m,按 Ctrl+T 查看进度。
sync && sudo umount /mnt/usb拔出 U 盘之前
swapon --show当前的交换空间
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile添加 2 GB 交换文件(写入 /etc/fstab 才能永久生效)
在 Btrfs 上创建交换文件需要额外步骤(较新的 btrfs-progs 中使用 btrfs filesystem mkswapfile)。
shred -u -n 3 secrets.txt覆写三次后删除
危险: 不可逆。另请注意,它在 SSD、日志型或写时复制文件系统(Btrfs、ZFS)以及任何带快照的存储上并不可靠;真正的保护请使用全盘加密。
IP 地址、路由、开放端口、HTTP 请求、DNS、SSH 和文件传输。
ip -br a每个网卡一行:名称、状态、地址
ip a show eth0查看单个网卡的详细信息
hostname -I只显示 IP 地址
macOS/BSD: macOS:ifconfig,或 ipconfig getifaddr en0。
ip 取代了旧的 ifconfig(net-tools),很多发行版已不再默认安装后者。
ip r路由;“default via”后面就是网关
ip route get 1.1.1.1访问某个目标时使用哪个网卡和网关
sudo ip route add 10.20.0.0/16 via 192.168.1.1添加路由(重启后失效)
ip link网卡和 MAC 地址
sudo ip link set eth0 down && sudo ip link set eth0 up重启某个网卡
危险: 停用你通过 SSH 连接所用的网卡会切断当前会话。
sudo ss -tulpn所有监听端口及对应程序
ss -tn state established '( dport = :443 )'到 443 端口的已建立连接
ss -s连接总数
macOS/BSD: macOS:lsof -iTCP -sTCP:LISTEN -n -P,或 netstat -an。
ss 取代了 netstat;装有 net-tools 的系统上 netstat -tulpn 仍然可用。
curl -I https://example.com状态行和响应头
curl -LO https://example.com/file.tar.gz下载文件,并跟随重定向
curl -s -o /dev/null -w '%{http_code}\n' https://example.com只看状态码
curl -fsSL https://example.com/install.sh -o install.sh先下载脚本,看过再运行
curl -H 'Content-Type: application/json' -d '{"name":"Ada"}' https://api.example.com/usersPOST JSON
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/me使用双引号,$TOKEN 才会被展开
curl -X DELETE https://api.example.com/users/42其他请求方法
wget -c https://example.com/big.iso断线后继续下载
wget -qO- https://example.com/data.json | jq .直接通过管道交给另一个命令
macOS/BSD: macOS 默认没有;请用 curl -LO(续传用 curl -C - -LO)。
dig +short example.com只看 A 记录
dig MX example.com邮件服务器
dig @1.1.1.1 example.com向指定的解析服务器查询(绕过本地缓存)
dig -x 8.8.8.8反向解析
dig +trace example.com从根服务器开始跟踪委派过程
软件包名:dnsutils(Debian/Ubuntu)或 bind-utils(Fedora/RHEL)。
host example.com一个简短回答中包含 A、AAAA 和 MX
nslookup example.com 8.8.8.8Windows 上也有同样的命令
resolvectl status各网卡的 DNS 服务器
sudo resolvectl flush-caches清除 systemd-resolved 缓存
macOS/BSD: macOS:sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder。
仅适用于使用 systemd-resolved 的系统(Ubuntu、Fedora 默认使用)。
ping -c 4 example.com发送四个数据包,然后显示汇总
在 Linux 和 macOS 上,除非加 -c,ping 会一直运行到按下 Ctrl+C 为止(Windows 发送 4 次后停止)。没有回应并不一定代表主机宕机:很多主机会屏蔽 ICMP。
traceroute -n example.com显示各跳,不做 DNS 解析
tracepath example.com无需 root,还会报告 MTU
macOS/BSD: macOS 有 traceroute,但没有 tracepath。
Linux 上可能需要另行安装 traceroute;tracepath(iputils)通常已自带。
mtr -rw -c 100 example.com每跳探测 100 次后输出报告
结合了 ping 和 traceroute。如果只有中间某一跳丢包,通常是该路由器降低了 ICMP 的优先级;一直持续到终点的丢包才是真正的丢包。
ssh alice@203.0.113.10登录
ssh -p 2222 alice@host非标准端口
ssh alice@host 'df -h'执行一条命令后返回
ssh -J bastion.example.com alice@10.0.0.5通过跳板机中转
ssh -N -L 5432:localhost:5432 alice@db-host用本地数据库客户端连接远程 Postgres
ssh -N -D 1080 alice@host通过服务器上网浏览
ssh-keygen -t ed25519 -C "you@example.com"在 ~/.ssh 中生成新的密钥对
ssh-copy-id alice@host把你的公钥追加到服务器的 authorized_keys
ssh-keygen -R host服务器重装后删除旧的主机密钥(“REMOTE HOST IDENTIFICATION HAS CHANGED”)
Host web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519之后只需:ssh web(scp 和 rsync 也会使用它)
scp report.pdf alice@host:/tmp/上传
scp alice@host:/var/log/app.log .下载
scp -r -P 2222 site/ alice@host:~/通过其他端口上传文件夹
自 OpenSSH 9.0 起,scp 底层改用 SFTP 协议。大量或重复复制时 rsync 更快,因为它只传输变化的部分。
rsync -avzP site/ deploy@host:/srv/site/site/ 末尾的斜杠表示复制其内容,而不是文件夹本身
rsync -av --exclude 'node_modules' ./ /backup/app/本地备份,排除无用文件
macOS/BSD: 较新的 macOS 自带 openrsync 而不是 rsync;常用选项可用,部分少见选项不支持。
src/ 表示“src 中的内容”;不带斜杠的 src 表示“src 这个文件夹”。弄错的话会多套一层文件夹(dest/src/…)。
rsync -avn --delete site/ /srv/site/先演练:以“deleting”开头的行就是会被删除的内容
rsync -av --delete site/ /srv/site/然后正式运行
危险: 会删除 dest 中所有 source 里没有的内容。把源和目标写反,或者源路径为空或写错,都会清空目标。务必先加 -n 运行一次。
nc -zv db.internal 5432结果为“succeeded”,或“Connection refused”/超时
nc -l 9000在端口上监听,从另一端测试防火墙
不同版本的 netcat 选项不同:传统版本需要写成 nc -l -p 9000。
sudo ufw status verbose规则和默认策略
sudo ufw allow 22/tcp放行 SSH(在 enable 之前执行)
sudo ufw allow from 10.0.0.0/8 to any port 5432只对一个网段开放一个端口
危险: 在远程服务器上,如果没有先放行 SSH(ufw allow OpenSSH 或 22/tcp)就执行 sudo ufw enable,你会把自己锁在外面。
sudo firewall-cmd --list-all当前区域和规则
sudo firewall-cmd --permanent --add-service=https && sudo firewall-cmd --reload永久开放 HTTPS
sudo firewall-cmd --permanent --add-port=8080/tcp开放端口
不加 --permanent 的规则只在下次重新加载或重启前有效。
nmcli device status网卡及其连接状态
nmcli device wifi list附近的网络
nmcli device wifi connect 'MyWiFi' password 'secret'连接到网络
同一任务在四大包管理器中的写法:Debian/Ubuntu(apt)、Fedora/RHEL(dnf)、Arch(pacman)、openSUSE(zypper)。凡是会改动系统的操作,请在前面加上 sudo。
| 任务 | apt(Debian、Ubuntu) | dnf(Fedora、RHEL) | pacman(Arch) | zypper(openSUSE) |
|---|---|---|---|---|
| 刷新软件包列表 # 元数据过期时 dnf 会自动刷新。在 Arch 上,切勿先运行 pacman -Sy 再运行 -S pkg:官方不支持部分升级,请使用 -Syu。 | apt update | dnf makecache | pacman -Sy | zypper refresh |
| 升级所有软件包 # openSUSE Tumbleweed 使用 zypper dup。apt full-upgrade 在必要时还会删除软件包以完成升级。 | apt update && apt upgrade | dnf upgrade | pacman -Syu | zypper update |
| 安装软件包 # | apt install nginx | dnf install nginx | pacman -S nginx | zypper install nginx |
| 安装下载好的软件包文件 # ./ 告诉 apt 这是一个文件而不是包名,这样依赖会被自动解决(dpkg -i 不会)。 | apt install ./app.deb | dnf install ./app.rpm | pacman -U app.pkg.tar.zst | zypper install ./app.rpm |
| 卸载软件包 # | apt remove nginx | dnf remove nginx | pacman -R nginx | zypper remove nginx |
| 卸载并删除配置文件 / 无用依赖 # | apt purge nginx && apt autoremove | dnf remove nginx && dnf autoremove | pacman -Rns nginx | zypper remove --clean-deps nginx |
| 搜索软件包 # | apt search keyword | dnf search keyword | pacman -Ss keyword | zypper search keyword |
| 查看软件包详情 # | apt show nginx | dnf info nginx | pacman -Si nginx (installed: -Qi) | zypper info nginx |
| 列出已安装的软件包 # | apt list --installed | dnf list --installed | pacman -Q | zypper search --installed-only |
| 列出可用更新 # | apt list --upgradable | dnf check-update | checkupdates (pacman-contrib) | zypper list-updates |
| 查询文件属于哪个软件包 # 对于尚未安装的文件:dnf provides /path、apt-file search path(需要安装 apt-file)、pacman -F path。 | dpkg -S /usr/bin/curl | rpm -qf /usr/bin/curl | pacman -Qo /usr/bin/curl | rpm -qf /usr/bin/curl |
| 列出软件包安装的文件 # | dpkg -L nginx | rpm -ql nginx | pacman -Ql nginx | rpm -ql nginx |
| 锁定软件包的当前版本 # 在 DNF 4 上,versionlock 需要安装 versionlock 插件包。 | apt-mark hold nginx | dnf versionlock add nginx | IgnorePkg = nginx in /etc/pacman.conf | zypper addlock nginx |
| 清理软件包缓存 # | apt clean | dnf clean all | pacman -Sc | zypper clean |
你是谁、谁已登录,以及账户管理。
iduid、gid 以及你所属的每个组
id alice其他用户
w谁在线以及正在运行什么
last -n 10最近的登录和重启记录
sudo lastb -n 10最近的登录失败记录(Linux)
sudo useradd -m -s /bin/bash alice && sudo passwd alice创建用户并设置密码
在 Debian/Ubuntu 上,adduser alice 是更友好的交互式封装,会设置好主目录和密码。
sudo usermod -aG docker alice让 alice 可以运行 docker
sudo usermod -aG sudo alice在 Debian/Ubuntu 上授予管理员权限(在 Fedora/RHEL/Arch 上该组是 wheel)
危险: 不加 -a 时,usermod -G 会替换该用户的所有附加组,可能导致失去 sudo 权限。组的变更在下次登录时生效(或运行 newgrp docker)。
sudo userdel -r olduser同时删除主目录和邮件池
危险: -r 会永久删除主目录及其中的文件。请先备份,或者改为锁定账户(passwd -l)。
passwd修改自己的密码
sudo passwd alice重置他人的密码
sudo passwd -l alice锁定密码登录(SSH 密钥可能仍然有效)
sudo groupadd developers新建用户组
sudo gpasswd -d alice developers把 alice 移出该组
groups alicealice 所属的组
getent group sudosudo 组的成员(也适用于 LDAP)
getent passwd alice账户条目:UID、主目录、shell
sudo visudo -f /etc/sudoers.d/deploy每条规则单独一个文件
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp免密码执行某一条命令
visudo 会在保存前检查语法。用普通编辑器修改 /etc/sudoers 时一旦写错,所有人都可能无法使用 sudo。
sudo chage -l alice上次修改日期和过期日期
sudo chage -M 90 alice每 90 天过期
tar、gzip、xz、zip 和校验和。
tar -czf site-2026-10-18.tar.gz site/把文件夹打包为 gzip 压缩归档
tar -cJf logs.tar.xz --exclude='*.tmp' logs/更小的 xz 归档,跳过临时文件
tar -xf archive.tar.gzGNU tar 和 macOS tar 会自动识别压缩格式
tar -xzf app.tar.gz -C /opt/app --strip-components=1解压到某个文件夹,并去掉外层包装目录
tar -tf backup.tar.gz | less不解压直接查看里面有什么
tar -xf backup.tar.gz etc/nginx/nginx.conf提取单个文件(路径以 -t 显示的为准)
tar --zstd -cf data.tar.zst data/比 xz 快得多,压缩率与 gzip -9 相当或更好
zstd -d file.zst解压单个文件
需要 GNU tar 1.31+(或较新的 bsdtar)以及 zstd 程序。
gzip -k access.log生成 access.log.gz,保留原文件
zcat access.log.gz | grep 404不解压到磁盘直接读取
zgrep 500 access.log.*.gz直接在轮转后的日志中 grep
不加 -k 时,gzip 会用 .gz 版本替换原文件。
xz -T0 -k big.sql使用所有 CPU 核心,保留原文件
unxz big.sql.xz解压
zip -r site.zip site/压缩文件夹
zip -r site.zip site/ -x '*.git*' '*/node_modules/*'排除路径
zip -e 使用的是老旧且安全性弱的 ZipCrypto 加密。真正需要保密请使用 7z 或 gpg。
unzip files.zip -d files/解压到某个文件夹
unzip -l files.zip只列出内容
unzip -o files.zip不提示直接覆盖
7z x archive.7z按完整路径解压
7z a -p backup.7z docs/AES-256 加密压缩包(会提示输入密码)
7z l archive.rar列出多种格式压缩包的内容
软件包:Debian/Ubuntu 上为 p7zip-full / 7zip,Fedora/Arch 上为 p7zip 或 7zip。
sha256sum ubuntu.iso与下载页面上的哈希值对比
sha256sum -c SHA256SUMS --ignore-missing检查清单中列出、且你确实拥有的每个文件
macOS/BSD: macOS:shasum -a 256 file(以及 shasum -a 256 -c SUMSFILE)。
split -b 100M backup.tar.gz backup.part.backup.part.aa、.ab……
cat backup.part.* > backup.tar.gz重新合并
按名称、时间或大小查找文件,以及在文件中查找文本。
find . -name '*.log'给模式加上引号,以免被 shell 提前展开
find / -iname 'nginx.conf' 2>/dev/null全盘搜索,并隐藏权限错误
find . -maxdepth 1 -type d直接子目录
find . -type l -xtype l失效的符号链接(GNU)
find . -type f -empty空文件
find /var/log -type f -mtime +30超过 30 天的日志
find . -type f -mmin -15最近 15 分钟内有哪些变化
sudo find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null根文件系统上超过 500 MB 的文件
find . -name '*.sh' -exec chmod +x {} +{} + 会一次把多个文件传给命令(速度快)
find . -name '*.py' -exec grep -l 'TODO' {} +哪些 Python 文件包含 TODO
find . -name '*.jpg' -print0 | xargs -0 -P4 -n 20 jpegoptim并行处理,文件名带空格也安全
find /tmp/app -name '*.tmp' -mtime +7 -print第 1 步:列出匹配的文件
find /tmp/app -name '*.tmp' -mtime +7 -delete第 2 步:同一条命令,把 -delete 放在末尾
危险: 顺序很重要:-delete 写在哪里就在哪里执行,所以 find . -delete -name "*.tmp" 会在名称条件生效之前就删光 . 下的所有内容。请把 -delete 放在最后,并先用 -print 运行一次。
find /srv -type f -perm -o+w所有人可写的文件
sudo find / -xdev -perm -4000 -type f 2>/dev/nullsetuid 程序
locate -i nginx.conf比 find / 快得多
sudo updatedb立即刷新索引
由 plocate 或 mlocate 提供;索引每天重建一次,所以当天新建的文件在 updatedb 运行前可能搜不到。
grep -n 'ERROR' app.log带行号的匹配行
grep -v '^#' nginx.conf | grep -v '^$'去掉注释和空行后的配置
grep -c 'Failed password' /var/log/auth.log统计 SSH 登录失败次数
grep -rn 'TODO' src/所有 TODO 及其所在文件和行号
grep -rl --include='*.php' 'mysql_connect' .哪些 PHP 文件还在使用旧 API
grep -rn --exclude-dir={.git,node_modules} 'apiKey' .跳过干扰的文件夹
grep -C 3 'Traceback' app.log前后各 3 行
grep -A 20 'Exception' app.log错误后面的堆栈跟踪
grep -E 'error|warn' app.log匹配任一单词(扩展正则)
grep -Eo '[0-9]{1,3}(\.[0-9]{1,3}){3}' access.log | sort | uniq -c | sort -rn | head日志中出现最多的 IP 地址
grep -P '\d{4}-\d{2}-\d{2}' filePerl 风格的 \d(GNU grep)
macOS/BSD: -E 在哪里都能用;-P(PCRE)是 GNU 特性,并非所有 macOS 版本都支持。
type ll告诉你它是别名、函数、内置命令还是文件
command -v docker >/dev/null || echo "docker missing"适合在脚本中使用的可移植检查
which -a python3PATH 中所有的 python3,按顺序列出
剪切、过滤、排序、计数、转换和重组文本与 JSON。
sed 's/http:/https:/g' links.txt输出结果;文件本身不变
sed 's|/usr/local|/opt|g' paths.txt可用任意分隔符,处理路径时很方便
sed -E 's/([0-9]+)px/\1rem/g' style.css复用捕获的分组
sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_configGNU sed
sed -i.bak 's/foo/bar/g' config.ini保留 config.ini.bak;GNU 和 macOS 通用
macOS/BSD: macOS 的 sed 要求 -i 后面带参数:sed -i '' 's/foo/bar/g' file。GNU sed 会把 '' 当作脚本,所以两边都能用的写法只有 -i.bak。
sed -n '100,120p' big.log第 100 到 120 行
sed '/^\s*#/d; /^$/d' app.conf去掉注释和空行(GNU \s)
sed -n '/BEGIN CERT/,/END CERT/p' bundle.pem两个标记之间的所有内容
awk '{print $1}' access.log第一列(客户端 IP)
awk -F: '{print $1, $7}' /etc/passwd用户和 shell
awk -F, 'NR>1 {print $2}' data.csvCSV 第二列,跳过表头(仅限简单 CSV:字段内不能有带引号的逗号)
awk '$9 >= 500' access.log第 9 个字段(状态码)为 5xx 的行
awk '{s += $2} END {print s}' sales.txt第 2 列求和
awk '{c[$1]++} END {for (k in c) print c[k], k}' access.log | sort -rn | head按值计数,取前 10 名
cut -d, -f1,3 data.csv第 1 列和第 3 列
cut -d: -f1 /etc/passwd所有用户名
cut -c1-10 file每行的前 10 个字符
cut 把每个分隔符都当作字段分界,所以两个空格就意味着中间有一个空字段。以空格对齐的输出请用 awk。
du -sh * | sort -h按大小排列文件夹
sort -t, -k3,3nr data.csv按第 3 列数值降序排列 CSV
sort -u emails.txt > unique.txt排序并去重
sort ips.txt | uniq -c | sort -rn | head出现频率最高的 10 行
uniq 只合并相邻的重复行,所以要先排序。
wc -l access.log行数
ls | wc -l当前文件夹中有多少项
grep -c '' file行数统计,包括末尾没有换行符的最后一行
tr 'a-z' 'A-Z' < in.txt转为大写
tr -d '\r' < windows.txt > unix.txt去掉 Windows 的 CRLF 换行符
tr -s ' ' < file压缩连续的空格
tr '\n' ',' < list.txt用逗号连接各行
tr 只读取标准输入,所以要用 < 把文件重定向进来。
find . -name '*.log' -print0 | xargs -0 rm -f安全删除找到的文件
cat urls.txt | xargs -n 1 -P 4 curl -sO每次同时下载 4 个
ls *.png | xargs -I {} cp {} /backup/{}每项执行一次命令
macOS/BSD: 即使输入为空,GNU xargs 也会运行一次命令,除非加上 -r;macOS xargs 默认跳过空输入,并为兼容性接受 -r。
jq . response.json美化输出
jq -r '.items[].name' data.json每行一个名称
jq -r '.[] | select(.active) | .email' users.json先筛选,再取某个字段
curl -s https://api.github.com/repos/jqlang/jq | jq '.stargazers_count'直接处理 API 返回的数据
用 apt/dnf install jq 安装。较新的 macOS 已自带。
paste -sd, ids.txt所有行用逗号连接
paste names.txt emails.txt两个文件并排成两列
comm -12 <(sort a.txt) <(sort b.txt)两边都有
comm -23 <(sort a.txt) <(sort b.txt)只在 a.txt 中
seq 1 51 到 5,每行一个
seq -w 1 10补零:01 … 10
for i in $(seq 1 3); do echo "run $i"; done循环计数器
printf '%s' 'user:pass' | base64编码(用 printf 可避免末尾多出换行符)
echo dXNlcjpwYXNz | base64 -d解码
base64 -w 0 image.png > image.b64不换行(GNU 默认每 76 个字符换行)
macOS/BSD: macOS 的 base64 默认不换行,也没有 -w。解码用 -d(旧版 macOS 用 -D)。
iconv -f WINDOWS-1252 -t UTF-8 old.csv > new.csv修复 Excel 导出文件的乱码
iconv -l列出支持的编码
shuf -n 1 names.txt随机一行
shuf -i 1-100 -n 5从 1 到 100 中随机取五个数
systemd 服务:启动、停止、设置开机自启,以及用 journalctl 查看日志。
systemctl status nginx状态、PID、内存和最近几行日志
systemctl is-active --quiet nginx && echo up用于脚本
sudo systemctl restart nginx完全重启
sudo systemctl reload nginx重新读取配置而不断开连接(如果服务支持)
尽量在重启前先测试配置,例如 sudo nginx -t,以免一个笔误就让网站宕掉。
sudo systemctl enable --now docker设为开机自启并立即启动
sudo systemctl disable --now cups立即停止并取消开机自启
sudo systemctl mask bluetooth彻底禁止它被启动(用 unmask 撤销)
systemctl --failed哪些出了问题
systemctl list-units --type=service --state=running哪些正在运行
systemctl list-unit-files --state=enabled哪些开机自启
sudo systemctl edit nginx以附加配置覆盖,软件包升级后依然保留
systemctl cat nginx单元文件及其所有覆盖配置
sudo systemctl daemon-reload手动编辑单元文件后需要执行
[Unit]
Description=My app
After=network.target
[Service]
User=app
WorkingDirectory=/srv/app
ExecStart=/srv/app/bin/server
Restart=on-failure
[Install]
WantedBy=multi-user.target然后:sudo systemctl daemon-reload && sudo systemctl enable --now myapp
journalctl -u nginx -f跟踪单个服务
journalctl -u myapp --since '10 min ago'最近一段时间
journalctl -b -1 -p err崩溃前那次启动中的错误
journalctl --disk-usage日志占用了多少空间
sudo journalctl --vacuum-size=500M已归档日志最多保留 500 MB
sudo journalctl --vacuum-time=14d删除两周前的已归档日志
要设置永久上限,请在 /etc/systemd/journald.conf 中设置 SystemMaxUse=。
sudo tail -f /var/log/syslogDebian/Ubuntu 上的通用日志(Fedora/RHEL 上是 /var/log/messages)
sudo tail -f /var/log/auth.logDebian/Ubuntu 上的登录和 sudo 记录(RHEL 上是 /var/log/secure)
部分发行版(Fedora、Arch)在未安装 rsyslog 时只把日志保存在 journal 中。
sudo reboot立即重启
sudo shutdown -r +10 'Kernel update'10 分钟后重启,并通知已登录的用户
sudo shutdown -c取消已计划的关机
sudo shutdown -h now关机
按计划运行命令,或稍后运行一次。
crontab -e在 $EDITOR 中打开你的 crontab
crontab -l列出 crontab
crontab -l > crontab.bak备份 crontab
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1每天 02:30 运行,保留输出
*/15 * * * * /usr/local/bin/check.sh每 15 分钟
0 9 * * 1-5 /usr/local/bin/report.sh周一至周五 09:00
@reboot /usr/local/bin/startup.sh开机时运行一次
cron 运行时 PATH 很精简,也不加载 shell 配置文件:请使用绝对路径。命令中的 % 必须转义为 \%。
crontab -l > ~/crontab.bak && crontab -r删除前先备份
crontab ~/crontab.bak从文件恢复
危险: 会不加提示地删除你的所有 cron 任务,而且键盘上 r 就挨着 e。部分 cron 实现提供 -i 选项,删除前会先询问(crontab -ri)。
0 3 * * * root /usr/local/bin/cleanup.sh/etc/cron.d/cleanup 中的一行:注意多出的用户字段
ls /etc/cron.daily/由 run-parts 每天运行一次的脚本
在 Debian 和 Ubuntu 上,/etc/cron.d 中文件名带点的文件会被忽略,所以请命名为 backup,而不是 backup.cron。
echo 'systemctl restart myapp' | sudo at 02:00今晚凌晨 2 点
echo './report.sh' | at now + 30 minutes半小时后
atq待执行的任务
atrm 3取消任务 3
需要安装 at 软件包并运行 atd 服务。
systemctl list-timers所有定时器及其下次触发时间
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.targetbackup.timer 放在 backup.service 旁边;Persistent 会在停机后补上错过的运行
systemd-analyze calendar 'Mon..Fri 09:00'查看 OnCalendar 表达式的含义
sleep 5 && curl -s localhost:8080/health给服务留出启动时间
sleep 2mGNU 和当前的 macOS 都支持时间单位后缀
管道、重定向、通配符、变量、历史记录,以及最省时间的快捷键。macOS 默认使用 zsh:这里的内容几乎都适用,只有 shopt、help 和 bash 4 的特性除外(macOS 自带的是 bash 3.2)。
ps aux | grep nginx过滤列表
history | grep 'docker run'查找以前运行过的命令
set -o pipefail在脚本中:管道中任何一部分失败都算失败,而不只看最后一个
ls -l > listing.txt覆盖(文件不存在则创建)
echo 'done' >> progress.log追加
set -o noclobber让 > 拒绝覆盖已有文件(>| 强制覆盖)
shell 会在命令运行前清空文件,所以 sort file > file 只会得到一个空文件。请先写入新文件名,再用 mv。
find / -name x 2>/dev/null丢弃错误信息
./build.sh > build.log 2>&1输出和错误写入同一个文件(顺序很重要:先 >,再 2>&1)
./build.sh &> build.logbash 中的等效简写
mysql mydb < dump.sql文件作为输入
cat > config.yml <<'EOF'
port: 8080
host: $HOST stays literal
EOF给 'EOF' 加引号后,$变量 不会被展开
grep -c a <<< "banana"here-string
make && sudo make install只有构建成功才安装
cd /srv/app || exit 1cd 失败时终止脚本
(cd frontend && npm run build)圆括号表示子 shell,所以当前目录不会改变
echo "Today is $(date +%A)"命令替换
echo $(( 1024 * 4 ))整数运算
diff <(ls dir1) <(ls dir2)进程替换:把输出当作临时文件
反引号 `command` 是 $(command) 的旧写法;$( ) 可以嵌套,可读性也更好。
ls *.jpg当前文件夹中的所有 JPG
rm photo-??.pngphoto-01.png … photo-99.png
cp config.{yml,yml.bak}花括号展开:cp config.yml config.yml.bak
shopt -s globstar; ls **/*.md** 匹配任意深度(bash 4+)
通配符默认不匹配以点开头的文件(shopt -s dotglob 可改变这一点)。如果没有匹配项,bash 会原样传递模式,除非设置了 shopt -s nullglob。
echo 'Cost: $5'单引号:什么都不展开
echo "Home is $HOME"双引号:变量会展开,空格会保留
cp "$file" "$dest/"存放路径的变量一定要加引号:不加引号时遇到空格就会出错
name="Ada"; echo "Hi $name"设置并使用
echo "${PORT:-8080}"未设置或为空时使用默认值
file=report.tar.gz; echo "${file%%.*}" "${file##*/}"去掉扩展名 / 去掉目录
echo "${#name}"字符串长度
export NODE_ENV=production对从当前 shell 启动的所有程序可见
DEBUG=1 ./app只对这一条命令生效
printenv | sort列出环境变量
unset DEBUG删除变量
shell 退出后就会失效。要永久保留,请把 export 写入 ~/.bashrc(交互式 shell)或 ~/.profile(登录 shell)。
echo "$PATH" | tr : '\n'每行一个条目
export PATH="$HOME/.local/bin:$PATH"把你自己的 bin 文件夹加到最前面(写入 ~/.bashrc)
hash -r移动可执行文件后清除缓存的命令位置
alias ll='ls -alF'写入 ~/.bashrc 以永久保留
source ~/.bashrc不开新终端即可应用更改(等同于 . ~/.bashrc)
\ls绕过别名,运行真正的 ls
grep -q root /etc/passwd; echo $?0 表示找到,1 表示没找到,2 表示出错
set -euo pipefail放在脚本开头:遇到错误、未设置的变量或失败的管道时停止
sudo !!用 sudo 重新运行上一条命令
cd !$使用上一条命令的最后一个参数
!42重新运行历史记录中的第 42 条
^foo^bar把上一条命令中的 foo 替换为 bar 后重新运行
设置 HISTCONTROL=ignorespace 后(Ubuntu 默认的 ignoreboth 已包含它),以空格开头输入的命令不会被保存:适合含有密码等机密信息的命令。
bind -P | less列出所有按键绑定
man rsync完整手册;按 / 搜索,按 q 退出
man 5 crontab第 5 节:文件格式,而不是命令
help cdbash 内置命令没有单独的 man 手册页
apropos partition哪些命令提到了某个词
#!/usr/bin/env bash
set -euo pipefail
name="${1:-world}"
if [[ -f "$name.txt" ]]; then
echo "found $name.txt"
fi
for f in *.log; do
echo "$f"
done参数、条件测试和循环
chmod +x script.sh && ./script.sh Ada设为可执行并运行
bash -x script.sh运行时逐行跟踪
$1 … $9 是参数,"$@" 是全部参数,$# 是参数个数。[[ ]] 是 bash 语法;POSIX sh 脚本请用 [ ]。
reset用 cat 查看二进制文件后终端一直输出乱码时使用
发现问题,或者觉得哪里可以更好?每条消息我们都会阅读,并尽快修复。
这份 Linux 命令速查表按你要完成的工作对 200 多条命令进行分类:目录切换和文件管理、权限、进程、磁盘空间、网络、软件包、用户、压缩归档、搜索、文本处理、systemd 服务和日志、cron,以及把这些串联起来的 bash 基础。每个条目都给出语法、你真正会用到的参数(附一行说明)、可复制的示例,并在必要时给出警告。可以按任务(“free disk space”、“what is using port 8080”)或命令名搜索,也可以直接链接到任意条目。
参数说明依据 GNU coreutils、util-linux、procps-ng、iproute2、systemd 和 bash 的手册,这也是 Ubuntu、Debian、Fedora、RHEL、Arch 和 openSUSE 所附带的工具。macOS 行为不同的地方会用蓝色注释说明,因为 sed -i、date -d、stat -c 和 xargs 正是在一个系统上写的脚本到另一个系统上就出错的经典位置。它覆盖的是常用的 90%,不能替代 man 手册:对于不常用的选项,man <command> 仍然是权威。
先从目录切换和文件操作开始:pwd、ls、cd、mkdir、cp、mv、rm、cat 和 less。然后是 man(帮助)、sudo,用于搜索的 grep 和 find,用于权限的 chmod 和 chown,用于进程的 ps、top 和 kill,用于磁盘空间的 df 和 du,以及用于远程机器的 ssh 和 scp。尽早学会管道(|)和重定向(> 和 >>),因为它们能把其他所有命令组合起来。
运行 df -h,以易读的单位查看每个已挂载文件系统的剩余空间。要找出是什么占用了空间,在目录中运行 du -h -d 1 | sort -h:它会列出各子目录,最大的排在最后。如果 df 显示磁盘已满,而 du 却找不到什么,那很可能是某个已删除的文件仍被进程打开着;sudo lsof +L1 可以列出这些文件。
运行 sudo ss -tulpn,列出所有正在监听的 TCP 和 UDP 端口及其所属程序,或用 sudo lsof -i :8080 查看单个端口。sudo 很关键:不加它,你只能看到自己进程的名称。ss 已取代 netstat,后者在安装了 net-tools 软件包的系统上仍然可用。
kill PID 发送 SIGTERM,请求进程退出,并让它完成清理工作:刷新文件、释放锁、关闭连接。kill -9 PID 发送 SIGKILL,由内核立即强制执行,进程无法捕获或忽略,因此不会进行任何清理。先用普通的 kill,等几秒钟,把 -9 留给那些不理会 SIGTERM 的进程。
macOS 自带的是 BSD sed,它的 -i 需要一个备份扩展名参数。在 macOS 上要写 sed -i '' 's/old/new/g' file;而在 Linux 的 GNU sed 上,同样的命令会失败,因为它会把 '' 当作脚本。两边都能用的写法是 sed -i.bak 's/old/new/g' file,它会保留一个备份副本,之后可以删除。
几乎都一样:核心工具在各处都来自相同的 GNU 和 util-linux 项目。不同的是软件包管理器(Debian 和 Ubuntu 用 apt,Fedora 和 RHEL 用 dnf,Arch 用 pacman,openSUSE 用 zypper,在“软件包”表格中并列展示)、部分日志文件路径、管理员组(sudo 还是 wheel)以及防火墙前端(ufw 还是 firewalld)。Alpine 和基于 BusyBox 的系统使用精简版工具,参数更少。
几乎所有破坏都出自少数几条命令:路径写错或为空的 rm -rf,指向错误磁盘的 dd 或 mkfs,作用于系统目录的 chmod -R 777 或 chown -R,源和目标写反了的 rsync --delete 或类似 robocopy 的镜像操作,把 crontab -e 打成 crontab -r,不带 -a 的 usermod -G,以及 -delete 放错位置的 find。速查表中每一条都标记为“危险”,并说明具体会怎样出错。
能避免大多数事故的习惯,是先运行无害的版本。执行 rm -rf 之前,先对同一路径运行 ls。执行 find … -delete 之前,先用 -print 运行同样的 find。执行 rsync --delete 之前,加上 -n 做一次试运行。执行 dd 或 mkfs 之前,运行 lsblk 并把设备名读两遍。在脚本中用 ${DIR:?} 而不是 $DIR,这样变量为空时脚本会中止,而不是把路径变成 /。
还有两个 shell 设置也有帮助:在脚本开头写 set -euo pipefail,遇到第一个错误就停止,而不是带着错误状态继续执行;set -o noclobber 则会让 > 拒绝覆盖已有文件。
macOS 是 Unix,但它的命令行工具来自 FreeBSD 而不是 GNU,这些差异恰恰会在你照搬 Linux 教程里的命令时暴露出来:
• sed -i 在 macOS 上需要一个参数(sed -i '' …);-i.bak 两边都能用。
• macOS 的 date 没有 -d;用 date -r <epoch> 转换时间戳,用 date -v-2d 表示相对日期。
• stat 使用 -f 和不同的格式字母,而不是 GNU 的 -c。
• macOS 上的 xargs 默认在输入为空时不执行命令,而 GNU xargs 除非加上 -r,否则仍会执行一次。
• du 在两边都支持 -d 1,但只有 GNU 接受 --max-depth;macOS 的 ps 没有 --sort(改用 ps aux -m 或 -r)。
• 原装 macOS 没有 head -n -5、tac、free、ip、ss、timeout 和 watch。
如果在 Mac 上需要 GNU 的行为,Homebrew 的 coreutils、gnu-sed 和 findutils 软件包会安装带 g 前缀的 GNU 版本(gsed、gdate、gstat、gxargs)。
ls -l 用十个字符显示权限,例如 -rwxr-x---。第一个字符是类型(- 文件,d 目录,l 链接);后面九个字符分为三组,分别是所有者、所属组和其他所有人的读、写和执行权限。换成数字,r 是 4,w 是 2,x 是 1,每组相加,所以 rwxr-x--- 就是 750。
常见权限:普通文件 644,目录和脚本 755,私钥和存放机密信息的文件 600,~/.ssh 这样的私有目录 700。对目录而言,x 表示“允许进入”,所以目录需要 x,而普通文件不需要。如果想在应用之前检查权限,chmod 计算器可以在符号形式和八进制形式之间换算。