说明¶
本笔记只整理日常高频、值得背下来直接敲的命令——简单问题自己输命令,往往比给大模型描述需求再等它跑更快。 如果是有循环控制的脚本,就直接上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 -77天内改动(+77天前)find . -size +100M大于100Mfind . -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/打 gztar -zxvf a.tar.gz解 gztar -jxvf a.tar.bz2解 bz2tar -Jxvf a.tar.xz解 xztar -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-xchmod +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登录信息;iduid/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/fstab:UUID=<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 host;curl URL(-O下载-I只看头);wget URLrsync -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 直接连:
传文件 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 upgrade、apt 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退出/EOFCtrl-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 interpreter:sed -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 默认空格
字符串 / 数字互转
匹配:~ 匹配、!~ 不匹配;推荐 [[: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 套空模式(恒匹配)
内建函数 / 特殊语句
print:print $0可缩写print;结束前隐含输出 ORS(默认\n)system(cmd):如system("sort < " tmpfile);exit n:退出;next:跳过本行后续模式;nextfile:跳到下一文件
重定向:与 shell 不同,写文件后必须手动 close("file"),除非走 system()
可替代 cut / 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
关联数组 / map(declare -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 -x…set +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软链、-Ssocket - 用
[[ ]]而非[ ]:&& || < >不会报错
流程控制
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:
0stdin、1stdout、2stderr;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语法