跳转至

说明

本笔记只整理日常高频、值得背下来直接敲的命令——简单问题自己输命令,往往比给大模型描述需求再等它跑更快。 如果是有循环控制的脚本,就直接上python吧,你可能遇到bash和shell兼容性问题,shell版本问题,循环对象里后空格或回车,处理起来很痛苦。python语法简单,跨平台也好,除了稍微重一点,没什么缺点。

复杂的脚本逻辑语法不友好,没必要硬记,交给大模型写即可。

参考:《Linux 就是这个范儿》

文件与目录

命令 作用 常用参数
ls 列目录 -l 详情 -a 含隐藏 -t 按时间 -r 逆序 -h 人读大小;常用 -arlt:含隐藏+详情,按时间排、最新在最后
cd 切目录 cd - 回上一个 cd ~ 回家
cp 复制 -rf 强制递归覆盖;-a 忠实复制(= -r+保属性+保链接,备份首选);软链接 -a 保留、-rL 解开成实体
mv 移动/改名 -f 强制覆盖
rm 删除 -rf 强制递归(最常用)
mkdir 建目录 -p 连父目录一起建
touch 建空文件/改时间戳
ln 链接 ln 硬链接;ln -s 软链接
tree 树形看目录 -L 2 限深 -d 只目录

链接:硬链接不能跨磁盘/分区、不能链目录;跨磁盘用软链接 ln -s

  • cp 目录嵌套坑:目标已是目录时 cp -r dirA dirB 会偷偷变成 dirB/dirA。通用解法 cp dirA/. dirB——把 dirA 的内容直接放进 dirB,dirB 存不存在、空不空都不嵌套。

查找与定位

find <dir> <条件> <动作>

  • find . -name "*.cpp" 按名(-iname 忽略大小写)
  • find . -type f 只文件(d 目录、l 链接)
  • find . -mtime -7 7天内改动(+7 7天前)
  • find . -size +100M 大于100M
  • find . -name "*.log" -delete 直接删
  • find . -name "*.c" -exec wc -l {} + 统计 .c 文件行数。{} + 批量喂给 wc、末尾给合计;\; 则逐文件跑、无合计(\; 必须转义,裸 ; 会被 shell 当命令分隔符截断;+ 不是特殊字符所以不转义)
  • find . -path '*.log' -o -path '*.xml' -type f -print : 在当前路径中查找文件,排除log和xml文件。-print让每一个文件占一行。
  • xargs:把前面命令的输出转成后面命令的参数——find 只管"找",算活交给 xargs 喂的命令: find . -type f | xargs md5sum 批量算 md5(文件名带空格用 find -print0 \| xargs -0:改用 NUL 当分隔符,避免 xargs 把空格拆成两个参数)

locate <关键词>:走索引库秒查(比 find 快),先 sudo updatedb 建索引。 which <cmd>:命令可执行文件路径。whereis <cmd>:命令 + man 路径。

文本查看

(文本处理见下方"文件处理"章;复杂正则/脚本见 [[shell 字符串]])

命令 作用
cat 输出全部
less 分页(/搜索 n下一个 q退出)
head -n 20 前20行
tail -n 20 后20行;tail -f 实时跟踪看日志
wc -l-w-c 字节
sort -n 数字序 -r 降序 -k2 按第2列
uniq 去重(先 sort);-c 计次数
diff a b 比较差异
  • 校验和:md5sum <file> / sha256sum <file>(验下载完整性、比对两文件是否一致);md5sum -c file.md5 核对

经典统计(历史命令 Top10): cut -d' ' -f1 ~/.bash_history \| sort \| uniq -c \| sort -nr \| head

grep 基础:

  • grep "str" <file>-E 扩展正则(+ ? { } | ( ) 不转义)-i 忽略大小写 -r 递归 -n 行号 -v 反向
  • -Ei 最常用组合(扩展正则+忽略大小写):grep -Ein "error|fail" <file>
  • -l 只列文件名 -c 计数
  • -5/-A 5/-B 5/-C 5:匹配行的前后5行/后5行/前5行/前后5行
  • --include="*.cpp" 限定类型;grep -Ei "obj" -rl ./ --include=*.{cpp,c} 找含某串的文件

文件处理

(cut/sed/awk 的日常高频用法;复杂多命令脚本、正则细节见 [[shell 字符串]])

cut — 按分隔符取列

  • -d':' 分隔符、-f1,6 取第 1、6 列;-c1-10 按字符位置取
  • cut -d':' -f1,6 /etc/passwd 取用户名和家目录

