pwd
显示当前工作目录的绝对路径。-P 会先解析符号链接,显示物理路径。
pwd
pwd -P日常打交道最多的部分:怎么列目录、怎么复制移动删除、怎么按条件找文件、怎么查看大文件、怎么用 grep / sed / awk 把文本处理成想要的样子。命令都以 GNU 工具链为准,参数写法在各主流发行版上通用。
都是破坏性操作的邻居,复制和移动前先看清目标;删除前先 ls 一遍确认。
mkdir创建目录。-p 递归创建多级目录且已存在不报错,-m 直接指定权限。
mkdir -p /data/app/{logs,conf,data}mkdir -m 750 /srv/secrettouch把文件时间戳更新为当前时间;文件不存在时创建空文件。-d 指定时间,-a 只改访问时间。
touch /tmp/health.checktouch -d '2026-01-01 00:00' old.txtcp复制文件或目录。-r 递归复制目录,-a 归档模式(保留权限、属主、时间戳、软链接),-i 覆盖前询问,-u 只复制更新的。
cp -a /etc/nginx /etc/nginx.bakcp -u src/*.conf /etc/app/复制目录必须加 -r 或 -a;-a 需要 root 才能保留属主信息。
mv移动文件,或给文件改名。同一文件系统内是原子操作,跨文件系统相当于复制后删除。-i 覆盖前询问,-n 不覆盖已存在的文件。
mv app.log app.log.20261019mv -n *.tar.gz /data/archive/rm删除文件或目录。-r 递归删除目录,-f 忽略不存在的文件和确认提示,-i 逐个确认。删除后不进回收站,无法撤销。
rm -i old.logrm -rf /tmp/build-cache写 rm -rf 之前请先 echo 一遍展开结果,或者先执行 ls 看一遍同一串通配符。
rmdir删除空目录。只能删空目录,-p 可以连同上级空目录一起删。要删非空目录用 rm -r。
rmdir emptydirrmdir -p a/b/cln创建链接。-s 创建符号链接(软链接),不加 -s 是硬链接。-f 覆盖已存在的链接。硬链接不能跨文件系统、不能指向目录。
ln -s /opt/app/current/app.conf /etc/app.confln -sf /usr/local/bin/app-v2 /usr/local/bin/app相对路径的软链接是相对于链接所在目录解析的,不是当前目录。用 ln -sr 可以让它自动转成正确的相对路径。
readlink -f解析出文件的最终真实路径(把沿途所有软链接展开)。realpath 效果类似。排查「这个软链接指向哪里」时最直接。
readlink -f /etc/app.confrealpath ../logs/app.logbasename / dirname从路径里取文件名 / 取所在目录。写脚本处理路径时比字符串截取可靠。
basename /var/log/nginx/access.logdirname /var/log/nginx/access.logmktemp安全地创建一个临时文件或目录(-d),返回唯一路径。脚本里不要再用 /tmp/fixed_name。
mktemp /tmp/app.XXXXXXtmpdir=$(mktemp -d)truncate把文件截断或扩展到指定大小。-s 0 常用于「清空日志但保留文件句柄」,比 rm 更适合正在被写入的文件。
truncate -s 0 /var/log/app/app.logrename批量改名。注意两种实现:util-linux 的 rename 是 rename 原串 新串 文件…;Perl 版(Debian / Ubuntu 上叫 rename,其它发行版常叫 prename)接受正则表达式。
rename .jpeg .jpg *.jpegrename 's/\.bak$//' *.bak先跑 rename -n(Perl 版)或 echo 预览一遍结果,确认无误再去掉 -n。
find 的语法是「起点 + 条件 + 动作」,条件可以自由组合;这也是它比 ls 慢但强得多的原因。
find按名字、类型、大小、时间、权限、属主等条件递归查找文件。-name 按名字(区分大小写),-iname 忽略大小写,-maxdepth 限制深度,-type f/d/l 限定类型。
find /etc -name '*.conf' -type ffind /var -maxdepth 2 -type d -name 'cache'find . -iname '*.log' -size +100M在 / 下直接 find 会遍历 /proc、/sys、挂载的网络盘,通常要加 -xdev 或显式排除。
find -mtime / -newermt按修改时间筛选。-mtime -1 表示 24 小时内改过,+30 表示 30 天以前;-newermt 接受人类可读的时间点,可读性更好。
find /var/log -name '*.log' -mtime -1find /data -newermt '2026-10-01' -type ffind /tmp -type f -mmin +60find -exec / -delete-exec 对每个结果执行命令,{} 代表文件名,\; 表示逐个执行,+ 表示批量传给一条命令(快得多)。-delete 直接删除匹配项。
find /tmp -type f -mtime +7 -deletefind /var/log -name '*.gz' -exec gzip -t {} +find . -name '*.sh' -exec chmod +x {} +-delete 会真的删除文件;先去掉 -delete 跑一遍看结果,再补回来。
locate / updatedb查询预建的文件名数据库,比 find 快几个数量级,但结果可能不是最新的(数据库由 updatedb 定期重建)。需要安装 mlocate 或 plocate。
locate -i nginx.confsudo updatedbwhich / typewhich 查找可执行文件在 PATH 里的位置;type 更可靠,能分辨命令是别名、函数、内置命令还是外部程序。脚本里推荐 command -v。
which python3type -a lscommand -v nginx || echo 'not installed'whereis查找命令的二进制、源码和 man 手册位置。比 which 覆盖的范围更宽。
whereis -b nginxwhereis -m sshd小文件直接 cat,大文件用 less 或只看头尾;日志跟读用 tail -f。
cat输出文件全部内容。-n 显示行号,-A 显示制表符和行尾(排查不可见字符很好用),-s 压缩连续空行。
cat /etc/hostscat -n /etc/fstabcat -A 出问题的脚本.sh不要在没有分页的情况下 cat 几百 MB 的日志,终端会被刷屏;用 less 或 head。
tac把文件按行倒序输出(cat 反过来)。适合快速看日志最后几行之前的内容。
tac /var/log/app.log | head -20less分页查看文件,大文件秒开。空格翻页、b 回翻、g 到开头、G 到结尾、/ 搜索、n 下一个匹配、q 退出。-N 显示行号,-S 不折行,+F 进入跟读模式。
less /var/log/syslogless +F /var/log/nginx/access.logless 里按 Shift+F 相当于 tail -f,按 Ctrl+C 退出跟读回到浏览模式。
head显示文件开头,默认 10 行。-n 指定行数,-c 按字节。看清楚一个文件的格式(比如 CSV 表头)时常用。
head -n 20 data.csvhead -c 512 /dev/urandom | xxdtail显示文件结尾。-n 指定行数,-f 持续输出新追加的内容(跟读),-F 在文件被轮转/重建后仍能继续跟随。
tail -n 100 /var/log/nginx/error.logtail -F /var/log/app/app.logtail -n +2 data.csvtail -n +2 表示「从第 2 行开始输出」,常用在跳过 CSV 表头。
nl给文件加行号输出。比 cat -n 更可控:-ba 所有行编号,-bt 只给非空行编号,-s 自定义分隔符。
nl -ba app.conf | sed -n '40,60p'wc统计行数、单词数、字节数。-l 只统计行数(最常用),-w 单词,-c 字节,-m 字符。
wc -l /var/log/nginx/access.logfind . -name '*.py' | wc -ldiff比较两个文件或目录的差异。-u 输出统一格式(patch 用),-r 递归比较目录,-q 只报告是否不同,-w 忽略空白差异。
diff -u nginx.conf.old nginx.confdiff -rq /etc/app/ /etc/app.bak/想边看边改,用 diff -y 并排显示;颜色高亮可以配合 colordiff 或 git diff --no-index。
cmp按字节比较两个文件,只报第一个不同之处。适合校验二进制文件是否完全一致。
cmp -s a.bin b.bin && echo samemd5sum / sha256sum计算文件校验和,用来验证下载完整性或对比两台机器上的文件是否一致。sha256sum 更安全,新场景优先用它。
sha256sum ubuntu-24.04.isosha256sum -c SHA256SUMSmd5 已被证明可以构造碰撞,只用于去重或快速比对,不要用于安全校验。
base64base64 编码 / 解码。-d 解码,-w 0 取消换行(把二进制塞进 JSON 或配置文件时常用)。
base64 -w 0 logo.png > logo.b64base64 -d logo.b64 > logo.pnggrep 是使用频率最高的文本工具。记住 -r 递归、-E 正则、-v 取反、-A/-B/-C 上下文这四组就够了。
grep在文件或标准输入里搜索匹配的行。-i 忽略大小写,-v 反向匹配(输出不匹配的行),-n 显示行号,-w 整词匹配,-c 只输出计数,-F 把模式当纯字符串(不做正则解释)。
grep -n 'error' app.loggrep -vi 'debug\|trace' app.loggrep -c 'HTTP/1.1" 500' access.log搜索以 - 开头的字符串要用 -- 分隔:grep -- '--verbose' file。
grep -r递归搜索目录下的所有文件。-r 跟随命令行给出的软链接,-R 连文件系统里的软链接也跟随。配合 --include / --exclude-dir 收窄范围。
grep -rn 'listen 80' /etc/nginx/grep -r --include='*.conf' 'timeout' /etc/grep -rI 'TODO' --exclude-dir={.git,node_modules} .-I 会跳过二进制文件,避免在搜索时把终端刷成乱码。
grep -E / -P-E 使用扩展正则(等价于 egrep):+ ? | () {} 可以直接写;-P 使用 PCRE,支持 \d \s 和零宽断言,但 GNU grep 之外的实现未必支持。
grep -E '^(ERROR|FATAL)' app.loggrep -oP 'cost=\K[0-9]+' app.log基础正则里 + 和 ? 需要写成 \+ \?;与其反复转义,不如直接加 -E。
grep -A -B -C显示匹配行的上下文:-A 后 N 行,-B 前 N 行,-C 前后各 N 行。看报错堆栈、看配置段落必备。
grep -n -A 5 -B 2 'Exception' app.loggrep -C 3 'worker_processes' nginx.confgrep -l / -L / -o-l 只列出匹配的文件名,-L 列出不匹配的文件名,-o 只输出匹配到的部分(配合 -P 做字段提取很方便)。
grep -rl 'old-domain.com' /etc/nginx/grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' access.log | sort | uniq -c | sort -nr | headzgrep / zcat直接在 gzip 压缩文件里搜索,不需要先解压。日志轮转后的 .gz 文件用它可以省一次解压。
zgrep -c '500 ' /var/log/nginx/access.log.2.gzsed 的模型很简单:一行一行读进来,按地址选行,执行命令。替换用 s///,其余常用 d(删除)和 p(打印)。
sed 's/旧/新/'替换每行第一处匹配。加 g 替换行内全部;加 i 忽略大小写;\( \) 和 \1 可以做分组引用。默认只输出到屏幕,不改原文件。
sed 's/localhost/127.0.0.1/' app.confsed -E 's/(listen\s+)80/\190/' app.confsed -i直接修改原文件。-i.bak 会先备份成 原文件名.bak,强烈建议保留这个习惯;GNU sed 与 BSD/macOS sed 的 -i 参数写法不同。
sed -i.bak 's/old-domain.com/new-domain.com/g' /etc/nginx/conf.d/site.confsed -i '/^#/d;/^$/d' app.confsed -i 不会留下自动回滚点,改配置文件前先 cp 一份原始文件是最省事的保险。
sed -n '10,20p'只打印指定范围的行。Np 单行,N,Mp 区间,/正则/p 匹配行,$ 表示最后一行。必须带 -n,否则 sed 会默认再输出一遍原文。
sed -n '40,60p' app.confsed -n '/^server/,/^}/p' nginx.confsed 删除与插入d 删除匹配行,a 在行后追加,i 在行前插入,c 替换整行,y 做字符逐位转换。多个命令用 -e 或分号串起来。
sed '/^#/d;/^$/d' config.inised '1i # 由脚本生成,请勿手改' config.inised '$a # end' config.inised 处理 Windows 换行删掉行尾的 \r,把 CRLF 文件转成 LF。踩过「脚本第一行莫名其妙报 No such file」的坑之后就会记住这条。
sed -i 's/\r$//' script.shawk 把每行按分隔符切成 $1、$2……,天然适合「取某一列」「按条件过滤」「做汇总统计」三件事。
awk '{print $1}'按空白切分,输出第 1 列。$0 是整行,$NF 是最后一列,$(NF-1) 是倒数第二列。
awk '{print $1}' access.logdf -h | awk '{print $5, $6}'awk -F指定字段分隔符。-F: 处理 /etc/passwd 这类冒号分隔的文件,-F',' 处理 CSV,-F'\t' 处理制表符。
awk -F: '{print $1, $3}' /etc/passwdawk -F, '$3 > 100 {print $1}' data.csvawk 条件过滤在动作前写条件,只处理匹配的行。支持 ==、!=、>、<、~(正则匹配)、!~(不匹配)以及 && || 组合。
awk '$9 == 500' access.logawk -F: '$3 >= 1000 {print $1}' /etc/passwdawk '$0 ~ /timeout/ && $3 > 1000' app.logawk 统计求和累加到变量并在 END 块输出。这是 awk 最经典的价值:不用写脚本就能算总和、平均值、最大值。
awk '{sum += $5} END {print sum}' access.logawk '{sum += $5; n++} END {printf "avg=%.2f\n", sum/n}' access.logawk '{if ($5 > max) max = $5} END {print max}' access.logawk 内置变量 NR / NF / FNRNR 是已读总行号,FNR 是当前文件内的行号,NF 是当前行的字段数。多个文件一起处理时用 FNR 区分。
awk 'NR > 1' data.csvawk 'NF != 5 {print NR": "$0}' data.txtawk 'END {print NR}' app.logawk BEGIN / ENDBEGIN 在处理任何输入之前执行(适合设分隔符、打表头),END 在全部处理完后执行(适合输出汇总)。中间的规则对每一行执行。
awk 'BEGIN {FS=":"; print "user\tuid"} {print $1"\t"$3}' /etc/passwdawk '{count[$1]++} END {for (k in count) print count[k], k}' access.log | sort -nr | headawk '{count[$1]++}' 是统计频次的标准写法,等价于先 sort 再 uniq -c,但一步到位。
排序、去重、切列、替换字符、批量传参——这些都是管道里的标准零件,单独看很简单,组合起来威力很大。
sort按行排序。-n 按数值,-r 倒序,-u 排序并去重,-k 指定列,-t 指定分隔符,-h 支持 1K/2M 这类人类可读数值(新版 coreutils 支持)。
sort -u domains.txtsort -t: -k3 -n /etc/passwddu -h --max-depth=1 /var | sort -hr | head默认排序受 locale 影响(LC_ALL=C 是字节序)。写脚本时显式指定 LC_ALL=C 结果更稳定。
uniq去掉相邻的重复行。-c 显示出现次数,-d 只显示重复行,-u 只显示不重复行。前提是输入已经排序。
sort access.log | uniq -c | sort -nr | head -20sort ips.txt | uniq -duniq 只比较相邻行,所以几乎总是和 sort 一起用。
cut按列截取。-d 指定分隔符,-f 指定字段(从 1 开始),-c 按字符位置。只支持单字符分隔符,复杂场景用 awk。
cut -d: -f1,3 /etc/passwdcut -c1-10 app.logtr字符级替换或删除。-d 删除指定字符,-s 压缩连续重复字符,-c 取补集。注意它不认字符串,只认字符集。
tr 'a-z' 'A-Z' < input.txttr -s ' ' < access.logtr -d '\r' < win.txt > unix.txtxargs把标准输入按空白/换行拆成参数,交给后面的命令。解决「管道不能直接传参数」的问题。-n 每次传几个,-I{} 占位替换,-t 打印实际执行的命令。
cat urls.txt | xargs -n1 curl -sIfind /data -name '*.tmp' | xargs -r rm -f用 -r(GNU)避免输入为空时仍执行一次命令;不加 -r 时 xargs 可能运行 rm -f 而无参可删。
xargs -0 / -P-0 以 NUL 分隔输入(配合 find -print0,能正确处理带空格和换行的文件名);-P N 并行执行 N 个进程,处理大量小文件时提速明显。
find /var/log -name '*.gz' -print0 | xargs -0 -P4 -n1 gzip -tfind . -type f -print0 | xargs -0 sha256sum > checksums.txttee把标准输出同时写到屏幕和文件。-a 追加,配合 sudo 可以在需要 root 的位置写文件而不破坏重定向。
systemctl status nginx | tee /tmp/nginx.statusecho 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.confsudo echo x > /root/f 是不生效的:重定向由当前 shell 执行。改用 sudo tee。
split把大文件切成小块。-l 按行数,-b 按大小,-d 用数字后缀。传输或导入有大小限制时常用。
split -l 100000 big.csv part_split -b 100M backup.tar.gz backup.part.comm比较两个已排序文件,输出三列:只在文件 1、只在文件 2、共有。-12 只显示共有行,-23 只显示文件 1 独有。
sort a.txt -o a.txt && sort b.txt -o b.txt && comm -12 a.txt b.txtcomm -23 installed.txt needed.txtcomm 要求输入必须是有序的,且两个文件用同一种排序规则(建议都加 LC_ALL=C)。
iconv转换文件编码。处理 Windows 上传的 GBK 文件、或者老系统里的 GB18030 数据时必用。-f 源编码,-t 目标编码,-c 丢弃无法转换的字符。
iconv -f gbk -t utf-8 legacy.csv > legacy.utf8.csviconv -f utf-8 -t gbk -c report.txt > report.gbk.txt用 file -i 先确认源编码,猜错编码会导致乱码甚至截断。
shuf / seqshuf 随机打乱行或随机取样(-n 取几个),seq 生成数字序列(-w 补零,-s 指定分隔符)。写测试数据和批量循环时很好用。
shuf -n 5 servers.txtseq -w 1 10for i in $(seq 1 5); do echo host-$i; done