#! 默认后面为绝对路径名
可修改Bash变量
BASH | |
---|---|
CDPATH | bash完整路径 |
EDITOR | cd命令逐个查找的路径,未设置则查找当前目录 |
ENV | 应用程序默认编辑器 |
HISTFILE | 存放历史记录的文件的路径名 |
HOME | 用户的主目录名字 |
IFS | Bash分割命令行参数的符号 |
用户的系统邮箱文件的名字 | |
MAILCHECK | shell检查用户系统邮箱的周期(单位s),有新邮件时通知用户 |
PATH | 检索路径变量,用于查找外部命令和程序 |
PPID | 父进程ID |
PS1 | 命令行主shell提示符,通常为$ |
PS2 | 二级shell提示符 |
PWD | 当前工作目录名字 |
TERM | 用户控制终端类型 |
上述shell环境变量可写
用户定义的变量在shell中作临时的存储空间,值在程序执行的过程中可改变。
set
不带参数时,显示当前所有的shell变量
env
可显示环境变量和它们的值,没那么完整
printenv有类似效果
declare和typeset要详细些
declare
declare [±options][name[=value]]
变量默认为字符串,可定义为一个整型值、函数或数组
-a name为数组
-f name为函数
-i name为整数
-r 给每一个name标记上只读的属性
-x 每一个name都可被子进程访问到
单纯声明时不会改变变量现有的值,即declare val,val原有的值不会改变
整型的变量不能被赋予非整型的值,否则变量的值会变为0.在声明时确定值的类型(declare等),后续不重新声明可直接用'='赋值。
非整型变量可以被赋予任何值,以字符串形式存放
值包含空格时,必须要用''引起来。
$val,表示取val的值,没有初始化为null
${val:-string},val存在不为空时返回其值,否则返回string
${val:=string},val存在不为空时返回其值,否则赋值并返回string
${val:+string},val存在不为空时返回string,否则返回null,用于测试变量存在与否
${val?string},val存在不为空时返回其值,否则显示 shell名字:val:string
在命令行中单独输入$val,会将val的值解析为命令执行。
控制shell提示符
\H:主机域名的全称
\T:时间,hh:mm:ss,12小时格式 \d:日期,格式为weekday month date
\h:计算机主机名的第一部分
\s:用户shell名字
\t:时间,hh:mm:ss,24小时格式
\u:当前用户的用户名 \v:Bash版本号
\w:当前的工作目录
命令替换
wsl中,若用$val取val的值,需要不带引号或只在双引号中使用
注:若想将某些命令的输出值赋给变量,采用val=$(command)会十分有效。此过程和管道的输入输出链接有所不同。
export
export [name-list]:从export命令开始,使name-list所有变量的名字和现在的值输出到从这点开始的每个命令中。(不对父进程生效)
类似的有declare -x[name-list],typeset -x[name-list]
bash只读环境变量
环境变量名 | 变量的用途 |
---|---|
$0 | 程序的名字 |
1~9 | 命令參数1~9的值 |
$* | 全部命令行參数的值 |
@ |全部命令行參数的值。假设@被“”包含。即“@”,这相当于当中的每个參数的值被“”包含。相反,假设\$\*被“”包含。即“\$*”。这就相当于全部的參数值作为一个串被“”包含。这就是@同$*在被“”包含的时候的区别。其它时候这二者是等价的 | |
$# | 记录了命令行參数的总个数 |
$$ | 当前进程的ID号 |
$? | 近期一次命令的退出状态 |
$! | 近期一次后台进程的ID号 |
上述环境变量可以通过echo显示。也可在命令行中配合其他命令使用
“$*”,"$@"的区别在于双引号括起来,*是将所有参数当作一个字符串处理,@是将每一个参数的值都作为一个字符串。
重置变量
unset [name-list]:删除name-list中的值,等于显示赋值为null:name=
只读常量
readonly [name-list]:等价于 declare -r [name-list]以及 typeset -r [name-list]
只读变量的值不可以被unset,即不能被重设。也不能通过declare,typeset等设置,只能退出该进程
read
read [options][variable-list],从标准输入中读入一行,赋值给variable-list中的变量。
options:
-a name 读到数组name中
-e 一整行读入第一个变量,其余为null
-p prompt 从终端读入数据,显示prompt字符串。
如果variable-list有多个,则将输入中的word按序赋给variable-list中的变量。如果词的数量比列出的变量的数量多,则余下的所有词赋值给最后一个变量。如果列出的变量的数量多于输入的词的数量,则多余的变量的值被置为null。
read -p "Enter:" line,此命令会在命令行提示Enter:,然后将命令行的输入存入line变量中。
read成功读取后会返回
shell只能保留最多9个命令行参数(在命令行中按序传入)
shift
shift[N]:将命令行参数左移N位,移位只在1以后的参数中进行,$0保持不变。
需要值得注意的是一开始传入shell脚本的参数数量大于9个时仍是全部被一次性读入到shell脚本中。
set
set [options][argument-list]
options:
-- 不把以'-'开头的词作为参数选项
-C 把noclobber标志设置为on,不允许用户通过重定向覆盖已经存在的文件,如果要覆盖,则需要强制重定向,如>|
-a 赋值的时候自动把变量输出
-o [options] 设置options;当options为空,打印出目前shell的设置,可选的option有
hash 内部哈希表保存命令的位置,可用-h选项设置
history 允许保存历史记录
noclobber 不允许输出重定向覆盖已经存在的文件
-v 详细模式:显示隐含的输入参数
set命令是将命令行参数设置为argument-list,即将后者对应填入$1~$9位置
Bash脚本编码规范
程序头内容
1.包含脚本的文件名
2.作者的名字
3.编写的日期
4.最后一次修改的日期
5.编写这个脚本的目的
6.对解决这个问题的算法的简要描述
注释以#开始
跳转
if expression;then
command
fi
如果要实现二路甚至是多路跳转,可以使用else,elif
if expression;then
command
elif expression;then
command
...(elif数目无限制)
else
command
fi
注:条件expression后接分号,i整个条件结束用fi
&> /dev/null:将输出结果丢弃
对表达式求值
test [expression] / [[expression]]
命令过长时,可以用'\'分隔命令。
for
for var [in argument-list]
do
command-list
done
如果有argument-list,则按序赋给变量var,并依次执行command-list。若没有argument-list,则从命令行获取
while
while expression
do
command-list
done
expression为真一直执行
until
until expression
do
command-list
done
expression值为假时,重复执行command-list中的命令
类似的,循环语句中有break和continue
case
使用符号';;'给command-list划分边界
case expression in pattern1) cmd1;; pattern2) cmd2;; ... patternN) cmdN;; esac
对于default case,可以用*)代替
数值数据处理
运算符 | 描述 | 示例 |
---|---|---|
+ | 加法,数字(操作数)的加法 | $(( 10 + 3 )) ,结果为:13 |
- | 减法,从第一个到第二个操作数的减法 | $(( 10 - 3 )) ,结果为:7 |
* | 乘法,操作数的乘法。 | $(( 10 * 3 )) ,结果为:30 |
/ | 除法,第一个操作数除以第二个操作数并返回商。 | $(( 10 / 3 )) ,结果为:3 |
** | 求幂,第一操作数的第二操作数的幂值。 | $(( 10 ** 3 )) ,结果为:1000 |
% | 模,测量第一个操作数除以第二个操作数时的余数。 | $(( 10 % 3 )) ,结果为:1 |
+= | 通过常量递增变量,用于按提供的常量递增第一个操作数的值。 | x=10;let "x += 3";echo $x; 结果为:13 |
-= | 通过常量递减变量,用于按提供的常量递减第一个操作数的值。 | x=10;let "x -= 3";echo $x; 结果为:7 |
*= | 将变量乘以常数,用于将第一个操作数的值乘以提供的常数。 | x=10;let "x *= 3";echo $x; 结果为:30 |
/= | 将变量除以常数,用于计算(变量/常数)的值并将结果存储回变量。 | x=10;let "x /= 3";echo $x; 结果为:3 |
%= | 变量除以常数的余数,用于计算(变量%常数)的值并将结果存储回变量。 | x=10;let "x %= 3";echo $x; 结果为:1 |
其他的运算符还有逻辑非、补(!、~),移位(<<、>>),不等关系(\leq、\geq、<、>、==、!=),逻辑运算(&、^、|,注意优先级不同),逻辑与或(&&、||),赋值(&=、^=、|=、<<=、>>=)
let expression:计算算术表达式expression的值,expression若是命令,则会被执行,expression可以有多个,中间用' '分隔
expr
expr args:计算表达式的参数args的值,并返回值到标准输出
expr index str1 str2: 在str1中寻找str2内的字符,并返回第一个匹配的位置索引,匹配不到返回0
expr length str:计算并将str长度送到标准输出
expr substr str num1 num2:提取str从num1开始,长为num2的子串
expr "abcd" : "\(.bc\)"
匹配正则字符串,用“\(\)”括起来的返回匹配到的字符串
expr "abcd" : ".bc"
此时返回匹配到的字符串的长度
使用expr命令时,参数与选项之间要留有空格
注:不要用''将expr语句括起来,在wsl中若想将expr的返回值赋值给变量,用var=$(expr command),也可以用var=`expr command`
数组
数组大小没有限制,不必连续赋值。只要声明了数组变量,就可以给数组任何一个元素赋值。
引用数组array内容:${array[i]},i为下标。若将@或者*当作下标,则引用数组中所有元素。区别在于$array[*]将数组中所有元素扩展为一个词,$array[@]将数组中每个元素分别扩展为一个词。
数组初始化方法:
array=(val1 val2 ... valN),不同值之间用' '隔开。
初始化后可以根据需要给任意下标数据赋值
local可以声明局部数组,但只能在函数中使用。
显示数组元素大小:${#array[i]},没有下标i时显示第一个数组元素的大小。
*作为下标时显示数组元素个数,只会统计被赋值的元素,如若只有1,19,36下标对应的元素被赋值,则结果为3。
数组下标从0开始
here文件
将脚本中命令的标准输入重定向到脚本中的数据(重定向到本文件中)
command << [-] input_marker
...input data...
input_marker(结束标记必须单独另起一行)
input_marker为自定义字
-连字符是取消here文件中(即input data区域)行首和结束标记前面的tab(不包括空格)
如果输出和错误也要重定向,则重定向要在here文件结束标记前,可以在<<之前,也可以在input_marker(非结束标记)与input data之间
中断(信号)处理
Arm Linux 信号
信号 | 值 | 执行动作 | 信号发出的原因 |
---|---|---|---|
SIGHUP | 1 | A | 终端的挂端或控制进程终止 |
SIGINT | 2 | A | 来自键盘的中断信号(ctrl+c组合键) |
SIGQUIT | 3 | C | 终端退出(ctrl+\组合键)(ctrl+I) |
SIGILL | 4 | C | 非法指令 |
SIGTRAP | 5 | C | 断点或陷阱指令(debuger使用) |
SIGABRT | 6 | C | 来自abort(3)发出的退出指令 |
SIGBUS | 7 | C | 总线错误 |
SIGFPE | 8 | C | 浮点运算错误 |
SIGKILL | 9 | AEF | Kill信号 |
SIGUSR1 | 10 | A | 用户自定义信号1 |
SIGSEGV | 11 | C | 段非法错误(无效的内存引用) |
SIGUSR2 | 12 | A | 用户自定义信号2 |
SIGPIPE | 13 | A | 管道损坏:写一个没有读端口的管道 |
SIGALARM | 14 | A | 由alarm(2)发出的信号 |
SIGTERM | 15 | A | 终止信号(软件中断) |
SIGSTKFLT | 16 | 栈溢出 | |
SIGCHLD | 17 | B | 子进程结束信号 |
SIGCONT | 18 | B | 进程继续(曾被停止的进程) |
SIGSTOP | 19 | DEF | 停止进程的执行,只是暂停 |
SIGTSTP | 20 | D | 停止进程的运行(Ctrl+z组合键)(挂起进程) |
SIGTTIN | 21 | D | 后台进程需要从终端读取数据 |
SIGTTOU | 22 | D | 后台进程需要向终端写数据 |
SIGURG | 23 | B | I/O有紧急数据到达当前进程 |
SIGXCPU | 24 | A | 查过CPU资源限制 |
SIGXFSZ | 25 | A | 文件大小超出上限 |
SIGVTALRM | 26 | A | 虚拟时钟超时 |
SIGPROF | 27 | A | Profile时钟信号描述 |
SIGWINCH | 28 | B | 窗口大小改变 |
SIGIO | 29 | B | I/O相关 |
SIGPWR | 30 | B | 关机 |
SIGSYS | 31 | 非法的系统调用 |
trap 'command-list' signal-list:处理截获的信号,command-list两端必须有单引号。
使用trap但没有参数时,执行默认动作(命令是多余的)。
command-list为空(只剩下单引号),则signal-list被忽略
stty
修改终端命令行相关设置
stty -echo命令:禁止回显(即命令行上不会显示输入)
stty echo:打开回显
'-'表示恢复原来的功能,下同
stty iuclc:开启禁止输出大写
stty olcuc:开启禁止输出小写
stty size:打出终端的行数和列数
stty eof "string":改变文件结束符,默认为ctrl+D
stty igncr:忽略回车符
exec
独特用途:
执行一个命令或程序取代当前的进程
打开和关闭文件描述符
exec command:将command代码覆盖到运行exec命令的进程上不生成新的进程,结束后控制权交还给调用进程的父进程
exp:shell中执行exec,则返回到mingetty进程,需要login
exec [选项] <命令> [参数]
-
选项
:exec
命令可以接受一些选项,用于控制其行为。以下是一些常用的选项:-
-c
:在执行命令之前,先清除环境变量。 -
-l
:在执行命令之前,先将当前环境变量传递给新的进程。 -
-s
:在执行命令之前,将当前进程的信号掩码传递给新的进程。 -
-t
:在执行命令之前,分配一个伪终端(pseudo-terminal)给新的进程。
-
-
<命令>
:要执行的命令。可以是任何可执行的命令,包括内部命令和外部命令。 -
参数
:传递给命令的参数。你可以指定零个或多个参数,具体取决于命令的要求。
请注意,exec
命令执行后会替换当前进程,因此执行exec
命令后的代码不会被执行。如果你希望在执行完一个命令后继续执行其他代码,你可以使用分号(;
)将多个命令组合在一起。
以下是一个示例,展示了如何使用exec
命令执行一个外部命令:
bash shell最多允许10个文件描述符,(0 1 2)保留给标准输入、输出、错误
exec中的重定向操作和之前相同,还可以打开here文档进行重定向。
exec <&-关闭标准输入
exec >& -关闭标准输出
exec n<& - ,关闭重定向为标准输入的文件描述符n
exec n>& -,关闭重定向为标准输出的文件描述符n
exec < /dev/tty:将stdin重新连接到终端。/dev/tty是代表shell运行时终端的伪终端
exec > /dev/tty:将stout重新连接到终端.exec执行输出重定向后必须要使用该命令才能使显示屏重新和终端相连。
exec的特性配合重定向操作适合在脚本中对文件进行操作,不需要额外的command
函数
使用函数的原因:函数的定义在内存中,调用比脚本(硬盘)快。
在脚本中定义了函数后,使用前需要用.或source命令
函数前使用export,可使函数为子进程所使用。
定义:
func() { command-list }
函数可在命令行中按上述方式交互式地定义
函数中的参数通过脚本中的变量获取
调试
Bash shell中,-x选项用于启用shell的跟踪模式。当使用bash -x命令时,Bash会在执行每个命令之前打印该命令的跟踪信息,跟踪信息包括执行的命令、参数和结果。