sed — 流编辑(替换/删行最常用)

  • 替换:sed 's/old/new/g' <file>g 每行全换,不加只换第一个)
  • 分隔符可换:s 后第一个字符就是分隔符,old/new 里含 /(如路径)时改用 |/# 免转义:sed 's|/usr/local/bin|/opt/bin|g'
  • 原地改:sed -i 's/old/new/g' <file>(GNU sed;macOS/BSD 要写成 sed -i '' ...
  • 删行:sed '/pattern/d' <file> 删匹配行;sed '5d' <file> 删第 5 行
  • 看指定行:sed -n '10,20p' <file> 只输出 10~20 行
  • 批量改:sed -i "s/old/new/g" $(grep -rl "old" .)

awk — 按列处理(取列/筛选/求和)

  • 取列:awk '{print $1, $3}' <file>$0 整行、$NF 最后列、NR 行号、NF 列数)
  • 指定分隔符:awk -F':' '{print $1}' <file>
  • 筛选:awk '$3 > 100' <file> 第 3 列大于 100 的行
  • 求和:awk '{sum += $1} END {print sum}' <file>

压缩与解压

tar 口诀:c 打包 / x 解包;z=gz j=bz2 J=xz;v 过程 f 文件名

  • tar -zcvf a.tar.gz dir/ 打 gz
  • tar -zxvf a.tar.gz 解 gz
  • tar -jxvf a.tar.bz2 解 bz2
  • tar -Jxvf a.tar.xz 解 xz
  • tar -zxvf a.tar.gz -C /tmp 解到指定目录

