- 本笔记的 shell 为 bash
cat /etc/shells可获取系统当前安装的 shellecho $SHELL或echo $0可获知当前用户的默认 shell (即cat /etc/passwd对应用户的最后一列),一般是bash- 修改用户默认 shell 可以使用以下3种方法: 修改
/etc/passwd文件最后一列,sudo usermod --shell shell命令路径 用户名或sudo chsh --shell shell命令路径 用户名
- 修改用户默认 shell 可以使用以下3种方法: 修改
- Makefile 使用的默认 shell 是
/bin/sh指向的 shell (即readlink /bin/sh),Ubuntu 一般是dash- 修改 Makefile 默认 shell 可以重新设置符号链接
cd /bin && sudo ln -sf shell名称 sh,例如cd /bin && sudo ln -sf bash sh
- 修改 Makefile 默认 shell 可以重新设置符号链接
| Shell | 路径 | 特点 | 典型发行版 |
|---|---|---|---|
bash |
/bin/bash |
功能最全,GNU 项目,支持数组、关联数组、[[ ]]、$(( ))、进程替换等 |
大多数 Linux 默认 |
dash |
/bin/dash |
Debian Almquist Shell,POSIX 兼容,启动极快,不支持 bash 扩展 | Ubuntu/Debian 的 /bin/sh |
ash (busybox) |
/bin/ash |
BusyBox 内置,极度精简,用于嵌入式/Initramfs | Alpine、嵌入式 Linux |
zsh |
/bin/zsh |
兼容 bash,增强补全、主题、插件生态 | macOS 默认、Arch 可选 |
fish |
/usr/bin/fish |
语法不兼容 POSIX,开箱即用 | 可选安装 |
ksh |
/bin/ksh |
Korn Shell,bash 的前身 | 商业 Unix |
sh |
/bin/sh |
符号链接,指向 dash/bash/ash 等 | 视发行版而定 |
| 特性 | bash | dash / ash | 替代写法 |
|---|---|---|---|
数组 array=(a b c) |
✅ | ❌ | 使用位置参数 set -- a b c |
关联数组 declare -A |
✅ | ❌ | 无直接替代 |
双中括号 [[ ]] |
✅ | ❌ | 使用 [ ] 并加引号 |
算术扩展 $(( )) |
✅ | ✅ (POSIX) | — |
$[ ] 算术 |
✅ | ❌ | 使用 $(( )) |
C风格 for for((i=0;i<10;i++)) |
✅ | ❌ | i=0; while [ $i -lt 10 ]; do ...; i=$((i+1)); done |
变量切片 ${var:1:3} |
✅ | ❌ | 使用 expr substr 或 cut |
进程替换 <(cmd) |
✅ | ❌ | 使用管道或临时文件 |
source 关键字 |
✅ | dash ✅ / ash ❌ | 使用 . (点号) |
function 关键字 |
✅ | ❌ | 使用 fname() { } |
echo -e 转义 |
✅ | dash 不需要 -e;ash 需要 |
使用 printf 更安全 |
local 变量 |
✅ | dash ✅ / ash ✅ | — |
select 语句 |
✅ | ❌ | 手动实现 |
&> 重定向 |
✅ | ❌ | > file 2>&1 |
{a..z} 花括号展开 |
✅ | ❌ | 使用 seq 或循环 |
+= 字符串追加 |
✅ | ❌ | var="${var}new" |
BASH_SOURCE |
✅ | ❌ | $0 |
PIPESTATUS 数组 |
✅ | ❌ | 无直接替代 |
coproc 协进程 |
✅ | ❌ | 使用命名管道 FIFO |
mapfile/readarray |
✅ | ❌ | 使用 while read 循环 |
declare -n (nameref) |
✅ (bash 4.3+) | ❌ | 使用 eval |
正则匹配 [[ =~ ]] |
✅ | ❌ | 使用 expr 或 grep |
#!/bin/sh # 使用 sh 而非 bash,确保 dash/ash 兼容
# 1. 不使用数组,用位置参数或字符串
set -- "item1" "item2" "item3"
for item in "$@"; do echo "$item"; done
# 2. 不使用 [[ ]],用 [ ] 且变量加引号
if [ "$var" = "value" ]; then ...
# 3. 不使用 $[ ],用 $(( ))
result=$((a + b))
# 4. 不使用 source,用 .
. /etc/profile
# 5. 不使用 function 关键字
myfunc() { echo "hello"; }
# 6. 不使用 echo -e,用 printf
printf "\t%s\n" "$var"
# 7. 不使用 &>,用标准写法
cmd > output.txt 2>&1
# 8. 不使用花括号展开
i=1; while [ $i -le 10 ]; do echo $i; i=$((i+1)); done[TOC]
- 在 Linux 当中,有三种用户: root 用户、一般用户、虚拟用户
- root 用户的默认 shell 提示符是井号
#,$UID(用户ID)是0,可以执行所有命令sudo -i: Ubuntu 切换到 root 用户且切换到它的家目录,不需要先启用和添加 root 用户密码sudo su: Ubuntu 切换到 root 用户且停留在当前目录,不需要先启用和添加 root 用户密码su: 切换到 root 用户且停留在当前目录,Ubuntu 需要sudo passwd root先添加 root 用户密码才能使用 susu <user>: 切换到 user 用户,例如:su lengjingexit: 返回切换前的用户,如果是最后一个用户会关闭终端(也可以CTRL + d)
- 一般用户的默认 shell 提示符是美元符号
$,不可以执行特权命令,需要在命令前面加sudo才可以执行特权命令sudo <command>: 加上 sudo 运行特权命令- 修改 shell 提示符可修改
PS1环境变量
- 虚拟用户无法登陆终端执行命令,主要用于文件服务器权限的设置
- root 用户的默认 shell 提示符是井号
- Ubuntu 进入单人维护模式
- 系统重新启动,在读秒时按下任意键,再按下
e键就能够进入 grub 编辑模式 - 将光标移动到 kernel 那一行,再按一次
e键进入行编辑,行的最后输入single - 再按下
回车键确定之后,按下b键就会启动进入单人维护模式 - 在单人维护模式下,tty1 终端不需要输入密码即可取得控制权,例如: 输入
passwd <username>修改密码
- 系统重新启动,在读秒时按下任意键,再按下
- 帐号管理
passwd <username>: 修改密码/etc/passwdsudo passwd root: 添加或修改 root 用户密码sudo passwd -l root: 使 root 用户密码过期(禁用 root 用户)sudo passwd -u root: 使 root 用户密码有效(启用 root 用户)
useradd / usermod / userdel: 增加/删除/修改用户useradd -m <username>: 为用户创建相应的帐号和用户家目录/home/usernameuserdel -r <username>: 删除用户账号和用户家目录usermod -a -G <groupname> <username>: 将用户追加到用户组(例如串口组 dialout)sermod -aG sudo <username>: Debian 默认用户不是sudoers,需要su -切换到 root 用户运行此命令加入
groupadd / groupmod / groupdel: 增加/删除/修改组/etc/group
- 配置文件
/etc/profile~/.bash_profile~/.bash_login~/.profile: 登录时自动 source 此类脚本- 命令行登入时,会 source 系统登录配置
/etc/profile和用户登录配置(三选一,前面优先)~/.bash_profile~/.bash_login~/.profile- source
/etc/profile时会 source 其它脚本/etc/bash.bashrc/etc/profile.d/*.sh等
- source
- 打开新终端时不会再 source 登录配置脚本
- 命令行登入时,会 source 系统登录配置
/etc/bash.bashrc~/.bashrc: 打开新终端时自动 source 此类脚本- 用户一般会在
~/.bashrc改变环境变量PATH和 定义别名alias等
- 用户一般会在
~/.bash_logout: 登出时自动 source 此脚本~/.bash_history: 记录之前输入的命令,也可以history命令列出
- 命令格式:
command [-options] parameter1 parameter2 ...- command : 命令名、脚本名或可运行程序名, 例如: ./configure 执行当前文件夹下的 configure 文件
- 执行当前路径下的命令需要加上
./
- 执行当前路径下的命令需要加上
- options : 可选选项,短选项前通常会带
-,长选项前通常会带--,有的选项前可能什么都不带- 多个短选项可以放在一起,例如
-a -b -c一般也会写成-abc
- 多个短选项可以放在一起,例如
- parameter : 可能参数,多个参数用空格隔开
- command : 命令名、脚本名或可运行程序名, 例如: ./configure 执行当前文件夹下的 configure 文件
- 命令别名:
alias new_command='command sequence'- 单独
alias表示列出所有已定义的别名 command sequence中可以使用$@表示命令参数- 取消别名用
unalias new_command - 要使别名永久有效,需要写入
~/.bashrc配置文件 - 要使用别名的原始命令,需要对使用的命令进行转义
\command - 创建别名时,如果已经有同名的别名存在,那么原有的别名设置将被新的设置取代
- 例如: 定义别名
alias ll='ls -al'和取消别名unalias ll
- 单独
- 命令帮助:
man <num> commandnum: 查看对应类型的手册(不加 num 时表示找到第1个有效的章节)1: 可执行程序或 shell 命令,例如:man statorman 1 stat2: 系统调用(内核提供的函数),例如:man 2 stat3: 库调用(程序库中的函数),例如:man fopenorman 3 fopen- ... : ...
- 命令选项
-f: 等同于whatis,显示来自手册页的简短说明(若有),command 必须精确匹配命令whatis -w: 支持通配符,例如:whatis -w loc*
-k: 等同于apropos,搜索关键词对应的手册概述并显示所有匹配结果,command 可以是命令的一部分
- 搜索选项 :
/string向下搜 ;?string向上搜 ;n继续 ;N反向继续 - 翻页选项 :
[空格键]向下翻页 ;[PgUp][PgDn][Home][End]翻上/下/首/尾页 - 注: 一般命令的
--help或-h选项可显示命令帮助
-
中文版 man
- 下载和编译安装
wget https://src.fedoraproject.org/repo/pkgs/man-pages-zh-CN/v1.6.3.6.tar.gz/sha512/dc9ecd461eba41fc30658e028f853e3664fc6ce27c5b48c3159c5c8a452ad6d71730e0e5f551efa7b4c358baf010ba27a855457ae69b21e9637af326044dcca8/v1.6.3.6.tar.gz tar -xvf v1.6.3.6.tar.gz cd manpages-zh-1.6.3.6/ sudo apt install autotools-dev opencc autoreconf --install --force ./configure --disable-zhtw --prefix=/usr/local/zhman make && sudo make install
- 定义别名 cman
- 在
~/.bashrc中加入下面的内容cman() { man -M /usr/local/zhman/share/man/zh_CN $@ || man $@ } export -f cman
cman <cmd>: cmd 有中文说明时查看中文手册,没有中文时查看 man 原始的英文手册
- 在
- 下载和编译安装
-
命令位置
which: 查找命令- 命令选项
-a: 将所有由PATH定义的目录中找到的命令均分行列出,而不是第1个被找到的命令
- 命令选项
whereis: 查找特定文件(二进制文件、源码文件、说明文件等),同一行列出locate: 依据/var/lib/mlocate内的数据库记载,找出使用者输入的关键字档名(需要安装mlocate)- 命令选项
-i: 忽略大小写的差异-r: 使用正则表达式查找
updatedb根据/etc/updatedb.conf的配置去更新/var/lib/mlocate数据库
- 命令选项
type: 显示命令类型(别名/函数/内建/外部命令)type ls→ls is aliased to 'ls --color=auto'type cd→cd is a shell builtintype -a python→ 列出所有匹配
command -v <cmd>: POSIX 兼容的命令查找(替代 which)
- 特殊符号
cmd1 ; cmd2: 同一行的多个命令可以用分号分隔cmd1 | cmd2: 管道命令,上一个命令的输出 stdout 作为下一个命令的输入 stdin,常与xargs连用cmd1 || cmd2: 命令序列短路或执行: 若 cmd1 正确执行完毕,则不再执行 cmd2 ; 否则继续运行 cmd2cmd1 && cmd2: 命令序列短路与执行: 若 cmd1 正确执行完毕,则继续运行 cmd2 ; 否则不再执行 cmd2cmd &: 后台运行命令$(cmd): 获取命令的输出值,也可以使用`cmd`(cmd): 子 shell 命令组,当命令在子 shell 中执行时,不会对当前 shell 有任何影响,所有的改变仅限于子 shell 内- 小括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格
- 例如:
pwd;cd ..;pwd当前目录改变了,加小括号后pwd;(cd ..);pwd当前目录没改变
{cmd}: 命令区块(在当前 shell 中执行)$?: 最后运行的命令的结束代码(返回值),成功值为0
不同 Linux 发行版使用不同的包管理器,常用命令对比如下:
| 功能场景 | apt (Debian/Ubuntu) | dnf (Fedora/RHEL) | pacman (Arch/Manjaro) |
|---|---|---|---|
| 更新软件列表 | apt update |
dnf check-update |
pacman -Sy |
| 升级所有软件 | apt upgrade |
dnf upgrade |
pacman -Syu |
| 安装软件包 | apt install <包名> |
dnf install <包名> |
pacman -S --needed <包名> |
| 卸载软件包 | apt remove <包名> |
dnf remove <包名> |
pacman -R <包名> |
| 彻底卸载含配置 | apt purge <包名> |
无直接等效命令 | pacman -Rns <包名> |
| 卸载软件含依赖配置 | apt autoremove --purge |
dnf autoremove (不含配置) |
pacman -Rns $(pacman -Qdtq) |
| 搜索软件包 | apt search <关键词> |
dnf search <关键词> |
pacman -Ss <关键词> |
| 查看包信息 | apt show <包名> |
dnf info <包名> |
pacman -Si <包名> |
| 清理缓存 | apt clean |
dnf clean all |
pacman -Sc |
- 变量
- 变量赋值:
var=value- var 是变量名
- 变量名只能是字母、数字和下划线
_,且头字符不能是数字 - 通常全大写字符的变量名为系统环境变量
- 常用的环境变量:
PWD当前目录、USER当前用户名、HOME当前用户家目录、SHELL当前 shell、PATH命令搜索路径、LANG语言 cat /proc/$PID/environ | tr '\0' '\n'可查看进程相关的环境变量
- 常用的环境变量:
- 变量名只能是字母、数字和下划线
- value 是赋给变量的值
- 如果 value 不包含任何空白字符和
;等特殊符号,那么它就不需要使用引号进行引用,否则必须使用单引号或双引号 - 单引号中的变量引用不会扩展,双引号的会扩展为它的值
- 如果 value 不包含任何空白字符和
- 等号前后不能有空格,
var = value不是赋值而是比较的意思 - 变量默认是全局的,定义局部变量前面加
local readonly var或declare -r var: 定义只读变量
- var 是变量名
- 变量引用:
$varor${var}- 获取变量的值时如果变量名后面不是字母、数字和下划线,可以不加大括号
- 变量值长度:
${#var}- 获取变量值的长度,即字符串包含的字符数
- 变量默认值与替换
${var:-default}: var 未定义或为空时返回 default,不改变 var${var:=default}: var 未定义或为空时返回 default,并将 var 设为 default${var:+alternate}: var 已定义且非空时返回 alternate,否则返回空${var:?message}: var 未定义或为空时输出 message 到 stderr 并退出
- 变量赋值:
- 数组
- 普通数组(数字作为数组索引)
array=(test0 test1): 定义一个普通数组- 也可以单个定义或修改数组元素的值
array[0]=test0; array[1]=test1
- 也可以单个定义或修改数组元素的值
${array[n]}: 取数组的第n个元素的值,n从0开始
- 关联数组(文本作为数组索引)(从 bash4.0 开始)
declare -A array: 声明一个关联数组array=([ia]=test0 [ib]=test1): 将元素添加到关联数组中- 也可以一个一个元素地添加到关联数组中
array[ia]=test0; array[ib]=test1
- 也可以一个一个元素地添加到关联数组中
${array[index]}: 取关联数组的索引文本为index的元素的值
- 数组遍历
${array[*]}or${array[@]}: 数组所有元素值组成的列表${!array[*]}or${!array[@]}: 数组所有元素索引组成的列表${#array[*]}or${#array[@]}: 数组元素个数
- 数组操作
${array[@]:start:length}: 数组切片unset array[n]: 删除数组第n个元素unset array: 删除整个数组array+=("new_elem"): 追加元素到数组
- 注: dash 中不支持数组;busybox ash 不支持数组
- 普通数组(数字作为数组索引)
- 变量命令
eval: 变量引用前加eval会把变量字符串当作命令执行- 例如:
eval echo \$$val取变量名为$val的变量值
- 例如:
env: 查看所有的环境变量setorprintenv: 查看所有的环境变量和自定义变量unset var: 删除变量定义export var: 导出变量,可同时导出多个变量(空格分隔),则从当前 shell 执行的任何程序都会继承这个变量export var=value: 定义并导出变量- 例如:
export PATH=$PATH:/home/user/bin会将/home/user/bin添加到了环境变量PATH中 - 例如:
export LANG=en_US.UTF-8语言使用英文export LC_TIME=en_US.UTF-8日期使用英文 - 例如:
export GIT_SSL_NO_VERIFY=1关闭 git 的 ssl 安全校验
export -f fname: 导出函数declare/typeset: 声明变量属性declare -i var: 声明为整数declare -a var: 声明为索引数组declare -A var: 声明为关联数组declare -r var: 声明为只读declare -x var: 声明为导出(等同 export)declare -p var: 显示变量定义
shift [n]: 将位置参数左移 n 个(默认1个)
- 变量切片
${var:start:length}- 说明
var是变量名,start是开始位置,length是切片的长度start序号从0开始,也可以使用负数,-1是最后一个字符start是负数时必须在var的冒号后加空格或用小括号把数值括起来- 可以省略
:length,此时表示切片到字符串结尾 length大于最大长度时切片到字符串结尾length可以使用负数,此时不再表示长度的意思,而是切片到索引(不含)的意思- 注: dash / ash 中不支持变量切片
- 例子(定义
var=www.google.com)${var: -3}: 提取最后3个字符,也可以写成${var:(-3)},不可以写成${var:-3},例子值为 "com"${var:4}: 提取第4个(不含)字符之后的所有字符,也可以写成${var: 4},例子值为 "google.com"${var:4:6}: 提取第4个(不含)字符之后的6个字符,也可以写成${var:4:-4},例子值为 "google"
- 说明
- 变量提取
- 变量提取中
.表示定界作用,可换成其它的定界符,也可以使用多个字符 - 通配符:
*星号表示匹配任意数量(含0个)的任意字符,?问号表示匹配单个任意字符 - 例子(定义
var=www.google.com)${var#*.}: 从左边开始,去掉第一个符号'.'左边的所有字符,例子值为 "google.com"${var##*.}: 从右边开始,去掉第一个符号'.'左边的所有字符,例子值为 "com"${var%.*}: 从右边开始,去掉第一个符号'.'右边的所有字符,例子值为 "www.google"${var%%.*}: 从左边开始,去掉第一个符号'.'右边的所有字符,例子值为 "www"${var#????}: 表示删除前面4个字符,例子值为 "google.com"${var%????}: 表示删除后面4个字符,例子值为 "www.google"
- 变量替换
${var/old/new}: 替换第一个匹配${var//old/new}: 替换所有匹配${var/#old/new}: 替换行首匹配${var/%old/new}: 替换行尾匹配- 注: dash/ash 不支持
${var//}替换语法
- 变量提取中
- 变量计算
- 整数计算: 不支持浮点型,
expression的运算符和表达式符合C语言运算规则即可$[ expression ]: 取运算expression的值(注意expression前后有空格),出现在[ ]中的变量名之前可加可不加$(注: bash 已废弃,dash/ash 不支持)$(( expression )): 取运算expression的值,出现在(( ))中的变量名之前可加可不加$(POSIX 标准,所有 shell 支持)$(expr expression): 取运算expression的值,出现在( )中的变量名之前要加$(注意expression变量和运算符之间必须有空格)let expression: 进行expression运算更新值,使用let时,变量名之前不需要再添加$(注: dash/ash 不支持let)- 例如:
let num++ ; let num-- ; let num+=1 ; let num-=1 ; let num=1+1
- 例如:
- 高级计算:
echo "expression" | bc- 设定小数精度,例如:
echo "scale=2;22/7" | bc将输出 3.14 - 进制转换,
echo "obase=2;10" | bc将输出 1010 ;echo "obase=10;ibase=2;1010" | bc将输出 10 - 计算平方以及平方根,
echo "10^2" | bc将输出 100 ;echo "sqrt(100)" | bc将输出 10
- 设定小数精度,例如:
- 浮点计算替代:
awk 'BEGIN{printf "%.2f", 22/7}'(无需安装 bc) - 进制转换替代:
printf "%d" 0xFF(十六进制转十进制),printf "%x" 255(十进制转十六进制)
- 整数计算: 不支持浮点型,
- 打印输出
echo [options] expression: 通用打印- 打印屏幕,后面的字符串(即使有空格)可以不用引号,也可以用单引号或双引号
- 不带引号时,没法在所要显示的文本中使用分号
;,即使加-e也无法打印转义,例如:echo -e \t会打印\t - 带单引号时,特殊字符和字面义相同,变量替换无效,例如:
echo '$SHELL'打印$SHELL - 带双引号时,变量替换有效, 例如:
echo "$SHELL"或echo $SHELL打印/bin/bash - 不加引号时,命令替换会使输出中的换行符被 shell 进行字段拆分,最终 echo 用空格连接所有参数,因此输出变为单行;加双引号可以保留换行
- 例如:
echo $(ls -l)输出没有换行,echo "$(ls -l)"输出有换行
- 例如:
- 不带引号时,没法在所要显示的文本中使用分号
- 命令参数
-n: 不换行,后面输出紧接着这行(echo 默认会将一个换行符追加到输出文本的尾部)-e: 启用ASCII-C 转义字符的解释,例如:echo -e "\t"或echo -e '\t'会打印 tab,不加 -e 直接打印\t
- 颜色打印:
echo -e "\033[背景色;前景色m字符串\033[0m",例如:echo -e "\033[41;37m红底白字\033[0m"\033[0m: 关闭所有属性(注:\033可以写成\e)\033[4x;3xm: 同时设置背景色和前景色(x是数字代表:0黑1红2绿3黄4蓝5紫6天蓝7白)\033[4xm: 只设置背景色\033[3xm: 只设置前景色- 注: dash 中颜色打印不需要
-e;ash 中需要-e - 跨 shell 安全写法:
printf '\033[31m%s\033[0m\n' "红色文字"
echo { .. }: 生成值序列,例如:echo {a..z}echo {0..100}- 注: dash 不支持这种语法;ash 不支持这种语法
- 打印屏幕,后面的字符串(即使有空格)可以不用引号,也可以用单引号或双引号
printf FORMAT [ARGUMENT]: 格式化打印(POSIX 标准,所有 shell 可用)- printf 使用格式化字符,空格分隔的打印的参数,例如:
printf "%3.2f %s\n" 3.1415926 $PATH - printf 默认并不像 echo 命令一样会自动添加换行符
- 常用格式符:
%s字符串,%d整数,%f浮点,%x十六进制,%o八进制,%%百分号,\n换行,\t制表符 - 宽度精度:
%10s右对齐宽度10,%-10s左对齐宽度10,%.2f保留2位小数
- printf 使用格式化字符,空格分隔的打印的参数,例如:
- 读取输入
read [options] var1 var2 ...: 读取来自键盘输入的变量- 命令参数
-p tip_str: 提示-t sec: 最多等待 sec 秒-n num: 最多读取的 num 个字符-d separator: 特定定界符 separator 作为输入行的结束,默认结束符是换行符,变量的输入分隔符是空格-s: 无回显读取,用于读取密码-r: 不解释反斜杠(推荐总是加上)-a array: 读入数组(bash 特有)
- 注: dash 的
read不支持-p-t-n-s-a选项;ash 支持-r和-p
- 命令参数
$ read -p "Please keyin your name and age: " your_name your_age
Please keyin your name and age: lengjing 30
$ echo "The age of $your_name is $your_age."
The age of lengjing is 30.- 重定向
> >> <: 重定向文件>清空文件再输入(>等同于1>);>>追加到文件;<从文件中读取0stdin(标准输入)1stdout(标准输出)2stderr(标准错误)
:> file: 清空文件,例如::> a.txtcmd 2> stderr.txt 1> stdout.txt- 将 stderr 单独重定向到一个文件,将 stdout 重定向到另一个文件,
cmd 2>&1 output.txtorcmd &> output.txt- stderr 和 stdout 都被重定向到同一个文件中
- 注: dash / ash 中不支持
&>写法,替代写法cmd > output.txt 2>&1
cmd 2> /dev/null- 将 stderr 输出丢弃
cmd > /dev/null 2>&1- 丢弃所有输出
cmd | tee output.txt: tee只能从stdin中读取,终端中打印,并复制一份输出将它重定向到一个文件中- tee 命令默认会将文件覆盖,可以使用
-a选项追加内容
- tee 命令默认会将文件覆盖,可以使用
- Here Document ( heredoc )
cmd << DELIMITER ... DELIMITER: 将多行文本作为 stdin 输入cmd <<- DELIMITER: 忽略行首的 Tab(不忽略空格)cmd << 'DELIMITER': 不展开变量
- Here String ( bash 特有 )
cmd <<< "string": 将字符串作为 stdin 输入- 注: dash/ash 不支持
<<<
- 自定义文件描述符 exec
- 读
exec 10<input.txt; cat <&10 - 写
exec 11>output.txt; echo newline >&11 - 追加
exec 12>>input.txt; echo appended line >&12 - 关闭
exec 10>&-或exec 10<&- - 保存和恢复
exec 3>&1 # 保存 stdout 到 fd3 exec 1>file.txt # 重定向 stdout 到文件 echo "to file" # 写入文件 exec 1>&3 # 恢复 stdout exec 3>&- # 关闭 fd3
- 读
- 执行和调试
- 执行方式
./script_name.shorbash script_name.sh: 启用新的 sub-shell (新的子进程) 执行命令脚本. script_name.shorsource script_name.sh: 在当前 shell 下执行脚本,此时执行新的程序还可以访问脚本导出的变量等
- 执行过程
- shell 脚本需要添加运行权限
chmod +x script_name.sh才可以执行 - 命令的运行是从上而下、从左而右的分析与运行
- 第1行
#!/bin/bash在宣告这个 script 使用的 shell 类型- 跨发行版写法:
#!/bin/sh(POSIX兼容) 或#!/usr/bin/env bash(自动查找bash路径)
- 跨发行版写法:
- 命令、选项与参数间的多个空白都会被忽略掉,空白行也将被忽略掉
- 如果读取到一个换行符,就尝试开始运行该行(或该串)命令
- 如果一行的内容太多,可以使用
\来延伸至下一行 - 可以用
sleep 整数或浮点数在脚本中延时一段时间(秒)
- shell 脚本需要添加运行权限
- 调试脚本
-n标志运行脚本只是读一遍脚本中的命令但不执行,用于检查脚本中的语法错误,例如:bash -n ./configure-x标志运行脚本可以打印出所执行的每一行命令以及当前状态,例如:bash -x ./configure- 脚本内部使用
set -x(在执行时显示参数和命令) 和set +x(禁止调试) ,对包起来的命令进行调试 - 脚本内部使用
set –v(当命令进行读取时显示输入) 和set +v(禁止打印输入),对包起来的命令进行调试 - 脚本第一行写成
#!/bin/bash -xv,启用全程调试功能 set -e: 遇到命令返回非零值时立即退出脚本set -u: 使用未定义变量时报错退出set -o pipefail: 管道中任一命令失败则整个管道返回非零(bash 特有)- 推荐脚本开头:
set -euo pipefail
- 退出执行
exitreturn- 后面可以加数字指定退出状态码
source script_name.sh时exit会退出当前终端,而return不会
- 执行方式
- 特殊变量
$$: shell 本身的 PID (ProcessID)$!: shell 最后运行的后台进程的 PID$?: 最后运行的命令的结束代码(返回值),成功值为0$*: 所有参数列表,以"$1 $2 … $n"的形式输出所有参数,$*不被双引号包围时,效果同$@; 被双引号包围时,将所有的参数看做一份数据$@: 所有参数列表,以"$1" "$2" … "$n"的形式输出所有参数,将每个参数都看做一份数据$#: shell 的参数个数${BASH_SOURCE[0]}: source 脚本时脚本的路径名(bash 特有)$0: 普通执行脚本时脚本的路径名$1~$n: shell 脚本的各参数值,$1是第1参数、$2是第2参数 ... ,当n>=10时,需要使用${n}来获取参数$_: 上一条命令的最后一个参数$-: 当前 shell 选项标志(如 himB)
- 声明和使用
- 短命令选项
- 必带参数的选项: 参数声明背后会带1个冒号,类似
a:; 使用时参数和值之间可选是否带空格,类似-a valueaor-avaluea - 可选带参数的选项: 参数声明背后会带2个冒号,类似
b::; 使用时参数和值之间不能带空格,类似-bvalueb - 不带参数的选项: 参数声明背后没有冒号,类似
c; 使用时没有参数,类似-c
- 必带参数的选项: 参数声明背后会带1个冒号,类似
- 长命令选项
- 必带参数的选项: 参数声明背后会带1个冒号,类似
long-a:; 使用时参数和值之间可选是等号还是空格,类似--long-a=valueaor--long-a valuea - 可选带参数的选项: 参数声明背后会带2个冒号,类似
long-b::; 使用时参数和值之间只能是等号,类似--long-b=valueb - 不带参数的选项: 参数声明背后没有冒号,类似
long-c; 使用时没有参数,类似--long-c
- 必带参数的选项: 参数声明背后会带1个冒号,类似
- 短命令选项
getopts: bash 的内部命令(dash/ash 也支持)"a:c": 声明命令选项,getopts只支持短命令选项且不支持可选带参数的选项OPTARG: 特殊变量,自动设置此变量的值为当前命令选项的值(确切的说是下一个参数)OPTIND: 特殊变量,自动设置此变量的值为下一个参数的序号
#!/bin/bash
while getopts "a:c" opt; do
case $opt in
a) printf "%-40s%s\n" "option: -$opt" "parameter: $OPTARG";;
c) printf "%-40s%s\n" "option: -$opt" "parameter: None";;
*) echo "Error option: -$opt"; exit 1;;
esac
donegetopt: 规范化命令参数(外部命令,busybox 可能不包含)- getopt 参数说明
-o shortopts: 声明短命令选项,只有长命令选项时此选项的值必须置空-o '',不能省略-l longopts: 声明长命令选项,多个长命令选项使用逗号,分隔--: 固定写法,它的后面是原始的命令参数,getopt 生成的新的命令参数的最后一项是--
eval set -- "str": 将 str 替换为当前脚本的参数集shift num: 丢弃前面 num 个参数,不加 num 时丢弃一个,例如: 运行shift,$1被丢弃,$2变成了$1
- getopt 参数说明
#!/bin/bash
eval set -- "$(getopt -o a:b::c -l long-a:,long-b::,long-c -- $@)"
while :; do
case $1 in
-a|--long-a)
printf "%-40s%s\n" "option: $1" "parameter: $2"
shift 2
;;
-b|--long-b)
if [[ -z $2 ]]; then
printf "%-40s%s\n" "option: $1" "parameter: None"
else
printf "%-40s%s\n" "option: $1" "parameter: $2"
fi
shift 2
;;
-c|--long-c)
printf "%-40s%s\n" "option: $1" "parameter: None"
shift
;;
--)
shift
break
;;
*)
echo "Error option: $1"
exit 1
;;
esac
done- 定义函数
function可以省略- 注: dash / ash 中没有
function这个关键字
- 注: dash / ash 中没有
- 函数括号里面不写参数
- 函数里面参数用
$1 $2 ...表示,注意函数里面的这些值不再是脚本的参数($0还是脚本名)
- 函数里面参数用
- 支持递归调用,例如: Fork炸弹
:(){ :|:& };: - 返回值:
return n返回退出码(0-255),只能返回整数;返回数据用echo+ 命令替换
function fname() {
expression
}or (POSIX 兼容写法,推荐)
fname() {
expression
}- 调用函数
- 直接
fname或fname arg1 arg2 ...,不需要括号 - 函数内使用
local var声明局部变量(dash / ash 也支持local)
- 直接
注意条件测试语句的条件和中括号之间是有空格的,不能省略空格
-
数值比较
[ $var -eq value ]-eq相等;-ne不等;-gt大于;-ge大于等于;-lt小于;-le小于等于
(( var > value )): bash 算术比较(更直观)
-
文件系统测试
[ -f $var ]:-f是文件;-d是目录;-e文件存在;-s非空文件-r文件可读;-w文件可写;-x文件可执行-u SUID;-g SGID;-k SBIT-c是字符设备;-b是块设备;-L是符号链接;-S是socket;-p是FIFO/pipe-h是符号链接(同-L)-N文件在最后一次读取后被修改过- 注:符号链接指向目录,
-d 这个符号链接也是目录
[ file1 -nt file2 ]-nt新;-ot旧;-ef指向同一inode
-
字符串比较
[[ $str1 = $str2 ]]=相等;==相等;!=不等;<小于;>大于- 注1: 使用字符串比较时,最好用双中括号,因为有时候采用单个中括号会产生错误
- 注2: dash / ash 中只能用
=表示相等
[[ -z $var ]]-z空字符串;-n非空字符串- 注:
[ -n $var ]表示是否定义,变量赋值为空也是定义了
- 正则匹配(bash 特有):
[[ $str =~ regex ]]
-
多条件组合
[[ -n $var ]] && [[ $str1 = $str2 ]]- 使用逻辑运算符
&&和||能够很容易地将多个条件组合起来
- 使用逻辑运算符
[[ -n $var -a $str1 = $str2 ]][ $var -lt minvalue -o $var -gt maxvalue ]-a逻辑与;-o逻辑或
[[ ! -z $var ]]!条件取反
-
单/双中括号区别
- 单括号的 TEST 命令要对变量进行单词分离,当变量值包含空白符时,要用双引号将变量括起来;而双括号的 TEST 命令不会对变量进行单词分离
- 单括号的 TEST 命令不会对
*进行扩展,而双括号 TEST 命令则会对*进行扩展 - 单括号的 TEST 命令需要对大于号
<和 小于号>加转义符\,直接而双括号 TEST 命令不需要 test指令相当于单中括号,即test condition相当于[ condition ]- 注: dash / ash 中只能用单中括号
- 例子: 测试单双中括号
lengjing@lengjing:~$ var="a b"
lengjing@lengjing:~$ [ $var = "a b" ]; echo $?
bash: [: 参数太多
2
lengjing@lengjing:~$ [[ $var = "a b" ]]; echo $?
0
lengjing@lengjing:~$ [ "$var" = "a b" ]; echo $?
0
lengjing@lengjing:~$ [[ "$var" = "a b" ]]; echo $?
0
lengjing@lengjing:~$ var="a b"
lengjing@lengjing:~$ [ $var = a* ]; echo $?
bash: [: 参数太多
lengjing@lengjing:~$ [[ $var = a* ]]; echo $?
0
lengjing@lengjing:~$ [[ "$var" = a* ]]; echo $?
0
lengjing@lengjing:~$ [ "$var" = "a*" ]; echo $?
1
lengjing@lengjing:~$ [[ "$var" = "a*" ]]; echo $?
1
lengjing@lengjing:$ [ a < b ]; echo $?
bash: b: 没有那个文件或目录
lengjing@lengjing:$ [ a \< b ]; echo $?
0
lengjing@lengjing:$ [[ a < b ]]; echo $?
0
lengjing@lengjing:$ [ a > b ]; echo $?
0
lengjing@lengjing:$ [ a \> b ]; echo $?
1
lengjing@lengjing:$ [[ a > b ]]; echo $?
1- if 命令语句: 命令运行成功,则运行条件后的命令
if command; then
expression
elif command; then
expression
else
expression
fi- if 条件语句: 条件成立,则运行条件后的命令
if [ condition ]; then
expression
elif [ condition ]; then
expression
else
expression
fi- case 语句: case 语句中如果 pattern 后的命令成立,则运行 pattern 后的语句
- 每个变量内容建议用
双引号括起来,关键字则为右圆括号 - 每个类别结尾使用
两个连续的分号来处理 - 最后一个变量内容会用
*来代表所有其他值, - 最终以
esac关键字结尾 - pattern可使用
|表示两个值,例如:H264 | HEVC) - pattern可使用范围表示,例如:
[a-z]) ;&继续执行下一个 pattern(不判断)(bash4+);;&继续判断下一个 pattern(bash4+)
- 每个变量内容建议用
case $var in
pattern1)
expression
;;
pattern2 | pattern3)
expression
;;
[pattern4-patternn])
expression
;;
*)
expression
;;
esac- for-in 语句: 对 list 中的每一项进行迭代
- list 可以是一个字符串,也可以是一个序列,也可以是一个数组,也可以是带通配符的文件名
- 例如:
for i in $(seq 1 10)orfor i in {1..10}seq不写开始时从1开始 - 定界符
IFS的默认值为空白字符(空格符 换行符 制表符),可修改此变量从而使序列发生变化 - 例如:
bIFS=$IFS; IFS=':'; for i in $(cat /etc/passwd); do echo $i;done - 注:
{1..10}花括号展开 dash/ash 不支持,用$(seq 1 10)替代
for var in list; do
expression
done- for 语句: 类似C语言的 for 循环,注意空格
- 注: dash / ash 中不支持此种 for 循环
- 例如:
for (( i=0; i<10; i++ ))
for (( original; limit; step )); do
expression
done- while 语句: 条件为真时一直执行循环,直到条件为假
- 注:
while true或while :表示死循环,但:是 shell 的内建命令,退出状态总是0,不会每次执行时生成子进程true是作为一个二进制文件实现的,:是 shell 的内建命令,它的退出状态总是为0
- 从文件读取循环:
while IFS= read -r line; do echo "$line"; done < file.txt
- 注:
while [ condition ]; do
expression
done- until 语句: 条件为假时一直执行循环,直到条件为真
until [ condition ]; do
expression
done注: 循环也有 break continue 关键字,break n 跳出 n 层循环
trap 'commands' SIGNAL_LIST: 捕获信号并执行命令- 常用信号:
EXIT(0)HUP(1)INT(2,Ctrl+C)QUIT(3)TERM(15)ERRDEBUGRETURN trap - SIGNAL: 恢复信号默认行为trap '' SIGNAL: 忽略信号trap -p: 列出当前所有 trap 设置
- 常用信号:
#!/bin/bash
cleanup() {
echo "Cleaning up..."
rm -f "$tmpfile"
}
trap cleanup EXIT INT TERM
tmpfile=$(mktemp)
# ... 工作代码 ...-
进程替换(bash 特有)
diff <(cmd1) <(cmd2): 将命令输出作为文件参数>(cmd): 将输出写入命令的 stdin- 注: dash/ash 不支持进程替换,用命名管道(FIFO)或临时文件替代
-
后台任务管理
cmd &: 后台运行jobs -l: 查看后台任务fg %n: 将第 n 个后台任务调回前台bg %n: 让暂停的第 n 个后台任务继续运行Ctrl+Z: 暂停当前前台任务wait [pid]: 等待后台进程结束,返回其退出码disown %n: 将任务从 shell 的作业列表中移除(终端关闭后进程不退出)nohup cmd &: 忽略 HUP 信号运行
-
命名管道(FIFO)
mkfifo /tmp/myfifo: 创建命名管道echo data > /tmp/myfifo &: 写入cat /tmp/myfifo: 读取
xargs -P n: 并行执行 n 个进程parallel(GNU parallel): 更强大的并行工具&+wait实现简单并行:for i in 1 2 3 4 5; do process_item "$i" & done wait # 等待所有后台任务完成
- 限制并发数:
MAX_JOBS=4 for file in *.txt; do while [ "$(jobs -r | wc -l)" -ge $MAX_JOBS ]; do wait -n # bash 4.3+,等待任一任务完成 done process "$file" & done wait
-
bash 通配符(glob)
*: 匹配任意个(含0个)任意字符?: 匹配1个任意字符[ - ]: 匹配1个中括号内的字符,例如: [a-b] 匹配1个小写字母[^ ]: 匹配1个非中括号内的字符,例如: [^0-9] 匹配1个除了数字外的字符{ , }: 匹配1个大括号的字符或字符串,例如:{ab,ba}匹配 ab 或 ba
-
通配符控制(bash)
shopt -s nullglob: 无匹配时返回空而非字面模式shopt -s nocaseglob: 通配符匹配忽略大小写shopt -s extglob: 启用扩展通配符- 扩展通配符(extglob):
?(pattern): 匹配 0 或 1 次*(pattern): 匹配 0 或多次+(pattern): 匹配 1 或多次@(pattern): 匹配恰好 1 次!(pattern): 不匹配 pattern
注: 通配符主要用于匹配完整文件名,正则表达式主要用于匹配文件中的行的部分文本
- 图形化正则表达式 https://regexper.com/
- 正则表达式模式 https://zhuanlan.zhihu.com/p/435815082
- BRE(标准正则),grep / sed 的默认模式
- ERE(扩展正则),awk 的默认模式,grep / sed 使用
-E选项可使用扩展正则 - PCRE(Perl正则),perl/python/ruby/php/java等的模式,grep 使用
-P选项可使用Perl正则
- 特殊字符:
- 不加反斜杠:
?+{}|(),BRE 表示字符本身,ERE 和 PCRE 表示正则规则 - 加反斜杠:
\?\+\{\}\|\(\),BRE 表示正则规则,ERE 和 PCRE 表示字符本身
- 不加反斜杠:
-
重复(BRE ERE PCRE)
.: 匹配任意1个字符(是且只是1个),一般不会匹配换行符*: 匹配前1个字符任意次(包括0次),例如:co*l表示匹配 cl、col、coool ...
-
重复(BRE)
\?: 匹配前1个字符0次或1次,例如:co\?l表示匹配 cl、col\+: 匹配前1个字符至少1次,例如:co\+l表示匹配 col、coool ... (不包括 cl)\{n\}: 匹配前面字符出现n次\{n,\}: 匹配前面字符至少出现n次\{n,m\}: 匹配前面字符出现n到m次
-
重复(ERE PCRE)
?: 匹配前1个字符0次或1次,例如:co?l表示匹配 cl、col+: 匹配前1个字符至少1次,例如:co+l表示匹配 col、coool ... (不包括 cl){n}: 匹配前面字符出现n次{n,}: 匹配前面字符至少出现n次{n,m}: 匹配前面字符出现n到m次
-
贪婪和回溯(PCRE)
- 默认:重复匹配符默认是贪婪匹配(尽可能匹配多的字符)且可回溯(贪婪匹配下一步出错时返回前面符合的那步再重新匹配)
- 非贪婪: 重复匹配符后加问号
?表示非贪婪匹配(尽可能匹配少的字符) - 不回溯: 重复匹配符后加加号
+表示不回溯(贪婪匹配下一步出错时不会返回前面符合的那步再重新匹配)
lengjing@lengjing:~$ echo 123123 | grep -P -o '[0-9]+?3' 123 123 lengjing@lengjing:~$ echo 123123 | grep -P -o '[0-9]+3' 123123 lengjing@lengjing:~$ echo 123123 | grep -P -o '[0-9]++3' lengjing@lengjing:~$
-
定界(BRE ERE PCRE)
\< \>: 精确匹配,如:\<the\>表示精确匹配the这个单词,而不匹配包含the字符的单词\<和\>是 GNU grep 扩展,在 BRE 和 ERE 模式下有效,但 PCRE 中通常使用\b
^: 匹配字符串开头,一般工具都是读取每行作为字符串,即^看做匹配行首$: 匹配字符串结尾,即$看做匹配行尾,例如:^$表示匹配空行 (注意 win 下的换行字符是^M$,即\r\n)
-
集合(BRE ERE PCRE)
[ ]: 匹配字符集中的1个字符,例如:[ab]表示匹配a或匹配b[ - ]: 匹配字符集(连续编码使用减号连接),例如: 大写字母[a-z],小写字母[a-z],数字[0-9][^ ]: 字符集的反向选择,例如: 非数字和英文[^a-zA-Z0-9]
-
集合(BRE)
\|: 匹配用或的方式找出数个字符串, 例如:ma\(tri\)\|\(ilbo\)x表示匹配 matrix 或 mailbox\(pattern\): 匹配子串,例如:ma\(tri\)\?x表示匹配 max 或 matrix
-
集合(ERE PCRE)
|: 匹配用或的方式找出数个字符串, 例如:ma(tri)|(ilbo)x表示匹配 matrix 或 mailbox(pattern): 匹配子串,例如:ma(tri)?x表示匹配 max 或 matrix
-
集合中字符
?+{}|()特殊字符在集合中会失去其正则意义(BRE ERE PCRE)- PCRE 集合中可以使用元字符,BRE ERE 中不行
- 高级扩展(PCRE)
(?aiLmsux): 设置正则表达式标记,可同时设置多个,标记前面加减号-表示关闭标记i忽略大小写 : 进行忽略大小写匹配,例如:(?i)b(?-i)ook表示匹配 Book 或 bookm多行模式 : 设置以后,^匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);$匹配字符串尾,和每一行的结尾(换行符前面那个符号)s点号匹配全部字符 : 让.特殊字符匹配任何字符,包括换行符; 如果没有这个标记,.匹配除了换行符的其他任意字符x冗长模式 : 注释(#后面的到行尾)和空白符号会被忽略L语言依赖 : 由当前语言区域决定\w,\W,\b,\B和大小写敏感匹配,这个标记只能对 byte 样式有效a只匹配 ASCII 字符 : 让\w,\W,\b,\B,\d,\D,\s和\S只匹配 ASCII,而不是 Unicode,只对 Unicode 样式有效uUnicode 匹配
\num: 子串回溯匹配,\0一般表示正则表达式本身,\1表示第1个子项,\2表示第2个....,例如:([0-9])\1([0-9])\2表示匹配mmnn格式的数字(?:pattern): 正则括号的非捕获版本,匹配在括号内的任何正则表达式,但该分组所匹配的子字符串不能在执行匹配后被获取或是之后在模式中被引用(?aiLmsux:pattern): 正则括号的非捕获版本,k可设置正则表达式标记(?#annotation): 注释;里面的内容会被忽略(?P<name>pattern): 匹配 pattern 并为这个模式定义一个名字 name(?P=name): 匹配前面 name 定义的 pattern,例如:(?P<quote>['"]).*?(?P=quote)表示匹配单引号或者双引号括起来的字符串patterna(?=patternb): 前视,只在后面是 patternb 的情况下匹配 patternapatterna(?!patternb): 前视取反,只在后面不是 patternb 的情况下匹配 patterna(?<=patternb)patterna: 后视,只在前面是 patternb 的情况下匹配 patterna,例如:(?<=a)[0-9](?=b)表示匹配处于ab之间的一个数字(?<!patternb)patterna: 后视取反,只在前面不是 patternb 的情况下匹配 patterna
- ASCII C 转义字符
\0: 空字符,十进制为 0,十六进制为 0x00\a: 响铃,十进制为 7,十六进制为 0x07\b: 退格符,十进制为 8,十六进制为 0x08\t: 水平制表符,十进制为 9,十六进制为 0x09\n: 换行符,十进制为 10,十六进制为 0x0A\v: 垂直制表符,十进制为 11,十六进制为 0x0B\f: 换页符,十进制为 12,十六进制为 0x0C\r: 回车符,十进制为 13,十六进制为 0x0D\": 双引号,十进制为 34,十六进制为 0x22\': 单引号,十进制为 39,十六进制为 0x27\\: 反斜杠,十进制为 92,十六进制为 0x5C\nnn: 1~3位八进制数字表示的字符\xHH: 1~2位十六进制数字表示的字符\uHHHH: 1~4位十六进制数字表示的 Unicode (ISO/IEC 10646) 字符\UHHHHHHHH: 1~8位十六进制数字表示的 Unicode (ISO/IEC 10646) 字符
-
元字符(PCRE)
\d: 匹配数字[0-9]\D: 匹配非数字[^0-9]\A: 匹配字符串开始\Z: 匹配字符串结尾
-
元字符(BRE ERE PCRE)
\w: 匹配字母数字下划线[a-zA-Z0-9_]\W: 匹配非字母数字下划线[^a-zA-Z0-9_]\s: 匹配空白字符[\r\n\f\t\v ]\S: 匹配非空白字符[^\r\n\f\t\v ]\b: 匹配单词边界(单词边界为字母数字下划线之间)\B: 匹配非单词边界(单词边界为字母数字下划线之间)
- POSIX 字符类 (在正则表达式中POSIX字符类一般是2个连续的方括号,外层方括号表示集合,例如
[[:digit:]])(BRE ERE PCRE)[:digit:]: 表示数字[0-9][:xdigit:]: 表示十六进制数[0-9A-Fa-f][:lower:]: 表示小写字母[a-z][:upper:]: 表示大写字符[A-Z][:alpha:]: 表示大小写字母[A-Za-z][:alnum:]: 表示大小写字母和数字[0-9A-Za-z][:blank:]: 表示空格或 Tab[\t ][:space:]: 表示空白字符[\r\n\f\t\v ][:cntrl:]: 表示 ASCII 控制字符,ASCII 码 0-31 和 ASCII 码 127[\x00-\x1F\x7F][:print:]: 表示 ASCII 码 32-126[:graph:]: 表示 ASCII 码 33-126,比[:print:]少了空格[:punct:]: 表示 ASCII 码 32-47 和 58-64 和 91-96 和 123-126,[:print:]除去[:alnum:][:ascii:]: 表示 ASCII 码 32-47 和 58-64 和 91-96 和 123-126[\x00-\x7F]
find [path] [options] [action]- 功能
- 查找文件,默认会遍历完所有的子目录
- path 省略时默认查找当前目录,path 也可以指定为多个目录
- options 前可以加
!空格否定某项参数,例如:find . ! -name "*.o"
- 查找参数(通过文件名查找)
-name filename: 搜寻文件名称为 filename 的文件,可以使用通配符-iname filename: 搜寻文件名称为 filename 的文件,忽略大小写-regex pattern: 正则搜寻文件名称匹配 pattern 的文件-iregex pattern: 正则搜寻文件名称匹配 pattern 的文件,忽略大小写
- 查找参数(通过文件类型查找)
-type typename: 搜寻文件的类型为 typename 的文件,- 类型主要有:
f一般文件d目录l符号链接c字符设备b块设备文件ssocketpFIFO
- 类型主要有:
- 查找参数(通过文件大小查找)
-size +value: 搜寻比 value 还要大的文件- 单位有:
c1 byte;w2 bytes;b512 bytes;k1024 bytes;M1024k bytes;G1024M bytes
- 单位有:
-size -value: 搜寻比 value 还要小的文件,例如: 查找比1MB小的文件find -size -1M
- 查找参数(通过文件时间查找)
-newer filename: 列出比 filename 文件还要新的文件-mtime num: 列出在 num 天之前的那一天内被更改过内容的文件- num 前加加号
+表示 num 天之前(不含)改动,num 前加减号-表示 num 天之内(含)改动,ctime 和 atime 同理
- num 前加加号
-ctime num: 列出在 num 天之前的这一天内被更改过属性的文件-atime num: 列出在 num 天之前的这一天内被访问过的文件
- 查找参数(通过文件用户查找)
-user username: 文件所属用户为 username 的文件-group groupname: 文件所属组为 groupname 的文件-perm xyz: 文件属性为 xyz 的文件
- 限定参数
-L: 如果符号链接指向了目录,默认不会查找指向的目录,该选项改变此默认值-maxdepth num: 搜索最大深度为 num , num=1 时只在当前目录搜索-mindepth num: 搜索最小深度为 num-aor-and: 逻辑与(AND)操作,例如:find . \( -name '*e*' -and -name 's*' \)-oor-or: 逻辑或(OR)操作,例如:find . \( -name '*.c' -o -name '*.h' \)-path GLOB -prune: 排除某些文件夹,例如:find -path 'linux-*' -prune -o -path '.git' -prune -o -iname "*.c" -print整条语句理解为当 prune 执行为 true 时,那么就不再执行后面的选项
- 动作参数
-print: 打印找到的文件的文件名,默认动作-print0: 以 null 字符分隔打印(配合xargs -0处理含空格文件名)-delete: 删除找到的文件-exec command: 对找到的文件执行 command,注意该命令结尾的特殊标记\;- command 中的
{}表示对于每一个相应的匹配文件的文件名,例如:find -name *.html -exec cp {} ../html \;
- command 中的
-exec command {} +: 批量执行(更高效),类似 xargs-ok command: 同-exec但每次执行前询问确认
- 注: busybox 的 find 功能精简,不支持
-regex-prune-exec {} +等高级选项
- 功能
- 例子 find.sh: 查找指定目录下的指定文件名的文件
- 用法:
./find.sh [find_str]or./find.sh [options],可使用./find.sh -h查看详细帮助信息 - 用户可以修改
ignore_pathused_path对应他自己的工程
- 用法:
#!/bin/bash
find_str=
find_path=
ignore_path="arch-v1 arch-v2 arch-v3 arch-v4 arch-v5 armv7-a-hf armv8-a dsp-v1 dsp-v2 dsp-v3 ai-v1 ai-v2 linux* out"
used_path="arch-v5 armv8-a dsp-v3 ai-v2"
usage() {
echo "========================================"
echo -e "\033[34mUsage: '$0 find_str' or '$0 [options]'\033[0m"
echo -e "\033[34moptions:\033[0m"
echo -e "\033[34m-s find_str\033[0m : Specify the find string."
echo -e "\033[34m-p find_path\033[0m : Specify the find path."
echo " The default value is current dir."
echo -e "\033[34m-i ignore_path\033[0m : Specify the ignore dir names to process."
echo " The default value is all the dir names related to version."
echo -e "\033[34m-u used_path\033[0m : Specify the dir names which will be removed from the ignored dir names."
echo " The default value is 'arch-v5 armv8-a dsp-v3 ai-v2'."
echo "========================================"
}
if [ $# -eq 0 ]; then
usage
exit 1
elif [ $# -eq 1 ] && [[ $1 != '-h' ]]; then
find_str=$1
else
while getopts "s:p:i:u:h" opt; do
case $opt in
s) find_str=$OPTARG;;
p) find_path=$OPTARG;;
i) ignore_path=$OPTARG;;
u) used_path=$OPTARG;;
h) usage; exit 0;;
*) echo "Error option: -$opt"; usage; exit 1;;
esac
done
fi
for i in ${used_path}; do
ignore_path=$(echo "${ignore_path}" | sed -e "s:^${i} ::" -e "s: ${i} : :" -e "s: ${i}$::")
done
start_time_sec=`date +%s`
cmd=$(echo find ${find_path} -path \'*/.git\' -prune \
$(echo "${ignore_path}" | sed "s:\([*a-zA-Z0-9_\-]\+\):-o -path '*/\1' -prune:g") \
-o -name \"${find_str}\" -print)
cd `pwd`
eval $cmd
end_time_sec=`date +%s`
echo -e "\033[34mCost $(( $end_time_sec - $start_time_sec )) seconds.\033[0m"
echo -e "\033[32m$cmd\033[0m"- 例子 ctags.sh: 对指定目录下的源码文件生成 ctags 索引文件
- 用法:
./ctags.shor./ctags.sh [options],可使用./ctags.sh -h查看详细帮助信息 - 用户可以修改
ignore_pathused_path对应他自己的工程
- 用法:
#!/bin/bash
# ctags和omnicppcomplete配合自动补全 ctags --c++-kinds=+p --fields=+ialS --extra=+q
# --c++-kinds=+p : 为C++文件增加函数原型的标签
# --fields=+ialS : 在标签文件中加入继承信息(i)、类成员的访问控制信息(a)、 源文件语言包含信息(l)、以及函数的指纹(S)
# --extra=+q : 为标签增加类修饰符,如果没有此选项,将不能对类成员补全
ctags=ctags
more_options="--c++-kinds=+p --fields=+ialS --extra=+q"
find_path=
ignore_path="arch-v1 arch-v2 arch-v3 arch-v4 arch-v5 armv7-a-hf armv8-a dsp-v1 dsp-v2 dsp-v3 ai-v1 ai-v2 linux* out"
used_path="arch-v5 armv8-a dsp-v3 ai-v2"
find_suffix="c h cc cpp c++ hh hpp hxx"
usage() {
echo "========================================"
echo -e "\033[34mUsage: '$0' or '$0 [options]'\033[0m"
echo -e "\033[34moptions:\033[0m"
echo -e "\033[34m-m\033[0m : Specify using 'ctags ${more_options}'."
echo -e "\033[34m-p find_path\033[0m : Specify the find path."
echo " The default value is current dir."
echo -e "\033[34m-i ignore_path\033[0m : Specify the ignore dir names to process."
echo " The default value is all the dir names related to version."
echo -e "\033[34m-u used_path\033[0m : Specify the dir names which will be removed from the ignored dir names."
echo " The default value is 'arch-v5 armv8-a dsp-v3 ai-v2'."
echo "========================================"
}
while getopts "mp:i:u:h" opt; do
case $opt in
m) ctags="ctags ${more_options}";;
p) find_path=$OPTARG;;
i) ignore_path=$OPTARG;;
u) used_path=$OPTARG;;
h) usage; exit 0;;
*) echo "Error option: -$opt"; usage; exit 1;;
esac
done
for i in ${used_path}; do
ignore_path=$(echo "${ignore_path}" | sed -e "s:^${i} ::" -e "s: ${i} : :" -e "s: ${i}$::")
done
start_time_sec=`date +%s`
cmd=$(echo ${ctags} \$\(find ${find_path} -path \'*/.git\' -prune \
$(echo "${ignore_path}" | sed "s:\([*a-zA-Z0-9_\-]\+\):-o -path '*/\1' -prune:g") \
$(echo "${find_suffix}" | sed 's:\([*a-zA-Z0-9_+\-]\+\):-o -iname "*.\1" -print:g')\))
cd `pwd`
eval $cmd
end_time_sec=`date +%s`
echo -e "\033[34mCost $(( $end_time_sec - $start_time_sec )) seconds.\033[0m"
echo -e "\033[32m$cmd\033[0m"文本搜索 grep
grep [options] [grep_str] [file1] [file2] ...- 功能
- 搜索文件中正则匹配的行,默认输出
文件名: 匹配行 - 搜索的字符串使用正则表达式,包含空格时,必须用单引号或双引号括起来,双引号会对表达式求值
- 不使用文件名时,一般与
-r选项合用,表示递归搜索当前文件夹下的所有字符串
- 搜索文件中正则匹配的行,默认输出
- 处理参数
grep -G: 表示使用基本正则表达式,默认行为 (BRE)grep -Eoregrep: 表示使用扩展正则表达式 (ERE)grep -P: 表示使用 Perl 正则表达式 (PCRE)grep -F: 表示不使用正则表达式(固定字符串匹配,速度快)grep -f file: 从文件中获取搜索的字符串的样式,每个样式一行,相当于与逻辑grep -e "pattern1" -e "pattern2": 同时匹配,等价于grep "pattern1" | grep "pattern2"
- 范围参数
-ror-R: 递归搜索,-r不会解符号链接,而-R会--include=GLOB: 包含某些文件,GLOB 表示可使用通配符,例如:grep -rn "\<malloc\> *(" ./ --include=*.{c,cpp,h}--exclude=GLOB: 排除某些文件--exclude-dir=GLOB: 排除某些文件夹
- 控制参数
-i: 忽略大小写-v: 反向匹配-w: 精确匹配单词-x: 精确匹配行
- 输出参数
-n: 输出匹配行的行号,输出文件名:行号: 匹配行-c: 只列出匹配多少行,并不是匹配的次数,相当于grep "xxx" | wc -l-l: 只输出有匹配的文件列表,而不是匹配的行,-L相反-o: 只输出匹配部分的字符串,一行有多个匹配会输出多行,例如:echo this is a line. | egrep -o "[a-z]+\."输出line.-q: 静默模式,无任何输出,命令运行结果$?: 匹配到会返回 0,否则返回 1-A/-B/-C: 输出匹配行的周边行,选项后面可加数字,A / B / C分别表示除了列出匹配行外,后面 / 前面 / 两面的n行也列出来--color=auto: 高亮匹配部分-H/-h: 强制显示/隐藏文件名前缀
- 注: busybox grep 不支持
-P(PCRE),部分版本不支持--include/--exclude
- 功能
ag [options] pattern [path ...]- 功能
- 递归搜索目录中文件(默认不搜索二进制文件)匹配的行,类似
grep -rni,但执行效率比 grep 高 - 安装方法
sudo apt install silversearcher-ag
- 递归搜索目录中文件(默认不搜索二进制文件)匹配的行,类似
- 命令参数
-a: 搜索(不包括隐藏文件和忽略文件的)全部文件-s: 大小写敏感-f: 解符号链接--workers NUM: 多线程搜索-g GLOB: 打印和 GLOB 匹配(匹配一部分即可)的文件路径名-G GLOB: 仅搜索与 GLOB 匹配(匹配一部分即可)的文件名中的内容--ignore GLOB: 搜索排除与 GLOB 匹配文件或文件夹- 注:
-v-w-c-l-L-o-A-B-C等选项意义同 grep
- 功能
rg [options] pattern [path](ripgrep)- 功能
- 比 grep/ag 更快的递归搜索工具,Rust 编写
- 默认尊重 .gitignore,自动跳过二进制文件和隐藏文件
- 常用选项
-t type/-T type: 包含/排除文件类型,如-t c-t cpp-g GLOB: 包含/排除 GLOB 模式-l: 只输出文件名-c: 输出每个文件的匹配数-F: 固定字符串匹配-w: 匹配完整单词-i: 忽略大小写-n: 显示行号(默认开启)-A/-B/-C N: 上下文行
- 功能
- 例子 grep.sh: 搜索指定目录下的指定后缀的文件中的字符串
- 用法:
./grep.sh [grep_str]or./grep.sh [options],可使用./grep.sh -h查看详细帮助信息 - 用户可以修改
ignore_pathused_path对应他自己的工程
- 用法:
#!/bin/bash
grep_option=
grep_str=
grep_path=
ignore_path="arch-v1 arch-v2 arch-v3 arch-v4 arch-v5 armv7-a-hf armv8-a dsp-v1 dsp-v2 dsp-v3 ai-v1 ai-v2 linux* out"
used_path="arch-v5 armv8-a dsp-v3 ai-v2"
grep_suffix="c cc cp cxx cpp CPP c++ C h hh hp hxx hpp HPP h++ H"
usage() {
echo "========================================"
echo -e "\033[34mUsage: '$0 grep_str' or '$0 [options]'\033[0m"
echo -e "\033[34moptions:\033[0m"
echo -e "\033[34m-o grep_option\033[0m : Specify the additional grep options. for example: -o '-w'."
echo -e "\033[34m-s grep_str\033[0m : Specify the grep string."
echo -e "\033[34m-p grep_path\033[0m : Specify the grep path."
echo " The default value is current dir."
echo -e "\033[34m-i ignore_path\033[0m : Specify the ignore dir names to process."
echo " The default value is all the dir names related to version."
echo -e "\033[34m-u used_path\033[0m : Specify the dir names which will be removed from the ignored dir names."
echo " The default value is 'arch-v5 armv8-a dsp-v3 ai-v2'."
echo -e "\033[34m-x grep_suffix\033[0m : Specify the filename suffix to grep."
echo " The default value is the C/C++ source code suffix."
echo "========================================"
}
if [ $# -eq 0 ]; then
usage
exit 1
elif [ $# -eq 1 ] && [[ $1 != '-h' ]]; then
grep_str=$1
else
while getopts "o:s:p:i:u:x:h" opt; do
case $opt in
o) grep_option=$OPTARG;;
s) grep_str=$OPTARG;;
p) grep_path=$OPTARG;;
i) ignore_path=$OPTARG;;
u) used_path=$OPTARG;;
x) grep_suffix=$OPTARG;;
h) usage; exit 0;;
*) echo "Error option: -$opt"; usage; exit 1;;
esac
done
fi
for i in ${used_path}; do
ignore_path=$(echo "${ignore_path}" | sed -e "s:^${i} ::" -e "s: ${i} : :" -e "s: ${i}$::")
done
start_time_sec=`date +%s`
cmd=$(echo grep -rn --color=auto ${grep_option} \"${grep_str}\" ${grep_path} --exclude-dir=.git \
$(echo "${ignore_path}" | sed 's:\([*a-zA-Z0-9_\-]\+\):--exclude-dir=\1:g') \
$(echo "${grep_suffix}" | sed 's:\([*a-zA-Z0-9_+\-]\+\):--include=*.\1:g'))
cd `pwd`
eval $cmd
end_time_sec=`date +%s`
echo -e "\033[34mCost $(( $end_time_sec - $start_time_sec )) seconds.\033[0m"
echo -e "\033[32m$cmd\033[0m"流编辑器 sed
sed [options] 'pattern command' [file1] [file2] ...- 功能
- 编辑流中的匹配的行,如果不指定文件,需要从管道读取输入
pattern command必须用单引号或双引号括起来,双引号会对表达式求值- 临时缓冲区
- 模式空间: 模式空间中的内容会主动打印到标准输出,并自动清空
- 保持空间: 保持空间内容不会主动清空,也不会主动打印到标准输出,而是需要 sed 命令来进行处理
- 工作流程
- 模式空间初始化为空,保持空间初始化为一个空行,也就是默认带一个
\n - 读取文件的一行,存入模式空间,检查该行和提供的样式
pattern(可选) 是否匹配,如果没有提供样式,那么所有的行都是匹配的 - 如果匹配,(在模式空间)对匹配的行进行命令处理
- 不管是否匹配,sed 默认会将模式空间的内容输出打印到标准输出(
-n取消此默认行为),接着清空模式空间 - 然后继续读取下一行的内容到模式空间,继续处理,依次循环处理
- 模式空间初始化为空,保持空间初始化为一个空行,也就是默认带一个
- 命令参数
sed -e 'pattern command': 从命令行获取命令的样式,默认选项,只有一个命令时可以省略-e- 可同时使用多个样式
sed -e 'expression' -e 'expression'orsed 'expression' | sed 'expression'orsed 'expression; expression'
- 可同时使用多个样式
sed -f file: 从文件中获取命令的样式sed -Eorsed -r: 表示使用扩展正则表达式 (ERE)--debug: 调试 sed-n: 不打印模式空间的行,例如:sed -n '2p' filename表示只打印 filename 文件的第2行-i: 在文件中直接修改文件内容,不加此选项时默认打印到屏幕sed -i.bak: 修改并创建 .bak 备份
- 功能
-
匹配样式(pattern)
- 行号匹配
n: 匹配第n行,其中1是首行,$是尾行n,m: 匹配第n行(含)到第m行(含)之间的行n,+m: 匹配第n行(含)之后的共m行n,~m: 匹配第n行(含)直到到后面第一个行号被m整除(含)之间的行
- 正则匹配
/regexp/: 匹配包含正则表达式 regexp 的行\cregexpc: 匹配包含正则表达式 regexp 的行,c是定界符,可换成其它字符
- 混合匹配
/regexp/,n: 匹配从与 regexp 匹配的行(含)到第n行(含)之间的行,可以匹配多次n,/regexp/: 匹配从第n行(含)到第一个与 regexp 匹配的行(含)之间的行,如果第n行后的行都与 regexp 不匹配,将匹配到文件结尾
- 匹配取反
n,m!: 匹配不是第n行到第m行之间的行,上面的匹配都可以加感叹号!匹配取反
- 行号匹配
-
执行命令(command)
- 编辑命令(常用)
p: 打印行,打印模式空间,通常p会与参数sed -n一起运行d: 删除行,清空模式空间,模式空间只有一行时dD作用相同i text: 插入行,在当前行的上一行插入内容为 text 的行a text: 追加行,在当前行的下一行追加内容为 text 的行c text: 取代行, 使用内容为 text 的行取代当前行(iac命令可写成两行,第一行加\转义换行)
- 编辑命令(不常用)
D: 删除行,删除模式空间中的内容直到第一个换行符,并使用生成的模式空间重新开始循环,而不读取新的输入行e: 执行命令,执行在模式空间中找到的命令并用输出替换模式空间(不带尾随换行符被抑制)e command: 执行命令,执行命令并将其输出发送到输出流,该命令可以跨多行运行,除了最后一行以反斜杠结尾F: 打印文件名,打印当前输入文件的文件名(带尾随换行符)=: 打印行号,打印当前输入的行号(带尾随换行符)P: 打印行,打印模式空间中的内容直到第一个换行符r file: 追加文件,在当前行的下一行追加 file 文件的内容R file: 追加文件行,在当前循环结束时或在读取下一个输入行时,将要读取的文件的一行插入到输出流中w file: 另存文件,将当前模式空间的内容写入到另外的文件W file: 另存文件,将当前模式空间空间中的内容直到第一个换行符写入到另外的文件
- 空间置换命令
h: 把模式空间内容覆盖到保持空间中H: 把模式空间内容追加到保持空间中g: 把保持空间内容覆盖到模式空间中G: 把保持空间内容追加到模式空间中x: 交换模式空间与保持空间的内容z: 情况模式空间的内容
- 编辑命令(常用)
- 取代匹配
sed -i 's/regexp/replace/g'- 使用说明
- 取代匹配的关键字是
s,关键字前面还可以加行范围 - 一般使用
/作为区域分隔字符,也可以使用其他任意字符 - sed 默认只会打印替换后的文本,如果要在替换的同时保存更改到原文件,可以使用
-i选项 - sed 默认会将每一行中第一处符合模式的内容替换掉,如果要替换该行的所有匹配,需要在命令尾部加上参数
g, 如果要替换该行的第n处匹配开始之后所有的匹配,需要在命令尾部加上参数ng - 例如:
sed -i .bak 's/regexp/replace/g' filename保存更改到原文件,并创建备份文件 filename.bak - 例如:
sed -i '1,10s/\<malloc\>[ \t]*([ \t]*/calloc(1, /g' file# 表示 file 文件的前10行的所有 malloc 函数替换成 calloc 函数
- 取代匹配的关键字是
- 已匹配字符串标记
&- replace 中的
&是已匹配字符串标记,代表前面匹配的字符串 - 例如:
echo Leng Jing | sed 's/\w\+/[&]/g'输出为[Leng] [Jing]
- replace 中的
- 子串匹配标记
\n- 子串匹配标记
\n,\1表示第1个子串,\2表示第2个子串,依此类推... - 子串是圆括号括起来的字符串
- 例如:
echo Leng Jing | sed 's/\(\w\+\) \(\w\+\)/\2 \1/'orecho Leng Jing | sed -E 's/(\w+) (\w+)/\2 \1/'输出为Jing Leng
- 子串匹配标记
- 使用说明
- 简单例子
sed -n '/\<malloc\>/p' file: 表示打印 file 文件含有 malloc 单词的行sed -n '1,10p' file: 表示打印 file 文件的前10行sed -i '1,10d' file: 表示删除 file 文件的前10行sed -i '/^[ \t]*$/d' file: 表示删除空白行sed -i 'a \\' file: 表示 file 文件的每一行之后都增加新的空行sed -i '$ a abcdsfg' file: 表示 file 文件的最后一行之后增加新的行 "abcdsfg"sed -i '1i #!/bin/bash' file: 表示 file 文件第1行之前增加新行,该行字符串为 "#!/bin/bash"sed -i 'c hello' file: 表示 file 文件的每一行都替换成了 "hello"
- 例子 rename.sh: 替换掉源码中的符号定义
- 用法:
./rename.sh [replace] [olddefs] [defvars],例如:./rename.sh "ENV_ARCH" "CONFIG_ARCH CONFIG_VERSION" "V1 V2"- replace : 新的定义名字
- olddefs : 旧的定义名字
- defvars : 该变量可以被赋予的值
- 例子说明:
- 配置文件中使用了
CONFIG_ARCHCONFIG_VERSION - Makefile 中使用了
CONFIG_ARCHCONFIG_VERSION-DCONFIG_ARCH_$(CONFIG_ARCH)-DCONFIG_VERSION_$(CONFIG_VERSION) - 源码文件中使用了
CONFIG_ARCH_V1CONFIG_ARCH_V2CONFIG_VERSION_V1CONFIG_VERSION_V2 - 本例子把上面所有的字符串中的 CONFIG_ARCH 和 CONFIG_VERSION 换成了 ENV_ARCH
- 配置文件中使用了
- 用法:
#!/bin/bash
do_rename() {
replace=$1
olddefs=$2
defvars=$3
for i in ${olddefs}; do
for j in ${defvars}; do
str=${i}_${j}
files=$(grep -rwl "${str}" | xargs)
if [ ! -z "${files}" ]; then
echo -e "\033[32mRename ${str}\033[0m"
echo ${files}
sed -i "s/\<${str}\>/${replace}_${j}/g" ${files}
fi
done
str=D${i}_
files=$(grep -rwl "${str}" | xargs)
if [ ! -z "${files}" ]; then
echo -e "\033[32mRename ${str}\033[0m"
echo $files
sed -i "s/\<${str}\>/D${replace}_/g" ${files}
fi
str=${i}
files=$(grep -rwl "${str}" | xargs)
if [ ! -z "${files}" ]; then
echo -e "\033[32mRename ${str}\033[0m"
echo $files
sed -i "s/\<${str}\>/${replace}/g" ${files}
fi
done
}
do_rename "$1" "$2" "$3"文本编辑语言 awk
awk [options] 'BEGIN{commands} pattern{commands} END{commands}' [file1] [file2] ...- 功能
- awk 是一个强大的文本分析语言(数据驱动),有它自己的一套脚本语法(类似C语言,换行又是脚本形式)
- 程序一般使用单引号包含,由3个块组成: 开始块
BEGIN{commands}、主体块pattern{commands}、结束块END{commands},都是可选的 BEGIN和END是关键字,匹配样式pattern可以是正则表达式、条件语句以及行匹配范围等- commands 中多个命令使用分号
;分隔,支持条件语句和循环语句,支持各种运算,变量引用不需要加美元符$ - 工作流程
- 从输入流中读取行之前执行
BEGIN {commands}语句块(可选)中的语句 - 从文件或 stdin 中每读取一行,awk 就会检查该行和提供的样式
pattern(可选) 是否匹配,如果没有提供样式,那么 awk 就认为所有的行都是匹配的 - 如果当前行匹配该样式,则执行
{commands}中的语句(可选),如果不提供该语句块,则默认执行{ print },即打印所读取到的每一行 - 读取完所有的行之后执行
END {commands}语句块(可选)中的语句
- 从输入流中读取行之前执行
- 打印
print var1,var2orprint var1 var2: print 会自动增加换行符 ,参数以逗号进行分隔时,打印后多个参数间是空格分隔;以空格进行分隔时,打印后多个参数间没有分隔printf "format",var1,var2: printf 不会自动增加换行符,是格式化打印- 例如:
echo abc | awk '{print 100 ":" $0}'orecho abc | awk '{printf "%d:%s\n",100,$0}'orecho abc | awk '{print sprintf("%d:%s",100,$0)}'都输出100:abc
- 命令参数
awk -f awk_script: 执行 awk_script 脚本文件-F separator: 指定分隔符,可以是字符串或正则表达式,默认分隔符是(1个或多个)空格,分隔符分开的每一项称为一个域(字段)-v var1=value1 var2=value2 ...: 定义用户变量
- 功能
- 匹配样式
- 行号匹配
NR==n: 匹配第n行,还支持!=<<=>>=等其它运算符,也可以使用运算再条件判断,例如:awk 'NR % 2 == 0'NR==n,NR==m: 匹配第n行(含)到第m行(含)之间的行
- 正则匹配
/regexp/: 匹配包含正则表达式 regexp 的行/regexpn/,/regexpm/: 匹配包含正则表达式 regexpn(含) 到 regexpm(含)之间的行
- 混合匹配
/regexp/,n: 匹配从与 regexp 匹配的行(含)到第n行(含)之间的行,可以匹配多次n,/regexp/: 匹配从第n行(含)到第一个与 regexp 匹配的行(含)之间的行,如果第n行后的行都与 regexp 不匹配,将匹配到文件结尾
- 匹配取反
!/regexp/: 匹配不包含正则表达式 regexp 的行,上面的匹配都可以加感叹号!匹配取反
- 行号匹配
- 运算符
=+=-=*=/=%=^=**=: 赋值?:: C条件表达式||: 逻辑或&&: 逻辑与~!~: 判断匹配/不匹配后面的正则表达式/regexp/<<=>>=!===: 关系运算符: 空格,连接符,可连接字符串+-: 加 减*/%: 乘 除 余+-!: 一元加 减 逻辑非^***: 求幂++--: 自增 自减,作为前缀或后缀$: 字段引用in: 是否是数组成员
- 条件和循环(类似C语言,循环语句也有
break和continue)if (condition) { commands } else if (condition) { commands } else { commands }: if 条件语句for (init_clause; cond_expression; iteration_expression): for 循环语句,例如:len = length(array); for (i=1; i<=len; i++) {print array[i]}for (var in array) { commands }: for-in 循环语句,例如:for (i in array) {print array[i]}while (condition) { commands }: while 循环语句do { commands } while (condition): do-while 循环语句
- 内置变量
FILENAME: 当前处理的文件名,没有文件时值是-NR: Number of Record,已经读出的记录数,即行号,从1开始FNR: 多文件操作时,新打开文件时 FNR 会重新从1开始,而 NR 则不会NF: Number for Field,当前记录中的字段个数$0: 当前记录,即当前行的文本内容$1$2...: 当前记录中的第1 / 2 /...个字段的文本内容,最后一个字段用$NF, 倒数第2个字段用$(NF‐1)RS: Record Separator,输入记录的分隔符,默认是换行符FS: Field Separator,输入字段的分隔符,默认是空格符ORS: Out of Record Separator,输出记录的分隔符,默认是换行符OFS: Out of Field Separator,输出字段的分隔符,默认是空格符IGNORECASE: 设为1时忽略大小写
- 内建函数
- 字符串函数
asort(source[,dest[,how ]])asorti(source[,dest[,how ]])asort按数组source的值排序,且将数组的索引替换为从1开始的连续整数,数组的值还是原来的值asorti按数组source的索引排序,且将数组的索引替换为从1开始的连续整数,数组的值是原来的索引- 有
dest参数时,将排序后的值保存到dest,否则直接在source上排序保存 how使用自定义函数排序,使用时函数名要用双引号包含,函数定义为function cmp_name(i1, v1, i2, v2),其中i表示索引,v表示值- 例如:
echo | awk '{a[1]="orange"; a[3]="apple"; a[4]="pear"; asort(a); for (i in a) printf "[%d:%s]",i,a[i]} END{print ""}'输出[1:apple][2:orange][3:pear] - 例如:
echo | awk '{a[1]="orange"; a[3]="apple"; a[4]="pear"; asorti(a); for (i in a) printf "[%d:%s]",i,a[i]} END{print ""}'输出[1:1][2:3][3:4]
sub(regexp,replace[,str])gsub(regexp,replace[,str])gensub(regexp,replace,how[,str])sub将字符串str中正则表达式regexp匹配到的第1处内容替换成字符串replacegsub将字符串str中正则表达式regexp所有匹配到的内容替换成字符串replacegensub将字符串str中正则表达式regexp匹配到的指定位置的内容替换成字符串replace- 函数返回值是替换的个数
replace中可用&表示匹配到的字符串- 不指定
str时缺省值是当前记录$0 gensub中的how为g/G时替换所有匹配到内容,为数字时替换匹配到的第how处内容- 例如:
echo axbxc | awk '{var=gsub(/x/,"|&|"); print var ":" $0}'输出2:a|x|b|x|c
length([str])- 返回字符串
str的长度 - 不指定
str时缺省值是当前记录$0,也可以省略小括号 - 例如:
echo abcdefg | awk '{print length}'输出7
- 返回字符串
substr(str,start[,len])- 提取字符串
str的子串 - 位置从1开始编号,从位置
start(含),提取len个字符 - 不指定
len时输出直到结尾 - 例如:
df -h | awk '{if (int(substr($5,1,length($5)-1)) > 80) print $0}'输出空间占用大于 80 的磁盘
- 提取字符串
index(str,substr)- 返回字符串
substr在字符串str出现的位置 - 位置从1开始编号,找到时返回位置编号,没找到时返回0
- 例如:
echo abcdefg | awk '{print index($0,"cd"),index($0,"hi")}'输出3 0
- 返回字符串
match(str,regexp)- 返回正则表达式
regexp在字符串str首次匹配的位置 - 位置从1开始编号,匹配时返回首次匹配的位置编号,没找到时返回0
- 匹配同时
RSTART特殊变量设置为位置编号,否则设置为 0 - 匹配同时
RLENGTH特殊变量设置为匹配的字符串的长度,否则设置为 -1 - 例如:
echo 'Hello World!' | awk '{ret=match($0,/\w+/); print ret,RSTART,RLENGTH}'输出1 1 5 - 例如:
echo 'Hello World!' | awk '{ret=match($0,/abc/); print ret,RSTART,RLENGTH}'输出0 0 -1
- 返回正则表达式
split(str,array[,delimiter[,seps]])patsplit(str,array[,regexp[,seps]])split使用定界符delimiter将字符串str切割成子字符串数组存入array,返回分割后的元素总数patsplit使用正则表达式regexp提取字符串str匹配的子字符串数组存入array,返回提取后的元素总数split不指定delimiter时默认使用输入字段的分隔符FSseps是 gawk 扩展,保存str中的分隔的/不匹配的字符串为数组- 例如:
echo a:b:c | awk '{split($0,array,":"); for (i in array) printf "%s",array[i]} END{print ""}'输出abc - 例如:
echo ab:cd:ef:g | awk '{patsplit($0,array,/\w+/); for (i in array) printf "(%s)",array[i]} END{print ""}'输出(ab)(cd)(ef)(g)
sprintf(format,var1,var2,...)- 格式化字符串
- 例如:
echo | awk '{var=sprintf("%s = %lf","PI",3.1415926);print var}'输出PI = 3.141593
tolower(str)toupper(str)- 大小写转换
- 例如:
echo aXbXc | awk '{print tolower($0) " | " toupper($0)}'输出axbxc | AXBXC
strtonum(str)- 检查
str并返回其数值,0开头是八进制数,0x0X开头是八进制数
- 检查
- 算术函数
int(x): 取整,也可以转化"strnum"型的字符串srand([x]): 将生成随机数的种子设置为值 x,x被省略则当前日期和时间用于种子rand(): 随机数,返回0到1之间的随机数,例如:echo | awk '{srand();print rand()}'sin(x): 正弦cos(x): 余弦atan2(y, x): 反正切sqrt(x): 平方根log(x): 对数exp(x): e指数e ^ x
- 位函数
lshift(val,count): 左移rshift(val,count): 右移compl(val): 补码and(v1,v2[,…]): 位与or(v1,v2[,…]): 位或xor(v1,v2[,…]): 位异或
- 类型函数
isarray(x): 是数组typeof(x): 返回类型字符串"number""strnum""string""array""regexp""unassigned""untyped"
- I/O 函数
close(filename[,how]): 关闭文件或管道fflush([filename]): 刷新缓冲
- 时间函数
systime(): 返回 UTC 时间戳mktime(datespec[,utc-flag]): 字符串转换为时间戳,utc-flag为时区strftime([format[,timestamp[,utc-flag]]]): 时间戳格式化为字符串
- 特殊函数
system(command)- 调用子 shell
- 例如:
awk 'BEGIN{var=system("ls -al");print var}'
- 字符串函数
[expression |] getline [var]orgetline [var] [< file]: 设置变量- 把管道
expression输出或文件file内容的下一个记录赋值给变量var - 不指定管道和不指定文件时,读取的是当前输入文件
- 不指定变量时,则当前记录
$0记录变量设置为该记录的值,还将设置NF、NR和FNR特殊变量 - 例如:
awk 'BEGIN{while ("cat /etc/passwd"|getline) {print $0}; close("/etc/passwd")}' - 例如:
awk 'BEGIN{while (getline < "/etc/passwd") {print $0}; close("/etc/passwd")}'
- 把管道
- awk 脚本
- 使用
awk -f awk_script [file1] [file2] ...执行 awk_script 脚本文件 - 使用
#作为注释 - 行尾不需要使用分号,一行多条命令可以使用分号分隔
- 可以在
BEGIN前自定义函数function fname(param1,param2) { commands } - 支持普通数组和关联数组,对数组名
for-in遍历的是数组的索引
- 使用
- 简单例子
- 打印例子
echo | awk '{var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3}': 输出v1 v2 v3echo | awk 'BEGIN{OFS="_"} {var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3}': 输出v1_v2_v3echo | awk '{var1="v1"; var2="v2"; var3="v3"; print var1 "-" var2 "-" var3}': 输出v1-v2-v3
- 打印匹配和非匹配行
awk 'NR < 3': 打印行号小于3的行,即第1行和第2行awk '!/linux/': 打印不包含 linux 的行
- 删除某个字段
echo "a.o: a.c a.h b.h" | awk '{$2="\b";print $0}': 输出a.o: a.h b.h,即删除了第2个字段
- 指定分隔符
cat /etc/passwd | awk -F ':' '{print $1"\t"$7}': 输出账户名和对应的 shell,以制表符分隔
- 传递外部变量
var1="Variable1" ; var2="Variable2"; echo | awk '{print v1,v2}' v1=$var1 v2=$var2: 输出Variable1 Variable2
- 复杂用法
echo -e "1\n 2\n 3\n 4" | awk 'BEGIN{num=0;} {sum+=$1; print $1" +"} END{print "="; print sum}' | xargs echo | sed 's/+ =/=/g': 输出1 + 2 + 3 + 4 = 10ls -l | awk 'BEGIN{size=0;} {size=size+$5;} END{print "Total size is",size/1024,"KB"}': 统计当前文件夹所有文件的总大小
- 打印例子
- 例子 words.sh: 统计文件中单词出现的次数
- 用法:
./words.sh [filename] [sortop]- filename : 要统计的文件
- sortop : 排序方法: 0 单词排序,1 出现次数由多到少排序,2 出现次数由少到多排序
- 用法:
#!/bin/bash
if [ $# -ne 1 ] && [ $# -ne 2 ] ; then
echo "Usage: $0 filename"
echo " $0 filename sort_option"
exit -1
fi
filename=$1
egrep -o '\b\w+\b' $filename | \
awk -v opt=$2 '
function cmp_num(i1, v1, i2, v2)
{
return (v1 - v2)
}
function rcmp_num(i1, v1, i2, v2)
{
return (v2 - v1)
}
{
count[$0]++
}
END {
if (opt == 1) {
asorti(count,dst,"rcmp_num")
} else if (opt == 2) {
asorti(count,dst,"cmp_num")
} else {
asorti(count,dst)
};
printf("%-20s%s\n","Word","Count");
for (i in dst) {
printf("%-20s%d\n",dst[i],count[dst[i]])
}
}
'xargs: 定界符转换- 功能
- xargs 默认使用空白字符分割输入并执行
/bin/echo - xargs 命令把从 stdin 接收到的数据重新格式化(默认会把换行符转换为空格),再将其作为参数提供给其他命令
- xargs 命令应该紧跟在管道操作符之后,把标准输入转换为命令行参数来执行其他命令
- 有些命令只能以命令行参数的形式接受数据,例如:
find -name *.o | xargs rm -f
- xargs 默认使用空白字符分割输入并执行
- 命令参数
-n num: 表示 num 个元素之后另起一行-d separator: separator 是单个字符,表示这个字符作为定界符,例如:echo "AXBXCX" | xargs -d X
- 功能
tr set1 set2: 字符映射,集合可以使用POSIX字符类- 功能
- 将来自 stdin 的输入字符从 set1 映射到 set2,然后将输出写入 stdout
- set1 和 set2 是字符类或字符集
- 如果 set1 比 set2 大,那么 set2 会不断复制其最后一个字符,直到长度与 set1 相同
- 如果 set1 比 set2 小,那么 set2 中超出 set1 长度的那部分字符全部被忽略
- 例子
- 例如:
cat a.txt | tr 'A-Z' 'a-z' > a.txtortr '[:upper:]' '[:lower:]'将输入字符由大写转换成小写 - 例如:
cat a.txt | tr '\t' ' ' > a.txt将制表符转化为四个空格 - 例如:
cat test.txt | tr 'a-zA-Z' 'n-za-mN-ZA-M' > encryption.txt; cat encryption.txt | tr 'n-za-mN-ZA-M' 'a-zA-Z' > decryption.txtROT13 加解密
- 例如:
- 功能
tr [options] set: 字符处理- 命令参数
-d: 后面接要删除的字符集合-d -c: 后面接要保留的字符集合-s: 后面接要压缩的字符集合
- 例子
- 例如:
echo "Hello 123 world 456" | tr -d '0-9' | tr -s ' '删除数字压缩空格 - 例如:
cat file | tr -c '0-9'获取文件中所有数字
- 例如:
- 命令参数
col [options]: 字符转换- 命令参数
-x: 将 tab 键转换成对等的空格键-b: 在文字内有反斜杠时,仅保留反斜杠接的那个字符
- 命令参数
cut [options] [filename]: 切割文本- 功能
- 按列切分文件,在 cut 的术语中,每列被称为一个字段
- 命令参数
- 提取参考
-c filed: 提取特定范围的字符-b filed: 提取特定范围的字节,这些字节位置将忽略多字节字符边界,除非也指定了-n标志-f filed: 提取特定范围的字段-d separator: 指定字段的分隔符,默认的字段分隔符为 Tab
- 提取范围
N1,N2,N3...: 提取第N1,N2,N3...个字符、字节或字段,例如:cut -f 2,3 filename表示提取第2列和第3列N-: 从第N个(含)字符、字节或字段到行尾,序号从1开始N-M: 从第N个(含)字符、字节或字段到第M个(含)字符、字节或字段-M: 从第1个(含)字符、字节或字段到第M个(含)字符、字节或字段
--complement: 对提取的字段进行补集运算--output-delimiter: 后面接新的分割字符,输出使用新的分割字符
- 提取参考
- 功能
sort [options] [filename]: 排序- 功能
- 以文件行为单位进行排序,如果文件已经排序,sort 会返回为0的退出码,否则返回非0
- 命令参数
-r: 逆序-n: 按数字顺序排序-d: 以字典序进行排序-t separator: 指定排序时所用的栏位分隔字符,默认情况下,键就是文本文件中的列,列与列之间用空格分隔-k num: 按第 num 列参数的值进行排序-m: 合并两个已排序过的文件-b: 忽略文件中的前导空白行
- 功能
uniq [options]: 消除相邻的重复行,常和sort连用- 命令参数
-u: 只显示唯一的行-d: 找出重复的行-c: 统计各行出现的次数-s num: 指定可以跳过前 num 个字符-w num: 指定用于比较的最大字符数
- 命令参数
comm [options] file1 file2: 求集合,常和sort连用- 功能
- 两个文件当中行求集合,输出制表符分隔的3列,第1列放置 file1 独有的行, 第2列放置 file2 独有的行,第3列放置共有的行
- 命令参数可用
-1删除 file1 独有的行,-2删除 file2 独有的行,-3删除共有的行
- 功能
join [options] file1 file2: 联合,常和sort连用- 功能
- 两个文件当中,有 "相同数据" 的那一行,才将他加在一起
- join 默认以空格符分隔数据并且比对第1个字段的数据,如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个
- 命令参数
-t separator: 指定栏位分隔字符-i: 忽略大小写的差异-1 num: 代表第1个文件要用哪个字段来分析的意思-2 num: 代表第2个文件要用哪个字段来分析的意思
- 功能
paste [options] file1 file2: 拼接- 功能
- 将两行贴在一起,且中间以 TAB 键隔开
- 命令参数
-d separator: 后面可以接分隔字符,默认是以 TAB 来分隔-: 如果 file 部分写成-,表示来自 stdin 的数据的意思
- 功能
wc file1: 统计- 功能
- 当不使用任何选项执行 wc 时,它会分别打印出文件的行数、单词数和字符数
- 命令参数
-l: 统计行数-w: 统计单词数-c: 统计字符数-L: 打印出文件中最长一行的长度,例如:wc -L file
- 功能
cat- 功能
cat file: 显示全部文件内容cat file1 file2 file3 > file: 拼接文件echo 'Text through stdin' | cat - file1 > file: 拼接输入和文件,减号-被作为 stdin 文本的文件名- 导入多行到文件
EOF是标识符,也可以使用其它任意字符串作为标识符,导入的文件内容直到某行字符串等于标志符结束- 标识符不加单引号,文件内容中的变量会替换成它的值; 标识符加单引号,文件内容原样导入
- 保存文件前
>表示清空文件再写,>>表示追加到文件
cat <<EOF> file ... EOF cat <<EOF>> file ... EOF cat <<'EOF'> file ... EOF cat <<'EOF'>> file ... EOF
- 命令参数
-s: 压缩空行,连续空行合并为一行-b: 列出行号,空白行不列出-n: 列出行号,空白行也列出-A: 相当于-vET-v: 列出特殊字符-E: 显示结尾断行字符$-T: 制表符以^I显示
- 功能
tac- 功能
- 从最后一行开始反向显示全部文件内容
- 功能
nl- 功能
- 从第一行开始显示全部文件内容(非空行会加上行号)
- 功能
od- 功能
- 以二进位的方式读取文件内容
- 功能
more/less- 功能
- 一页一页的显示文件内容,
more只能向后翻页,less可以向前向后翻页 [Space]向下翻一页;[Enter]向下翻一行;b或[Ctrl]+b往回翻(不适用于管道文件);q离开/string向下搜这个字符串;?string向上搜这个字符串;n继续搜索;N反向继续搜索
- 一页一页的显示文件内容,
- 功能
head- 功能
- 只看头几行
- 命令参数
-n num: 列出前面 num 行,数字为负数为后面 num 行不列出
- 功能
tail- 功能
- 只看尾几行
- 命令参数
-n num: 列出后面 num 行,数字为负数为前面 num 行不列出-f: 持续监测文件,例如:tail -f /var/log/syslog等效dmesg -w
- 功能
-
pwd: 显示当前目录 -
ls [options] [filename]: 文件清单- 命令参数
-l: 详细信息-a: 隐藏文件也列出,包括.和..-A: 隐藏文件也列出,不包括.和..-d: 将目录名象其它文件一样列出,而不是列出它们的内容-F: 加类型后缀,*可执行文件/目录@符号链接|FIFOs=套接字 无后缀表示普通文件-R: 递归式操作-t: 按最近修改时间排序-h: 将文件容量以 GB MB KB 等列出
- 例如:
ls -d */orls -F | grep "/$"orls -l | grep "^d"orfind . -maxdepth 1 -type d -print列出当前目录下的目录
- 命令参数
-
cd [dirname]: 切换目录- 功能
/根目录.当前目录..上一层目录-前一工作目录~当前用户家目录~lengjing用户 lengjing 家目录cd /xxx/xxx/...进绝对路径目录 ;cd ./xxx/xxx/...进相对路径目录
- 功能
-
pushd [dirname]popddirs: 压入并切换路径 / 删除最近压入的路径并切换到下一个目录 / 查看栈的内容 -
mkdir [options] [dirname]: 创建目录- 命令参数
-m n1n2n3: 设权限-p: 上层目录没有也会递归创建,文件存在也不报错
- 命令参数
-
rmdir [options] [dirname]: 删除空目录,目录有文件要用rm -r- 命令参数
-p: 连上一层空目录也删除,一直到不是空目录停止
- 命令参数
-
stat [filename]: 显示文件信息 -
file [filename]: 查看文件类型 -
touch [filename]: 新建空文件- 说明
- 如果文件已经存在,那么 touch 命令会将与该文件相关的所有时间戳都更改为当前时间
touch -a只更改文件访问时间,touch -m只更改文件修改时间。
- 如果文件已经存在,那么 touch 命令会将与该文件相关的所有时间戳都更改为当前时间
- 说明
-
mktemp: 生成一个临时文件并返回其文件名- 说明
- 如果提供了定制模板(至少3个
X),X会被随机的字符(字母或数字)替换
- 如果提供了定制模板(至少3个
- 命令参数
-d: 生成一个临时目录并返回其目录名-u: 生成文件名,不创建实际的文件或目录
- 说明
cp [options] [srcs] [dst]: 复制文件,srcs 可以是多个项目- 命令参数
-ror-R: 递归复制-f: dst 无法打开时,删除 dst 再试复制-d: 保留符号链接属性,符号链接指向的文件不存在时也可以复制,相当于--preserve=links-p: 连同属性也复制(符号链接)(备份常用),相当于--preserve=mode,ownership,timestamps-i: 询问是否覆盖-a: 保留属性,递归的复制,相当于-dR --preserve=all-s: 创建符号链接,也可以用ln -s创建符号链接-u: 仅在源文件比目标文件新,或者目标文件不存在的情况下复制
- 命令参数
mv [options] [srcs] [dst]: 移动文件,可以用来重命名,srcs 可以是多个项目- 命令参数
-f: 同名档案直接覆盖-p: 保持权限-i: 询问是否覆盖-u: 比已有文件新则覆盖(update)
- 命令参数
rm [options] [filename]: 删除文件,命令删除是没有回收站的- 命令参数
-ror-R: 递归地删除(常用于删除有文件的目录)-f: 忽略文件不存在时的警告信息-i: 询问是否删除
- 命令参数
ln [options] [src] [dst]: 给文件或目录创建链接- 说明
- 不指定 dst 时 dst 的名字取
basename $src - Hard Link (实体链接, 硬链接或实际链接),多个档名连结到同一个 inode,hard link 是有限制的: 不能跨 Filesystem,不能 link 目录
- Symbolic Link (符号链接,软链接或快捷方式),创建一个独立的文件,而这个文件会让数据的读取指向他 link 的那个文件的档名
- 不指定 dst 时 dst 的名字取
- 命令参数
-f: 如果目标文件存在时,就主动的将目标文件直接移除后再创建,文件夹还要加上-T-r: 创建相对路径的符号链接-s: 添加符号链接,如果不加任何参数就进行硬链接-T: 总是将给定的链接名当作普通文件
- 说明
gzip/gunzip/zcatbzip2/bunzip2/bzcatxz/unxz/xzcat- 功能
- gzip 默认压缩 / gunzip 默认解压 / zcat 默认查看
- bzip2 默认压缩 / bunzip2 默认解压 / bzcat 默认查看
- xz 默认压缩 / unxz 默认解压 / xzcat 默认查看
- 通过选项可以改变默认行为:
-z强制压缩 /-d强制解压 /-t测试压缩文件 /-l列出压缩信息 - 注: gzip 族不支持
-z选项
- 命令参数
-1...-9: 设置压缩等级,默认是 -6,压缩最高是 -9-k: 保留输入文件(压缩解压默认会删除原文件)-f: 强制覆盖输出文件-h: 帮助信息-v: 显示进度等信息-T <num>: 多线程支持(仅 xz 族命令)
- 功能
tartar -[Jjz] -c -f [tarname] [objects] -C [dir] tar -x -f [tarname] -C [dir] tar -t -f [tarname]- 使用说明
- 可以将选项写在一起 (UNIX-style),例如:
tar -Jcvf test.tar.xz test - 可以省略横线
-(Traditional Style),例如:tar Jcvf test.tar.xz test
- 可以将选项写在一起 (UNIX-style),例如:
- 压缩类型选项
-J: 选择 xz 压缩算法,此时 tarname 需要命名为*.tar.xz-j: 选择 bz2 压缩算法,此时 tarname 需要命名为*.tar.bz2-z: 选择 gzip 压缩算法,此时 tarname 需要命名为*.tar.gz-a: 自动根据后缀选择压缩算法
- 处理方式选项
-c: 压缩-x: 解压-t: 查看
- 其它选项
-f [tarname]: 打包文件名-C [dir]: 进入指定目录打包(否则包含路径)或解压到指定目录(否则当前目录)- 例如打包test目录下的内容且不包含test目录:
tar -Jcvf test.tar.xz -C test .
- 例如打包test目录下的内容且不包含test目录:
-v: 显示处理信息-p: 保留属性-P: 保留绝对路径--exclude-vcs: 打包时排除版本控制相关的文件和目录
- 使用说明
-
split [options] [filename] [prefix]: 分割文件,prefix为前缀名称- 命令参数
-x: 以数字命名后缀而不是字母命名-a num: 指定分割的后缀的位数num,默认2位-b value: 多大一个文件,单位有:c1 byte;w2 bytes;b512 bytes;k1024 bytes;M1024k bytes;G1024M bytes-l num: 多少行一个文件-n CHUNKS: 分割成指定个文件N: 均分为 N 个文件l/N: 约均分为 N 个文件,但分割位置不会拆分行K/N: 打印均分为 N 份时的第 K 份内容到屏幕l/K/N: 打印约均分为 N 份时的第 K 份内容到屏幕r/N: 类似l/N,但是使用round robin distributionr/K/N: 类似l/K/N,但是使用round robin distribution
- 命令参数
-
csplit [options] [filename] [pattern...]: 匹配分割文件- 命令参数
-b suffix: 设置后缀格式,可用格式化输出符,例如%04d.txt-f prefix: 设置前缀字符串,默认是xx-n num: 指定分割的后缀的位数num,默认2位-s: 静默模式,不显示输出文件的尺寸计数
- 匹配模式 pattern
N: 复制至指定行(不含)一个文件,其它又一个文件/regexp/offset: 复制至匹配行(不含)一个文件,其它又一个文件,offset可选,可用正+N负-N整数%regexp%offset: 跳过直至匹配行(不含)丢弃内容,其它又一个文件{N}: 将之前指定的模式重复 N 次{*}: 将之前指定的模式重复尽可能多的次数
- 命令参数
- 档案属性:
drwxr-xr-x 34 lengjing lengjing 4096 Aug 20 10:07 lengjing/- 第一个字符表示
档案类型d目录-文件l链接b区块设备(硬盘等)c字符设备(键盘鼠标等)s数据接口文件(sockets)p数据输送文件(FIFO)
- 随后每三个字符表示
所有者权限所属群组权限其他用户权限r可读(read)w可写(write)x可执行(execute)-无权限- 权限对文件的重要性
- r(read): 可读取此一文件的实际内容,如读取文本文件的文字内容等
- w(write): 可以编辑、新增或者是修改该文件的内容(但不含删除该文件)
- x(execute): 该文件具有可以被系统执行的权限
- 权限对目录的重要性
- r(read contents in directory): 具有读取目录结构列表的权限(ls指令可用)
- w(modify contents of directory): 具有改变该目录结构列表的权限
- 建立新的文件与目录
- 删除已经存在的文件或目录(不管对文件权限如何)
- 将已存在的文件或目录进行更名
- 搬移该目录内的文件、目录位置
- x(access directory): 进入该目录的权限(cd指令可用)
- 开放目录给任何人浏览时,应该至少也要给予 r x 的权限
- 然后是
连接数,表示有多少档名连结到此节点(i-node)(目录下文件数,包括.和..) - 接着是
所有者所属群组容量大小(默认单位为 bytes)最后修改时间 - 最后是
档案名称- 使用
Ext4/Ext3文件系统,单一档名可达 255 字符,完整文件名(包含路径)可达 4096 个字符 - 点号
.开头的档名,表示这个档案为隐藏档案
- 使用
- 第一个字符表示
- 特殊权限
4为SUID(Set UID)- 档案所有者的可执行权限位显示为
s时为SUID权限 - SUID 目前只针对文件有效,使用者运行此程序时,在运行过程中 (run-time) 用户会暂时具有程序拥有者 (owner) 的权限
- SUID 只能应用在 Linux ELF 格式的二进制文件上,你不能对脚本设置 SUID
- 档案所有者的可执行权限位显示为
2为 SGID` (Set GID)- 档案所属群组的可执行权限位显示为
s时为SGID权限 - 对文件来说,使用者运行此程序时(需具备 x 的权限),在运行过程中 (run-time) 用户会暂时具有程序所属群组 (owner) 的权限
- 对目录来说,使用者在此目录下创建的新档案时(需具备 r x 的权限),新档案的群组与此目录的群组相同
- 档案所属群组的可执行权限位显示为
1为SBIT(Sticky Bit)- 档案其他用户的可执行权限位显示为
t或T时为SBIT权限(粘滞位),典型例子就是/tmp - SBIT 目前只针对目录有效,使用者在此目录下创建的新档案时(需具备 w x 的权限),仅有自己与 root 才有权力删除该文件
- 档案其他用户的可执行权限位显示为
$ ls -ld /tmp /usr/bin/passwd drwxrwxrwt 13 root root 4096 8月 9 11:27 /tmp -rwsr-xr-x 1 root root 59640 3月 23 2019 /usr/bin/passwd
- 修改属性
chmod: 更改权限- 对符号链接来说,一般不考虑它的权限,而考虑它引用的文件的权限。
- 例如:
chmod u+x configure或chmod 744 configure给 configure 文件加上可执行权限 - 例如:
chmod a+t dir设置 SBIT - 例如:
chmod +s binname设置 SUID - 例如:
chattr +i filechattr -i file设置文件不可修改和取消设置
chmod [usertype sign type] [filename] 或 chmod [n1n2n3] [filename] u用户 +添加 r可读 r=4 w=2 x=1 g同组 -取消 w可写 o其他 =赋予 x可执行 a所有(可省略)chown [owner] [filename]: 修改所有者chown [owner:grouper] [filename]: 同时修改所有者和组chgrp [grouper] [filename]: 修改所有组
注: 这四个 chxxx 命令都可以用 -R 选项进行递归式操作
- 文件系统层次
superblock: 记录此 filesystem 的整体信息- block 与 inode 的总量
- 未使用与已使用的 inode / block 数量
- block 与 inode 的大小 (block 为 1, 2, 4K, inode 为 128 bytes)
- filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息
- 一个 valid bit 数值,若此文件系统已被挂载,则 valid bit 为 0 ,若未被挂载,则 valid bit 为 1 。
- 一般来说 superblock 的大小为 1024bytes
inode: 记录文件的属性- 该文件的数据所在的 block 号码
- 该文件的存取模式 (read/write/excute)
- 该文件的拥有者与群组 (owner/group)
- 该文件的容量
- 最近一次的读取时间 (atime)
- 最近创建或状态改变的时间 (ctime)
- 最近修改的时间 (mtime)
- 定义文件特性的标志 (flag),如 SetUID ...
- 该文件真正内容的指向 (pointer)
- inode 属性说明:
- 每个 inode 大小均固定为 128 bytes
- 每笔 block 号码的记录会花去 4bytes
- inode 记录 block 号码的区域定义为12个直接,1个间接, 1个双间接与1个三间接记录区。总额: 将直接、间接、双间接、三间接加总
- 每个文件都仅会占用一个 inode,因此文件系统能够创建的文件数量与 inode 的数量有关
- 系统读取文件时需要先找到 inode,并分析 inode 所记录的权限与用户是否符合,若符合才能够开始实际读取 block 的内容
- 文件名只与目录有关,但是文件内容则与 inode 有关
block: 实际记录文件的内容- 若文件太大时,会占用多个block,每个 block 内最多只能够放置一个文件的数据
注: 可以将一个分割槽格式化为多个文件系统(LVM),也能够将多个分割槽合成一个文件系统(RAID),linux 采用索引式文件系统,基本上不太需要常常进行碎片整理
- 文件系统操作
-
df [options] [filename or dirname]- 功能
- 列出文件系统的信息,不加名字时列出所有文件系统
- 命令参数
-a: 列出所有的文件系统,包括系统特有的/proc等文件系统-h: 以人们较易阅读的 GBytes, MBytes, KBytes 等格式自行显示容量-k: 以 KBytes 列出容量显示-m: 以 MBytes 列出容量显示-H: 以 M=1000K 取代 M=1024K 的进位方式-T: 连同文件系统类型也列出-i: 不用容量,而以 inode 的数量来显示
- 功能
-
du [options] [filename or dirname]- 功能
- 统计文件或文件夹的磁盘使用量,不加名字时默认是当前文件系统
- 命令参数
-a: 列出所有的文件与目录容量,默认仅统计当前目录底下的文件量而已-h: 以人们较易读的容量格式 (G/M) 显示-k: 以 KBytes 列出容量显示-m: 以 MBytes 列出容量显示-s: 列出总量而已,而不列出每个各别的目录占用容量-S: 不包括子目录下的总计
- 功能
-
mount [-t fstype] [-L Label ] [-o extra_options] [-n] [devname] [mountdir]- 功能
- 磁盘挂载
- 例如: 重新挂载根目录
sudo mount -o remount,rw,auto / - 例如: 手动挂载 ntfs:
sudo mount -t ntfs /dev/sda2 /home/ntfspd - 例如: 手动挂载 nfs:
sudo mount -t nfs <ip_addr>:<path> <mount_path> -o vers=3,nolock,proto=tcp,rsize=32768,wsize=32768 - 例如: 手动挂载 smb:
sudo mount -t cifs //<ip_addr>/<path> <mount_path> -o forceuid,forcegid,uid=1000,gid=1000,domain=<str1>,username=<str2>,password=<str3>,vers=2.0 - 进行挂载前,你最好先确定几件事:
- 单一文件系统不应该被重复挂载在不同的挂载点(目录)中
- 单一目录不应该重复挂载多个文件系统
- 要作为挂载点的目录,理论上应该存在且是空目录
- 功能
-
umount [options] [devname or mountdir]- 功能
- 磁盘卸载
- 命令参数
-f: 强制卸载,可用在类似网络文件系统 (NFS) 无法读取到的情况下-n: 不升级 /etc/mtab 情况下卸除
- 功能
-
fdisk [options] [devname]- 功能
- 磁盘分区相关操作,需要 root 权限
- fdisk 没有办法处理大于 2TB 以上的磁盘分区槽,此时得使用
parted,例如: 查看你的磁盘的分区类型sudo parted /dev/sda print
- 命令参数
-l: 列出指定分区信息,若仅有fdisk -l时,则全部 partition 均列出来
- 功能
-
dumpe2fs [options] [devname]- 功能
- 列出区段与 superblock 的信息,需要 root 权限
- devname 是文件系统设备,例如:
/dev/sda1
- 命令参数
-h: 仅列出 superblock 的数据,不会列出其他的区段内容-b: 列出保留为坏轨的部分
- 功能
-
mkfs [-t fstype] [options] [devname]- 功能
- 磁盘格式化
- 命令参数
-b: 可以配置每个 block 的大小,目前支持 1024, 2048, 4096 bytes 三种-i: 多少容量给予1个 inode-c: 检查磁盘错误,仅下达一次-c时,会进行快速读取测试;如果下达两次-c-c的话,会测试读写(read-write),会很慢
- 功能
-
fsck [-t fstype] [options] [devname]- 功能
- 磁盘检验,运行 fsck 时, 被检查的 partition 需要在卸载的状态
- 命令参数
-A: 依据 /etc/fstab 的内容,将需要的装置扫瞄一次-aor-y: 自动修复检查到的有问题的扇区,不用一直按 y-f: 强制细部检查-D: 针对文件系统下的目录进行优化配置
- 功能
-
dd if=src of=dst bs=size count=num- 功能
- 读取、转换并输出数据,源和目标可以是是文件或设备
if=: 源,两个常用的源:/dev/zero返回全0,/dev/random返回随机数of=: 目标bs=: 每次复制的大小,单位有:c1 byte;w2 bytes;b512 bytes;K1024 bytes;M1024k bytes;G1024M bytescount=: 复制的次数
- 功能
-
- 例子: U盘的某些命令
- 格式化
sudo fdisk -l # 查看挂载 sudo umount /dev/sdb1 # 必须先卸载该分区 sudo mkfs.vfat -F 32 /dev/sdb1 # -F 参数必须大写,参数有 12,16 和 32,分别对应FATxx
- 检测U盘坏块
badblocks -b 4096 -sv /dev/sdb
- 只读修复
ll /dev/disk/by-id/ # 查看对应的硬盘 sudo fsck -a /dev/disk/by-id/devname # fsck命令进行硬盘修复
-
git init: 新建一个Git代码库 -
git clone: 克隆Git资源 -
...: 修改工作区文件 -
git add/rm/mv: 将工作区修改提交到暂存区 -
git commit: 将暂存区修改提交到仓库区 -
git push: 将仓库区修改提交到远程仓库 -
Git的4个工作区
Workspace: 工作区Index/Stage: 暂存区(索引区)Repository: 仓库区(或本地仓库)Remote: 远程仓库
-
git config常用选项
选项 说明 配置文件路径 --system使用系统级配置文件 /etc/gitconfig--global使用全局配置文件 ~/.gitconfig--local使用仓库级配置文件 .git/config-f, --file <filename>使用指定的配置文件 -l, --list查看Git配置文件 -e, --edit编辑Git配置文件 -
查看Git全局配置文件
git config -l --global
-
编辑Git全局配置文件
git config -e --global
-
设置提交代码时的全局用户信息
git config --global user.name "name"git config --global user.email "email_address"
-
全局别名设置
git config --global alias.co checkoutgit config --global alias.br branchgit config --global alias.ci commitgit config --global alias.st status
-
commit编辑器 nano 改 vim
git config --global core.editor vim
-
配置图形化比较工具为 meld
git config --global diff.tool meld
-
配置图形化比较工具为 Beyond Compare
git config --global diff.tool bc3git config --global difftool.bc3.path "/usr/bin/bcompare"- 注:
~/.config/bcompare/registry.dat为 bc3 的许可证文件
- 将当前目录初始化为Git代码库
git init
- 新建dir目录,将其初始化为Git代码库
git init [dir]
- 克隆一个项目到当前目录
git clone [url]- 例:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git: 克隆linux kernel仓库
- 克隆一个项目到到指定目录dir
git clone [url] [dir]
注: 在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录(Git的版本库),该目录包含了资源的所有元数据
- 添加指定(修改的/新建的)文件或目录(包括子目录)到暂存区
git add [file] [dir] ...
- 强制添加指定(修改的/新建的)文件或目录(包括子目录)到暂存区,.gitignore中忽略的也提交
git add -f [file] [dir]
- 监控工作区的状态树,使用它会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件。
git add .
- 仅监控已经被add的文件(即tracked file),他会将被修改删除的文件提交到暂存区,不会提交新文件
git add -u
- 是上面两个功能的合集(git add --all的缩写)
git add -A
- 添加每个变化前,都会要求确认,对于同一个文件的多处变化,可以实现分次提交
git add -p
- 删除工作区文件,并且将这次删除放入暂存区
git rm [file1] [file2] ...
- 删除工作区文件夹,并且将这次删除放入暂存区
git rm -r [dir] ...
- 删除仓库区文件,并且将这次删除放入暂存区
git rm -f [file1] [file2]...
- 停止追踪指定文件,但该文件会保留在工作区
git rm --cached [file]
- 改名文件,并且将这个改名放入暂存区
git mv [file-original] [file-renamed]
- 提交暂存区到仓库区,会跳出编辑器让你输入提交信息
git commit
- 提交暂存区到仓库区,-m接提交信息
git commit -m [message]
- 提交暂存区的指定文件到仓库区
git commit [file1] [file2] ...
- 提交工作区自上次commit之后的变化,直接到仓库区
git commit -a
- 提交时显示所有diff信息
git commit -v
- 提交时在上一次的提交上盖楼
git commit --amend
- 列出所有本地分支
git branch
- 列出所有远程分支
git branch -r
- 列出所有本地分支和远程分支
git branch -a
- 新建一个分支,但依然停留在当前分支
git branch [branch-name]
- 新建一个分支,并切换到该分支
git checkout -b [branch]
- 新建一个分支,指向指定commit
git branch [branch] [commit]
- 切换到指定分支,并更新工作区
git checkout [branch-name]
- 切换到上一个分支
git checkout -
- 新建一个分支,与指定的远程分支建立追踪关系
git branch --track [branch] [remote-branch]
- 建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream [branch] [remote-branch]
- 合并指定分支到当前分支
git merge [branch]
- 选择一个commit,合并进当前分支
git cherry-pick [commit]
- 删除分支
git branch -d [branch-name]
- 删除远程分支
git push origin --delete [branch-name]git branch -dr [remote/branch]
- 列出所有tag
git tag
- 列出所有tag,时间倒序
git tag --sort=-taggerdate
- 新建一个tag在当前commit
git tag [tag]
- 新建一个tag在指定commit
git tag [tag] [commit]
- 删除本地tag
git tag -d [tag]
- 删除远程tag
git push origin :refs/tags/[tagName]
- 查看tag信息
git show [tag]
- 提交指定tag
git push [remote] [tag]
- 提交所有tag
git push [remote] --tags
- 新建一个分支,指向某个tag
git checkout -b [branch] [tag]
- 显示有变更的文件
git status
- 显示当前分支的版本历史
git log
- 显示当前分支的含commit date的版本历史
git log --pretty=fuller
- 显示commit历史,以及每次commit发生变更的文件
git log --stat
- 搜索特定用户的提交历史
git log --author=[author_name]
- 搜索提交历史,根据关键词
git log -S [keyword]
- 显示某个commit之后的所有变动,每个commit占据一行
git log [tag] HEAD --pretty=format:%s
- 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
git log [tag] HEAD --grep feature
- 显示某个文件的版本历史,包括文件改名
git log --follow [file]git whatchanged [file]
- 显示指定文件相关的每一次diff
git log -p [file]
- 显示过去5次提交
git log -5 --pretty --oneline
- 显示所有提交过的用户,按提交次数排序
git shortlog -sn
- 显示指定文件是什么人在什么时间修改过
git blame [file]
- 显示暂存区和工作区的差异
git diff
- 显示暂存区和上一个commit的差异
git diff --cached [file]
- 显示工作区与当前分支最新commit之间的差异
git diff HEAD
- 显示两次提交之间的差异
git diff [first-branch]...[second-branch]
- 显示今天你写了多少行代码
git diff --shortstat "@{0 day ago}"
- 显示某次提交的元数据和内容变化
git show [commit]
- 显示某次提交发生变化的文件
git show --name-only [commit]
- 显示某次提交时,某个文件的内容
git show [commit]:[filename]
- 显示当前分支的最近几次提交
git reflog
- 下载远程仓库的所有变动
git fetch [remote]
- 显示所有远程仓库
git remote -v
- 显示某个远程仓库的信息
git remote show [remote]
- 增加一个新的远程仓库,并命名
git remote add [shortname] [url]
- 取回远程仓库的变化,并与本地分支合并
git pull [remote] [branch]
- 上传本地指定分支到远程仓库
git push [remote host] [local branch]git push [remote host] [local branch]:[remote branch]- 例如:
git push origin masterorgit push origin master:masterorgit push origin HEAD:refs/heads/masterorgit push直接推入库中 - 例如:
git push origin HEAD:refs/for/master先推入gerrit评审中
- 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --force
- 推送所有分支到远程仓库
git push [remote] --all
- 恢复暂存区的指定文件到工作区
git checkout [file]
- 恢复某个commit的指定文件到暂存区和工作区
git checkout [commit] [file]
- 恢复暂存区的所有文件到工作区
git checkout .
- 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
git reset [file]
- 重置暂存区与工作区,与上一次commit保持一致
git reset --hard
- 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
git reset [commit]
- 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
git reset --hard [commit]
- 重置当前HEAD为指定commit,但保持暂存区和工作区不变
git reset --keep [commit]
- 新建一个commit,用来撤销指定commit,后者的所有变化都将被前者抵消,并且应用到当前分支
git revert [commit]
- 暂时将未提交的变化移除,稍后再移入
git stashgit stash pop
- 清除未被跟踪的文件(
-f)和文件夹(-d),包含.gitignore中忽略的(-x)git clean -fdx
- 生成一个可供发布的压缩包
git archive
- 生成最近一次提交的patch
git format-patch HEAD^orgit format-patch -1- 在Git中,
HEAD表示当前版本,HEAD^表示上一个版本,HEAD^^表示上上一个版本,HEAD~N表示上N一个版本
- 本地变更 git diff 的内容,生成patch文件
git diff > xxxx.patch
- 合并patch到其它仓库,dest_patch_dir为要打补丁的目录(git根目录可省略)
git am --directory='dest_patch_dir' xxxx.patch
- 合并patch到其它仓库
git apply xxxx.patch- git apply与git am的区别是:
git apply并不会将commit message等打上去,打完patch后需要重新git add和git commitgit am会直接将patch的所有信息打上去,而且不用重新git add和git commit
- 合并内核patch,dest_patch_dir为要打补丁的目录,src_patch_dir为存放补丁的目录
- 假设本地版本为4.9.150,网站下载增量补丁patch-4.9.150-151.xz,解压后修改名字patch-4.9.151
./scripts/patch-kernel dest_patch_dir src_patch_dir
- diff 生成补丁和 patch 打补丁和删除补丁
- 例如:
diff -rapuN --no-dereference -x .git linux-5.15 linux-5.15.120 > linux-5.15.120.patch
- 例如:
#!/bin/bash
patch_opt=$1
patch_src=$2
patch_dst=$3
patch_arr=""
if [ -e ${patch_dst} ]; then
for src in ${patch_src}; do
if [ -d ${src} ]; then
for ssrc in $(\ls ${src}); do
if [ $(echo ${ssrc} | grep -c '\.patch$') -eq 1 ]; then
patch_arr="${patch_arr} ${src}/${ssrc}"
fi
done
elif [ -f ${src} ]; then
patch_arr="${patch_arr} ${src}"
else
echo "Warning: ${src} is unexisted."
fi
done
for src in ${patch_arr}; do
patch_state="$(patch -p1 -R -s -f --dry-run -d ${patch_dst} < ${src})"
if [ ${patch_opt} = "patch" ] && [ ! -z "${patch_state}" ]; then
patch -p1 -b -d ${patch_dst} < ${src}
echo "Patch ${src} to ${patch_dst} Done."
elif [ ${patch_opt} = "unpatch" ] && [ -z "${patch_state}" ]; then
patch -p1 -R -d ${patch_dst} < ${src}
echo "Unpatch ${src} to ${patch_dst} Done."
fi
done
fi-
初始化
repo init -u url -m xml -b branch && repo sync: 下载repo并克隆manifest-u url: 指定一个URL,其连接到一个maniest仓库-m xml: 在manifest仓库中选择一个xml文件-b branch: 选择一个maniest仓库中的一个特殊的分支repo sync: 同步代码,更新代码到最新
-
一般工作步骤
repo start test .: 建立本地开发分支vi xxxx.c: 修改代码xxxx.cgit add xxxx.c: 修改提交到暂存区git commit xxxx.c: 暂存区提交到到本地仓库- 盖楼提交使用
git commit --amend
- 盖楼提交使用
repo upload .: 代码提交到远程服务器repo abandon test .: 删除本地分支
- 注意:
- 解决新的问题重做1-6步骤
- 如果这个问题还要修改并且已经做了第4步,但是没有做第6步,重做2-6步骤,第4步使用
git commit --amend - 如果这个问题还要修改(修改未merge)并且已经做了第6步,重做1-6步骤,第1步和第2步之间运行
Cherry Pick命令("问题网页downloads的Cherry Pick的字符串"),第4步使用git commit --amend - 如果这个问题还要修改(修改已merge), 删除本地分支再重做1-6步骤
-
其他repo命令
repo checkout: 切换分支repo branches: 查看分支repo diff: 查看工作区文件差异repo checkout: 切换分支repo status: 查看文件状态
-
在所有git仓库运行命令
repo forall -vc "COMMAND TO EXECUTE"-v是详细的,因此它将打印命令的输出-c "COMMAND TO EXECUTE"是您想要的实际命令- 例如清除所有修改
repo forall -vc "git reset --hard; git clean -fdx"
- 初始化
svn co URL
- 同步代码
- 同步代码到最新
svn up
- 同步代码到指定reversion
svn up -r [reversion]
- 同步代码到最新
- 增加/删除文件
- 添加指定(修改的/新建的)文件或目录(包括子目录)
svn add [file] [dir] ...
- 删除指定文件或目录(包括子目录)
svn rm [file] [dir] ...
- 添加目录下的所有类型的文件
svn add [dir] --no-ignore --force
- 添加指定(修改的/新建的)文件或目录(包括子目录)
- 撤销修改(未ci)
svn revert [file]svn revert -R [dir]
- 撤销修改(已ci)
svn merge -r [newest reversion]:[revert reversion] [dir] ; svn ci -m "revert from rxxx to rxxx"
- 提交代码
- 提交代码到服务器,会跳出编辑器让你输入提交信息
svn ci- 注: svn修改编辑器是将
editor-cmd = vim加入~/.subversion/config
- 提交代码到服务器,-m接提交信息
svn ci -m [message]
- 提交代码到服务器,会跳出编辑器让你输入提交信息
- 查看信息
- 显示有变更的文件
svn st
- 查看当前工作副本log
svn log
- 只查看指定版本的log
svn log -r [reversion]
- 查看特定时间范围内的log
svn log -r {2022-1-1}:{2022-8-1}
- 查看当前工作区的所有改动
svn diff
- 查看当前工作区和指定版本的差异
svn diff -r [reversion]
- 显示两个版本间的差异
svn diff -r [newreversion]:[oldreversion]
- 显示指定文件是什么人在什么时间修改过
svn blame [file]
- 显示有变更的文件
- 查看svn配置信息
svn info
- 查看SVN帮助
svn help