我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
Bash 教程
本文改编自 网道的 Bash 教程,主要为了精简大量本人不感兴趣的内容。
Bash & Shell 简介
Bash 是 Unix 系统和 Linux 系统的一种 Shell(命令行环境),是目前绝大多数 Linux 发行版的默认 Shell。
Shell 的原意是 外壳,跟 kernel(内核)相对应。
Shell 提供了一个与用户对话的命令行环境(command line interface,CLI),通过 CLI 将用户从键盘输入的命令送入操作系统执行,并将结果返回给用户。
Shell 有很多种,只要能给用户提供命令行环境的程序,都可以看作是 Shell。
wsl # 启动后显示的【bqt@BQT-X】代表【user@host】,【$】代表普通用户,【#】代表 root 用户
uname -a # 显示电脑以及操作系统的相关信息【Linux BQT-X 4.19.128... GNU/Linux】
echo $SHELL # 【/bin/bash】,查看当前运行的 Shell
cat /etc/shells # 查看当前的 Linux 系统安装的所有 Shell
bash --version # 【echo $BASH_VERSION】,查看本机的 Bash 版本
bash # 如果当前运行的 Shell 不是 Bash,可以输入 bash 命令启动 Bash
exit # 退出 Bash 环境
快捷键
- 命令自动补全:命令或路径输入到一半的时候,可以按下 Tab 键,Bash 会自动完成剩下的部分
- 路径选择提示:按下 Tab 键后,如果有多个可能的选择,再按一次 Tab 键,Bash 会显示所有选项让你选择
Ctrl + L
:将当前行移到页面顶部,并非清屏,通过滚轮可以查看滑出屏幕的内容Ctrl + C
:中止当前正在执行的命令Ctrl + D
:关闭 Shell 会话↑/↓
:浏览已执行命令的历史记录Shift + PgUp/PgDn
:向上/下滚动---无效Ctrl + U
:删除光标前面容Ctrl + K
:删除光标后门的内容
Bash 语法
基本语法
# 基本格式
command [arg1...argN] # command 是具体的命令或者一个可执行文件
echo foo bar # 【foo bar】,Bash 使用空格或 Tab 分割参数,多个连续的空格会被当做一个空格
# 组合命令
Command1; Command2 # 先执行 Command1,结束后再继续执行 Command2
Command1 && Command2 # 先执行 Command1,如果 Command1 运行成功,则继续运行 Command2
Command1 || Command2 # 先执行 Command1,如果 Command1 运行失败,则继续运行 Command2
echo 命令
echo 白 "白" '白' # 【白 白 白】,字符串可以使用双引号、单引号包裹,也可以省略引号
echo # 【(换行)】,默认情况下,输出的文本末尾会有一个回车符
echo -n a; echo b # 【ab】,取消末尾的回车符
type 命令
# type 命令用来判断命令的来源(内置命令、外部程序)
type echo # 【echo is a shell builtin】,内置命令
type ls # 【ls is aliased to `ls --color=auto'】,别名
type bash # 【bash is /usr/bin/bash】,文件
type -a echo # 查看一个命令的所有定义
type -t bash # 【file】,返回一个命令的类型:alias,keyword,function,builtin,file
Bash 变量
Bash 变量分成环境变量和自定义变量两类。
- 环境变量是 Bash 环境自带的变量,可以直接使用。通常是系统定义好的,也可以由用户从父 Shell 传入子 Shell。
- 自定义变量是用户在当前 Shell 里面自己定义的变量,仅在当前 Shell 可用。
set # 显示所有变量(包括环境变量和自定义变量),以及所有的 Bash 函数
环境变量
很多环境变量很少发生变化,而且是只读的,可以视为常量。
由于环境变量的变量名全部都是大写,所以传统上,如果用户要自己定义一个
常量
,也会使用全部大写的变量名。
env # 【printenv】,显示所有环境变量
echo $PATH # 【printenv PATH】,查看单个环境变量的值
echo -e ${PATH//:/"\n"} # 将环境变量 PATH 中的所有分隔符,由【:】替换成【\n】,并解释为换行符
echo -e "$BASHPID \n$BASHOPTS \n$DISPLAY \n$EDITOR \n$HOME \n$HOST \n$IFS \n$LANG"
echo -e "$PS1 \n$PS2 \n$PWD \n$RANDOM \n$SHELL \n$SHELLOPTS \n$TERM \n$UID \n$USER"
常见的环境变量。
BASHPID
:【104】Bash 进程的进程 IDBASHOPTS
:当前 Shell 的参数,可以用shopt
命令修改DISPLAY
:图形环境的显示器名字,通常是:0
,表示 X Server 的第一个显示器EDITOR
:默认的文本编辑器HOME
:【/home/bqt】用户的主目录HOST
:当前主机的名称。IFS
:词与词之间的分隔符,默认为空格LANG
:【C.UTF-8】字符集以及语言编码,比如zh_CN.UTF-8
PATH
:由冒号分开的目录列表,当输入可执行程序名后,会搜索这个目录列表PS1
:Shell 提示符PS2
:【>】输入多行命令时,次要的 Shell 提示符PWD
:【/home/bqt】当前工作目录RANDOM
:【19211】返回一个0到32767之间的随机数SHELL
:【/bin/bash】Shell 的名字SHELLOPTS
:启动当前 Shell 的set
命令的参数TERM
:【xterm-256color】终端类型名,即终端仿真器所用的协议UID
:【1000】当前用户的 ID 编号USER
:【bqt】当前用户的用户名
定义变量
- 变量名的规则和 Java 等编程语言一样
- 变量名区分大小写
- Bash 没有数据类型的概念,所有的变量值都是字符串
- 注意,变量名和等号之间不能有空格
var=value # 变量名区分大小写,变量值都是字符串
b="b qt" # 如果变量值包含空格,必须放在引号里面
e=$(pwd) # 【e=`pwd`】变量值可以是命令的执行结果
f=$((5*7)) # 变量值可以是数学运算的结果
foo=1;bar=2 # 同一行定义多个变量,必须使用分号分隔
for file in $(ls $(pwd)); do echo $file; done
读取变量
- 如果变量不存在,会输出空字符,而不会报错
- 在变量名与其他字符连用的情况下,必须使用 花括号 包围的格式:
${var}
- 如果变量的值本身也是变量,必须在变量前面加 感叹号 才能读取最终的值:
${!var}
- 变量值包含连续空格、制表符、换行符时,直接读取时会被合并成一个空格;放在 双引号 里面能保持原来的格式
echo $100.00 # 【00.00】Bash 将【$1】解释成了变量,该变量不存在,会输出空字符
echo \$100.00 # 【$100.00】加反斜杠进行转义
bqt=baiqiantao
echo $bqt2022 # 【(空)】Bash 将其整个 bqt2022 解释为变量,而这个变量是不存在的
echo ${bqt}2022 # 【baiqiantao2022】在变量名与其他字符连用的情况下,必须使用花括号包围
var=USER
echo $var # 【USER】
echo ${!var} # 【bqt】如果变量的值本身也是变量,必须使用【${!var}】读取最终的值
a="1 2 3"
echo $a # 【1 2 3】直接读取时,Shell 会将连续空格合并成一个
echo "$a" # 【1 2 3】放在双引号里面读取时,能保持原来的格式
删除变量
unset
命令用来删除一个变量,这个命令等价于将变量设成空字符串。
这个命令不是很有用,因为不存在的 Bash 变量一律等于空字符串,所以即使用
unset
命令删除了变量,还是可以读取这个变量,值为空字符串。
# 以下三种方式效果是一样的
unset bqt
bqt=''
bqt=
特殊变量 & 传递参数
Bash 提供一些特殊变量。这些变量的值由 Shell 提供,用户不能进行赋值。
$0
:当前 Shell 的名称(在命令行直接执行时),或者脚本文件名(在脚本中执行时)$n
:传递到脚本的第 n 个参数的值,建议使用${n}
来获取$#
:传递到脚本的参数数量$*
:显示所有向脚本或函数传递的参数,与$@
基本相同,区别见下文$@
:显示所有向脚本或函数传递的参数,与$*
基本相同,区别见下文$?
:上一个命令的退出码,返回0
表示上一个命令执行成功;否则,表示上一个命令执行失败$$
:当前 Shell 的进程 ID,常用来辅助命名临时文件$-
:当前 Shell 的启动参数$_
:上一个命令的最后一个参数,不一定是用户输入的参数$!
:最近一个后台执行的异步命令的进程 ID,没有的话返回空
# 调用格式【./test.sh 29 男】
chmod 777 test.sh
echo $0 #【./test.sh】脚本文件名
echo $1 #【29】
echo $2 #【男】
echo $# #【2】传递到脚本的参数数量
echo $* #【29 男】以一个字符串显示所有向脚本或函数传递的参数
echo $@ #【29 男】
echo $? #【0】上一个命令的退出码
echo $$ #【14372】当前 Shell 的进程 ID
echo $- #【hBH】当前 Shell 的启动参数
echo $_ #【hBH】上一个命令的最后一个参数,不一定是用户输入的参数
echo $! #【】最近一个后台执行的异步命令的进程 ID
$*
与 $@
的区别:在双引号
中,$*
的作用是将所有参数当做一个参数
# 【./test.sh 29 男 白乾涛】
for i in $@; do echo -n $i-; done; # 【29-男-白乾涛】
for i in $*; do echo -n $i-; done; # 【29-男-白乾涛】
for i in "$@"; do echo -n $i-; done; # 【29-男-白乾涛】
for i in "$*"; do echo -n $i-; done; # 【29 男 白乾涛】注意,这里是将所有参数当做一个参数
for i in '$@'; do echo -n $i-; done; # 【$@】
for i in '$*'; do echo -n $i-; done; # 【$*】
变量未定义时的默认值
${var:-word}
:如果变量var
存在且不为空,则返回它的值,否则返回word
${var:=word}
:如果变量var
存在且不为空,则返回它的值,否则将它设为word
,并且返回word
${var:+word}
:如果变量var
存在且不为空,则返回word
,否则返回空值,可用来测试变量是否存在${var:?info}
:如果变量var
存在且不为空,则返回它的值,否则中断脚本的执行,并打印var: info
echo ${abc:-"变量未定义"} # 【变量未定义】
echo ${abc:="baiqiantao"} # 【baiqiantao】
echo ${bqt:+"变量已定义"} # 【变量已定义】
echo ${abc:?"变量未定义"} # 【bash: abc: 变量未定义】变量未定义时就中断执行,并返回给定的报错信息
echo ${abc:?} # 【bash: abc: parameter null or not set】可以省略报错信息
上面四种语法如果用在脚本中,变量名的部分可以用数字1
到9
,表示脚本的参数。
声明输出变量 export
export
命令用来向子 Shell 输出变量。- 用户创建的变量仅可用于当前 Shell,使用
export
命令可以把变量传递给子 Shell - 通过
export
命令输出的变量,对于子 Shell 来说就是环境变量 - 子 Shell 如果修改继承的变量,不会影响父 Shell
bqt=baiqiantao
export bqt # 输出变量 bqt,执行后,当前 Shell 及随后新建的子 Shell,都可以读取变量 bqt
export var=value # 给变量赋值并输出
# 子 Shell 如果修改继承的变量,不会影响父 Shell
bash # 新建子 Shell
echo $bqt # 读取 $bqt
bqt=baz # 修改继承的变量
exit # 退出子 Shell
echo $bqt # 读取 $bqt
声明只读变量 readonly
声明只读变量,等同于 declare -r
,声明后无法改变变量值,也不能 unset
变量
readonly
命令有三个参数
-f
:声明的变量为函数名-p
:打印出所有的只读变量-a
:声明的变量为数组
声明时执行算术式 let
使用 let
命令声明变量时,可以直接执行算术表达式。
let a=1+2 # 使用 let 命令声明变量时,可以直接执行算术表达式
let "b =1 +2" # 参数表达式如果包含空格,需要使用引号
echo $a $b # 【3 3】
let "v1 = 1" v2=v1++ # 可以同时对多个变量赋值,赋值表达式之间使用空格分隔
echo $v1,$v2 # 【2,1】,v2=v1++ 的意思是:先返回 v1 的值,然后 v1 再自增
声明特殊变量 declare
declare
命令可以声明一些特殊类型的变量。declare
命令如果用在函数中,声明的变量只在函数内部有效,等同于 local
命令。
- 声明整数变量
-i
:声明后可以直接进行数学运算 - 声明只读变量
-r
:等同于readonly
命令,声明后无法改变变量值,也不能unset
变量 - 声明大写字母
-u
:声明后可以自动把变量值转成大写字母 - 声明小写字母
-l
:声明后可以自动把变量值转成小写字母 - 输出变量信息
-p
:输出已定义变量的值,未定义的变量会提示找不到;不带参数时输出所有变量的信息 - 输出环境变量
-x
:等同于export
命令,可以将一个变量输出为子 Shell 的环境变量 - 输出所有函数名
-F
:不包含函数定义 - 输出所有函数定义
-f
:包含函数定义 - 声明数组变量
-a
:
# 声明整数变量
declare -i a=2 b=5 # 声明整数变量,声明后可以直接进行数学运算
declare -i c=a*b # 只要一个变量声明为整数,它的赋值就会自动解释为整数运算,这里 a、b 可不声明为整数变量
echo $a*$b=$c # 【2*5=10】
c=bqt; echo $c # 【0(不确定的值)】变量声明为整数以后,如果被改写为字符串,不会报错,但会赋以不确定的值
# 声明只读变量
declare -r r=1 # 声明只读变量,等同于 readonly 命令,声明后无法改变变量值,也不能 unset 变量
r=2 # 【bash: r: readonly variable】报错,命令执行失败
unset r # 【bash: unset: r: cannot unset: readonly variable】
# 声明大/小写
declare -u u # 声明大写字母,声明后可以自动把变量值转成大写字母
u=bQt; echo $u # 【BQT】
declare -l l # 声明小写字母,声明后可以自动把变量值转成小写字母
l=bQt; echo $l # 【bqt】
# 输出变量信息
p=bqt
declare -p p # 【declare -- p="bqt"】
declare -p pp # 【bash: declare: pp: not found】
declare -p # 输出所有变量的信息
# 其他
declare -x x # 输出环境变量,等同于【export x】,可以将一个变量输出为子 Shell 的环境变量
declare -F # 输出当前环境的所有函数名,不包含函数定义
declare -f # 输出当前环境的所有函数,包括它的定义
declare # 等同于【set】命令,输出当前环境的所有变量以及函数
2022-1-3