zip / unzip:

  • zip -r a.zip ./* 递归压缩
  • unzip -o -d /home a.zip -o 覆盖不问 -d 指定目录

gzip:gzip <file> 压、gzip -d <file>.gz 解(原地替换,源文件消失)。

7z:

  • 7z x <file> 解压(保留目录结构)
  • -y 全 yes 可覆盖 -p<pwd> 密码 -o<dir> 输出路径(与路径间无空格)

权限与所有者

chmod(r=4 w=2 x=1):

  • chmod 755 <file> → rwxr-xr-x
  • chmod +x <file> 所有人加执行
  • chmod u+x g-w o=r <file> 符号法(u 所有者 g 组 o 其他 a 全部)

chown user:group <file>-R 递归。umask 查/设默认权限掩码。

特殊位:SUID(4) 执行时获所有者权限(如 passwd);SGID(2) 获组权限;SBIT(1) /tmp 才有,只所有者和 root 能删。

用户与身份

  • whoami 当前用户;who / who am i 登录信息;id uid/gid/组
  • su 切到 root(要 root 密码);su - user 切到某用户并加载其环境
  • sudo <cmd> 以 root 跑(要自己密码);root 密码默认随机,sudo passwd 设置
  • passwd 改密码;useradd / userdel / usermod 增删改

相关文件:/etc/passwd /etc/group /etc/sudoers

磁盘与分区

  • df -h 总体用量;du -sh dir 某目录大小,du -h --max-depth=1 逐层看
  • lsblk 树形看块设备/分区;blkid 查分区 UUID/类型
  • mount -t <fs> <dev> <mnt> 挂载;umount <mnt> 卸载;mount -o loop x.iso /mnt 挂镜像
  • dd if=in of=out bs=1M 块复制(磁盘镜像/测速)
  • fsck 修复文件系统

开机挂载 /etc/fstabUUID=<id> <mnt> <fs> defaults <dump> <pass>

进程与任务

  • ps aux \| grep xxx 看进程;top / htop 实时
  • kill <pid> / kill -9 <pid> 强杀;killall <name> 按名杀
  • cmd & 后台跑;nohup cmd & 脱离终端继续跑
  • jobs 看后台;fg/bg 前后台切换
  • systemctl start/stop/status/restart <svc> 服务管理
  • free -h 内存;uptime 负载

网络

  • ip a / ifconfig 看网卡(ip 是新版)
  • ping hostcurl URL-O 下载 -I 只看头);wget URL
  • rsync -avz src/ dst/ 增量同步(远程写 user@host:dst/,走 ssh)
  • ss -tlnp / netstat -tlnp 看监听端口;nc / telnet host port 测连通
  • top: 小内存服务器上经常需要关注一下avail Mem字段值。

远程连接(ssh / scp)

  • 登录:ssh user@host;指定端口 ssh -p 2222 user@host
  • 生成密钥:ssh-keygen -t ed25519(生成 ~/.ssh/id_ed25519 + .pub,回车一路默认即可)
  • 免密登录:ssh-copy-id user@host(把本机公钥追加到对方 ~/.ssh/authorized_keys,之后免密)

主机别名 ~/.ssh/config(省得记 user/host/port),之后 ssh myserver 直接连:

Host myserver
    HostName 1.2.3.4
    User root
    Port 2222

传文件 scp

  • scp <file> user@host:/path 上传;scp user@host:/path <file> 下载
  • -r 传目录;端口用 大写 -P(注意 ssh 是小写 -p,别搞混)
  • 指纹变了连不上(服务器重装过):ssh-keygen -R host 清掉 known_hosts 旧记录

软件包

Debian/Ubuntu(apt):apt install/remove <pkg>apt update(更新列表)、apt upgradeapt search/show <pkg> RedHat/CentOS(yum/dnf):yum install / yum update 源码安装:./configure && make && sudo make install(先看 README)

系统信息

  • uname -a 内核;lsb_release -a 发行版
  • date "+%Y-%m-%d %H:%M:%S" 时间;date -d @<时间戳>
  • dmesg 内核日志;lscpu / lspci / lsusb 硬件

环境变量与配置

  • env 看所有;export VAR="x" 设(仅当前 shell);unset VAR
  • alias ll='ls -la' 别名;source ~/.bashrc 重载

配置文件加载顺序:

  • login shell:/etc/profile~/.bash_profile(→~/.bashrc
  • non-login shell:~/.bashrc
  • 个人定制(别名、PATH、提示符)放 ~/.bashrc;PATH 等登录变量放 ~/.bash_profile

终端效率

tmux(会话断网不掉):

快捷键 作用
Ctrl-b % 左右分屏
Ctrl-b " 上下分屏
Ctrl-b 方向键 切换窗格
Ctrl-b d 脱离(后台继续跑)
Ctrl-b x 关当前窗格
tmux a 重新接入会话

其它:

  • history 历史命令列表(history 20 最近 20 条);!n 跑第 n 条、!str 跑最近匹配 str 的
  • Ctrl-r 反向搜历史命令;!! 上一条;!$ 上一条最后参数
  • Ctrl-c 中断 Ctrl-z 挂起 Ctrl-d 退出/EOF Ctrl-l 清屏
  • clear 清屏;reset 彻底重置(会丢可搜索内容)
  • 终端内搜索:Ctrl+Shift+F

重定向与管道(基础)

  • cmd > <file> 输出到文件(覆盖);>> 追加
  • cmd 2> err.log 标准错误;> <file> 2>&1 合并标准输出和错误
  • cmd \| cmd2 管道;cmd \| tee f 同时输出屏幕和文件
  • /dev/null 黑洞:cmd > /dev/null 2>&1 静默运行

(exec、mkfifo 等高级用法见 [[shell 脚本]])

常见问题

  • Windows 换行符报错 /bin/bash^M: bad interpretersed -i 's/\r$//' <file>.sh
  • 软链接辨别:ls -l 开头是 l 且文件名后有 -> 指向
  • adb:adb shell md5sum /path
  • 终端 beep 提醒:echo -e "\a"
  • cp/mv 进度条:标准 cp/mv 没有,需装补丁版 advcpmv,再 alias:alias cp='advcp -g'alias mv='advmv -g'

常用工具学习

  • vim:https://www.vim-hero.com/lessons/intro-to-modes
  • vim book: NEIL D. Practical Vim: Edit Text at the Speed of Thought [EB/OL]. (无出版日期). PDF 电子文档.
  • git:https://learngitbranching.js.org/?locale=zh_CN

备注:手机 adb 里只能用 vi。电脑上 vi 可按方向键(上下左右),手机按方向键会乱码,只能用 jkl;Ctrl+F(下翻页)、Ctrl+B(上翻页)。 备注2: 手机中可以使用busybox,有root权限则安装,没如果则busybox调用box中的工具使用。 备注3:git和vim都是一开始只需要学会简单的命令即可,但越用会发现自己的需求越多,学的命令就越多了。尤其git,团队内的代码修改等会越发熟练。


=========== 老笔记,可查询,不记忆 ===========

awk(完整参考)

把文本当数据库处理,核心是"模式/动作对"。

awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]

  • -F fs:输入字段分隔符(-F:-F[:/]-F ':|,',特殊符 | 要写 \\|
  • -v var=val:定义变量;-f 脚本文件:从文件读程序
  • prog 形式 pattern1{action1} pattern2{action2}...
  • pattern:如 NF > 3$0 ~ /ABC/(可省成 /ABC/);支持 > < == >= <= !=~ !~&& ||
  • {action}; 分子语句;可省略→默认 print;模式与动作可各省一个,但不能都省

变量[A-Za-z_][A-Za-z_0-9]*。不成文约定——局部全小写、全局首字母大写、内置全大写。字符串务必加双引号 "",否则变成空变量、匹配总为真。

内置变量

变量 含义
$0 当前整行记录
$1..$n 各字段(最大 n = NF)
NF 字段数
NR 当前行号
FS 输入字段分隔符(默认空格,等价 -F
RS 输入记录分隔符(默认 \n
OFS 输出字段分隔符
ORS 输出记录分隔符

OFS 关键点:直接 print $0 不受 OFS 影响;改了某字段(如 $1=$1)触发 $0 重算,才会应用 OFS:

echo "A B C D" | awk '{ OFS=":"; print $1,$2,$3,$4 }'
echo "A B C D" | awk '{ OFS="\n"; print $0 }'        # 不受影响
echo "A B C D" | awk '{ OFS="\n"; $1=$1; print $0 }'  # 受影响
echo "A,B,C,D" | awk -F"," '{ print $1,$2,$3,$4 }'    # OFS 默认空格

字符串 / 数字互转

n=123; s="" n         # s="123"(数字拼进串)
s="123"; n = s + 0    # n=123(串 +0 转数字)

匹配~ 匹配、!~ 不匹配;推荐 [[:upper:]] 代替 [A-Z](跨语言更稳);, 表范围 NR==3, NR==5 等价 NR>=3 && NR<=5

三个特殊模式

  • BEGIN{}:读第一行前(初始化,常设 FS/OFS);{}:逐行;END{}:全部处理完后(统计/汇总)
awk '/^$/{i++} END{print i}' /etc/services                       # 数空行
ifconfig eth0 | awk 'BEGIN{FS="(addr:)|(Bcast:)"} NR==2{print $2}'

多模式:各"模式/动作对"各管各的、互不影响;若动作 B 前不是模式而是动作 A,则 B 套空模式(恒匹配)

awk ' $1 ~ "L" {print "xx" $0} $1 ~ "H" {print "yy" $0}' test.txt

内建函数 / 特殊语句

  • printprint $0 可缩写 print;结束前隐含输出 ORS(默认 \n
  • system(cmd):如 system("sort < " tmpfile)exit n:退出;next:跳过本行后续模式;nextfile:跳到下一文件

重定向:与 shell 不同,写文件后必须手动 close("file"),除非走 system()

可替代 cut / grep

sort file | awk 'Last != $0 {print} {Last = $0}'   # 去重(替代 sort|uniq)
awk '/p1|p2/' file                                 # 替代 grep

综合例cat in.txt | awk -F'GPIO|32|0000_0000h' -v OFS="\t\t" '$1=$1{print}' > out.txt

注:32 位 awk 最多耗 256M 内存会 core,换 64 位或 export LDR_CNTRL=MAXDATA=0x80000000

数据结构

变量与作用域

  • 函数里定义的变量默认是全局(整个 shell 进程有效);./ 跑的脚本拿不到父进程变量
  • export VAR → 子进程也能用(环境变量)
  • local VAR → 仅函数内(局部),很重要,但经常忘记设置。

数组declare -a,整数索引,可不声明)

arr=(a b c)
echo ${arr[0]}      # 第 0 个(从 0)
echo ${arr[@]}      # 全部
echo ${#arr[@]}     # 长度
[[ "${arr[@]}" =~ "b" ]]   # 是否含某元素
for e in "${arr[@]}"; do echo $e; done

关联数组 / mapdeclare -A,字符串索引,必须先声明

declare -A m=(["k1"]="v1" ["k2"]="v2")
echo ${m[$k]}       # 按 key 取值
echo ${!m[@]}       # 所有 key
echo ${m[@]}        # 所有 value
echo ${#m[@]}       # 长度
for k in "${!m[@]}"; do echo "$k = ${m[$k]}"; done

注:map 不能重复声明(会冲突),交互式 shell 慎用。

字符串

判断[ ] / [[ ]]):-n 非空、-z 为空、== 等、!= 不等;[[ ]]=~ 正则包含

参数扩展 ${} —— 删头尾(口诀:# 左、% 右;一个最小、两个最大)

写法 含义
${str##*/} 左起删最大 */(拿文件名)
${str#*/} 左起删最小 */
${str%/*} 右起删最小 /*(拿目录)
${str%%.*} 右起删最大 .*
${str:start:len} 截取(${str: -1} 取最后字符,空格不能少)
${str:-默认} 为空时用默认值
${#str} 长度

长度也可 echo -n str | wc -c

sed(基础见上方"文件处理")

  • 删前 N 字符 sed -r 's/.{4}//';删后 N 字符 sed -r 's/.{3}$//'
  • 删匹配串 sed 's/foo//g'
  • 转大写 sed 's/[a-z]/\u&/g';转小写 \l&
  • 去首尾空格 eval echo " A BC "

awk(基础见上方"文件处理")

  • -F fs 分隔符、-v var=val 变量、-f 脚本文件
  • 结构 模式{动作},多对空格分隔;模式可省(恒真)
  • 内置变量:$0 整行、$1..$n 字段、NF 字段数、NR 行号、FS/RS/OFS/ORS 分隔符
  • BEGIN{} 前、{} 逐行、END{} 后(常用于统计)
  • $1=$1 触发重算以应用 OFS

正则 / 通配符

  • grep -E 扩展正则:() [] \. ^ $ | + ? {}
  • POSIX 字符集 [[:upper:]] [[:digit:]](比 [A-Z] 稳,跨语言)
  • [[ ]] 里直接比较通配符不加引号,但 + ? . 不生效

IFS(内部字段分隔符,默认空格/制表/换行)

  • IFS=$'\n' 真·换行;IFS='\n' 是字符 \n
  • for 读含空格的行需先设 IFS,或用 while read

echo 颜色echo -e "\033[<属性>m文字\033[0m"

  • 字体 30~37(黑红绿黄蓝紫青白)、背景 40~47
  • 1 加粗 4 下划线 5 闪烁 7 反显

cut / expr

  • cut -d' ' -f1 按分隔符取列
  • expr length "abc" 长度;expr substr "abc" 2 2 截取;expr 1 + 2 算术

shell脚本

运行bash x.sh 非交互 / bash -i x.sh 交互 / source x.sh 当前 shell 执行 / exec 替换进程(PID 不变)

调试

  • sh -x x.sh 跟踪(展开变量)/ sh -n 只查语法 / sh -v 打印命令
  • 区域:set -xset +x

set 选项(脚本开头常用)

  • set -e 出错即退;set -u 用未定义变量即退;set -o pipefail 管道任一失败即失败;set -x 打印命令;set -o noclobber > 不覆盖已存在文件

参数

  • $0 脚本名、$1.. 参数、$# 个数
  • $@ 各自独立("$@" 保留参数边界)、$* 合成一串;$? 退出码、$$ PID、$! 后台 PID、$_ 上条最后参数
  • shift [n] 移位;${1:-默认} 默认值

比较 / 判断

  • 数字 -eq -ne -lt -le -gt -ge
  • 字符串 -n -z == !=[[ ]] 里还有 =~
  • 文件 -d 目、-f 常规、-e 存在、-r/-w/-x 权限、-s 非空、-L 软链、-S socket
  • [[ ]] 而非 [ ]&& || < > 不会报错

流程控制

if [[ ... ]]; then ...; elif ...; then ...; else ...; fi   # 括号两边必须空格
[[ a -le b ]] && echo a || echo b                          # 三元
case $x in 模式) cmd ;; *) cmd ;; esac
while [[ ... ]]; do ...; done
for i in a b c; do ...; done                # 或 for i in {1..100} / $(seq 1 20)
for ((i=0; i<n; i++)); do ...; done         # C 风格

函数

f() { return 21; }      # $? 取返回码(0~255)
f() { echo 100; echo 200; }
a=$(f)                  # 多返回值靠 echo + 捕获,a="100 200"

重定向 / 管道(基础见上方"重定向与管道")

  • fd:0 stdin、1 stdout、2 stderr;2>&1 合并、>& 不可拆
  • tee <file> 同时输出屏幕和文件
  • exec 3>file 持久重定向 fd;mkfifo 命名管道

其它

  • trap 'cmd' EXIT(退出前)/ ERR(出错)/ SIGINT(Ctrl-C)
  • exit 0 成功 / exit 1 失败
  • read 读一行(IFS=, 改分隔);echo -n 不换行、-e 转义

vim

vim ~/.vimrc下的配置文件

" 显示行号
set number

" tab缩进配置 C/C++开发常用
set tabstop=4
set shiftwidth=4
set softtabstop=4
set noexpandtab

" 关闭自动换行
set nowrap

粘贴cpp时缩进异常::set paste

命令补充

# bash如果存在timeout命令,则指定超时命令
if command -v timeout >/dev/null 2>&1; then
    TIMEOUT_WRAP="timeout --signal=ABRT --kill-after=60 ${UT_TIMEOUT}"
fi
if command -v stdbuf >/dev/null 2>&1; then
    STDBUF_WRAP="stdbuf -oL -eL"
fi
${TIMEOUT_WRAP} ${STDBUF_WRAP} ${exec}

HERE-DOCUMENT语法

cat > file <<-EOF
    hello world
EOF