在Linux学习过程中,我们无可避免的会碰到一个既让人喜欢,又令人头疼的神奇的东西——bash编程,即shell脚本。那么什么是shell脚本呢?shell是一个命令语言解释器,而shell脚本则是Linux命令的集合,按照预设的顺序依次解释执行,来完成特定的、较复杂的系统管理任务,类似于Windows中的批处理文件。本文带来的是bash编程的基础语法讲解。
bash编程之变量
bash变量类别
本地变量:只对当前shell进程有效的变量,对其它shell进程无效,包当前shell进程的子进程
- VAR_NAME=VALUE
变量赋值:向变量的存储空间保存数据
变量引用:${VAR_NAME}
- "":弱引用,里面的变量会被替换
- '':强引用,里面的所有字符都是字面量,直接输出
环境变量:对当前shell进程及其子shell有效,对其它的shell进程无效
- 定义:export VAR_NAME=VALUE
- 导出:export VAR_NAME
- 撤消变量:unset VAR_NAME
- 只读变量:readonly VAR_NAME
局部变量: 对shell脚本中某代码片断有效,通常用于函数本地
- local VAR_NAME=VALUE
位置变量:用来接受变量指定位置的参数
- $1,$2...,${10}
特殊变量:shell对一些参数做特殊处理,这些参数只能被引用而不能被赋值
- $# 传递到脚本的参数个数
- $* 显示所有向脚本传递的参数 #与位置变量不同,此选项参数可超过9个
- $$ 获取当前shell的进程号
- $! 执行上一个指令的进程号
- $? 获取执行的上一个指令的返回值 #0为执行成功,非零为执行失败
- $- 显示shell使用的当前选项,与set命令功能相同
- $@ 与$*相同,但是使用时加引号,并在引号中返回每个参数
查看变量:
- set:查看当前shell进程中的所有变量
- export, printenv, env:查看当前shell进程中的所有环境变量
变量命名:
- 1、不能使用程序中的关键字(保留字)
- 2、只能使用数字、字母和下划线,且不能以数字开头
- 3、要见名知义
变量类型:
- 数值型:精确数值(整数),近似数值(浮点型)
- 字符型:char,string
- 布尔型:true, false
类型转换:
- 显式转换
- 隐式转换
bash的配置文件:
功能:设定本地变量,定义命令别名
- profile类:为交互式登录的用户提供配置
- 全局:/etc/profile、/etc/profile.d/*.sh
- 用户:~/.bash_profile
- bashrc类:为非交互式的用户提供配置
- 全局:/etc/bashrc
- 用户:~/.bashrc
bash编程之编写格式及执行方式
- 编写格式:shell脚本第一行必须顶格写,用shebang定义指定的解释器来解释该脚本。
- #!/bin/bash #!即为shebang
- # 其它的以#开头的行均为注释,会被解释器忽略,可用来注释脚本用途及版本,方便使用管理。
- 执行方式:bash编程属于面向过程编程,执行方式如下:
- 顺序执行:按命令先后顺寻依次执行
- 选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支
- 循环执行:将同一段代码反复执行多次,因此,循环必须有退出条件;否则,则陷入死循环
- bash执行选项:
- bash -n SHELLNAME #语法测试,测试是否存在语法错误
- bash -x SHELLNAME #模拟单步执行,显示每一步执行过程
bash之算数运算与逻辑运算
- 算数运算
定义整型变量:l
- et VAR_NAME=INTEGER_VALUE #例如:let a=3
- declare -i VAR_NAME=INTEGER_VALUE #declare -i a=3
实现算术运算的方式:
- let VAR_NAME=ARITHMATIC_EXPRESSION
- VAR_NAME=$[ARITHMATIC_EXRESSION]
- VAR_NAME=$((EXPRESSION))
- VAR_NAME=$(expr $num1 + $num2)
算术运算符:
- +:加法
- -:减法
- *:乘法
- /:整除
- %:取余数
- **:乘幂
注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算,bash会执行变量类型的隐式类型转换。
- 逻辑运算
- 布尔运算:真,假
- 与运算:真 && 真 = 真
- 真 && 假 = 假
- 假 && 真 = 假
- 假 && 假 = 假
- 或运算:真 || 真 = 真
- 真 || 假 = 真
- 假 || 真 = 真
- 假 || 假 = 假
- 非运算:!真=假
- !假=真
bash编程之条件测试语句
bash条件测试
整型测试:整数比较
- 例如 [ $num1 -gt $num2 ]
- -gt: 大于则为真
- -lt: 小于则为真
- -ge: 大于等于则为真
- -le: 小于等于则为真
- -eq: 等于则为真
- -ne: 不等于则为真
字符测试:字符串比较
- 双目:
- 例如[[ "$str1" > "$str2" ]]
- >: 大于则为真
- <: 小于则为真
- >=:大于等于则为真
- <=:小于等于则为真
- ==:等于则为真
- !=:不等于则为真
- 单目:
- -n String: 是否不空,不空则为真,空则为假
- -z String: 是否为空,空则为真,不空则假
- 文件测试:判断文件的存在性及属性等
- -a FILE:存在则为真;否则则为假;
- -e FILE: 存在则为真;否则则为假;
- -f FILE: 存在并且为普通文件,则为真;否则为假;
- -d FILE: 存在并且为目录文件,则为真;否则为假;
- -L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
- -b: 存在并且为块设备,则为真;否则为假;
- -c: 存在并且为字符设备,则为真;否则为假
- -S: 存在并且为套接字文件,则为真;否则为假
- -p: 存在并且为命名管道,则为真;否则为假
- -s FILE: 存在并且为非空文件则为值,否则为假;
- -r FILE:文件可读为真,否则为假
- -w FILE:文件可写为真,否则为假
- -x FILE:文件可执行为真,否则为假
- file1 -nt file2: file1的mtime新于file2则为真,否则为假;
- file1 -ot file2:file1的mtime旧于file2则为真,否则为假;
- 组合条件测试:在多个条件间实现逻辑运算
- 与:[ condition1 -a condition2 ]
- condition1 && condition2
- 或:[ condition1 -o condition2 ]
- condition1 || condition2
- 非:[ -not condition ]
- ! condition
- 与:COMMAND1 && COMMAND2
- COMMAND1如果为假,则COMMAND2不执行
- 或:COMMAND1 || COMMAND2
- COMMAND1如果为真,则COMMAND2不执行
- 非:! COMMAND
条件测试之if语句
- 1、if语句之单分支
- 语句结构:
- if 测试条件;then
- 选择分支
- fi
- 表示条件测试状态返回值为值,则执行选择分支
- 例:写一个脚本,接受一个参数,这个参数是用户名;如果此用户不存在,则创建该用户;
- #!/bin/bash
- if ! id $1 &> /dev/null;then
- useradd $1
- fi
- 2、if语句之双分支
- 语句结构:
- if 测试条件;then
- 选择分支1
- else
- 选择分支2
- fi
- 两个分支仅执行其中之一
- 例:通过命令行给定一个文件路径,而后判断:如果此文件中存在空白行,则显示其空白行的总数;否则,则显示无空白行;
- #!/bin/bash
- if grep "^[[:space]]*$" $1 &> /dev/null; then
- echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
- else
- echo "No blank lines"
- fi
- 注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。
- 3、if语句之多分支
- 语句结构:
- if 条件1;then
- 分支1
- elif 条件2;then
- 分支2
- elif 条件3;then
- 分支3
- ...
- else
- 分支n
- fi
- 例:传递一个用户名给脚本:如果此用户的id号为0,则显示说这是管理员;如果此用户的id号大于等于500,则显示说这是普通用户;否则,则说这是系统用户。
- #!/bin/bash
- if [ $# -lt 1 ]; then
- echo "Usage: `basename $0` username"
- exit 1
- fi
- if ! id -u $1 &> /dev/null; then
- echo "Usage: `basename $0` username"
- echo "No this user $1."
- exit 2
- fi
- if [ $(id -u $1) -eq 0 ]; then
- echo "Admin"
- elif [ $(id -u $1) -ge 500 ]; then
- echo "Common user."
- else
- echo "System user."
- fi
bash交互式编程
- read [option] “prompt”-p:直接指定一个变量接受参数
- -t timaout:指定等待接受参数的时间
- -n:表示不换行
- 例:输入用户名,可返回其shell
- #!/bin/bash
- read -p "Plz input a username: " userName
- if id $userName &> /dev/null; then
- echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."
- else
- echo "No such user. stupid."
- fi
条件测试之case语句
- case语句:有多个测试条件时,case语句会使得语法结构更明晰
- 语句结构:
- case 变量引用 in
- PATTERN1)
- 分支1
- ;;
- PATTERN2)
- 分支2
- ;;
- ...
- *)
- 分支n
- ;;
- esac
PATTERN:类同于文件名通配机制,但支持使用|表示或者
- a|b: a或者b*:匹配任意长度的任意字符
- ?: 匹配任意单个字符
- []: 指定范围内的任意单个字符
- 例:写一个脚本,完成如下任务,其使用形式如下所示:
- script.sh {start|stop|restart|status}
- 其中:如果参数为空,则显示帮助信息,并退出脚本;
- 如果参数为start,则创建空文件/var/lock/subsys/script,并显示“starting script successfully.”
- 如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop script successfully.”
- 如果参数为restart,则删除文件/var/locksubsys/script并重新创建,而后显示“Restarting script successfully.”
- 如果参数为status,那么:如果文件/var/lock/subsys/script存在,则显示“Script is running…”,否则,则显示“Script is stopped.”
- #!/bin/bash
- file='/var/lock/subsys/script'
- case $1 in
- start)
- if [ -f $file ];then
- echo "Script is running..."
- exit 3
- else
- touch $file
- [ $? -eq 0 ] && echo "Starting script successfully."
- fi
- ;;
- stop)
- if [ -f $file ];then
- rm -rf $file
- [ $? -eq 0 ] && echo "Stop script successfully."
- else
- echo "Script is stopped..."
- exit 4
- fi
- ;;
- restart)
- if [ -f $file ];then
- rm -rf $file
- [ $? -eq 0 ] && echo "Stop script successfully"
- else
- echo "Script is stopped..."
- exit 5
- fi
- touch $file
- [ $? -eq 0 ] && echo "Starting script successfully"
- ;;
- status)
- if [ -f $file ];then
- echo "Script is running..."
- else
- echo "Script is stopped."
- fi
- ;;
- *)
- echo "`basename $0` {start|stop|restart|status}"
- exit 2
- ;;
- esac
bash编程之循环语句
循环之for循环
- 1、for语句格式一
- 语句结构:
- for 变量名 in 列表; do
- 循环体
- done
- 列表:可包含一个或多个元素
- 循环体:依赖于调用变量来实现其变化
- 循环可嵌套
- 退出条件:遍历元素列表结束
- 例:求100以内所有正整数之和
- #!/bin/bash
- declare -i sum=0
- for i in {1..100}; do
- let sum+=$i
- done
- echo $sum
- 2、for语句格式二
- for ((初始条件;测试条件;修改表达式)); do
- 循环体
- done
- 先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式,否则直接跳出循环。
- 例:求100以内所有正整数之和(for二实现)
- #!/bin/bash
- declare -i sum=0
- for ((counter=1;$counter <= 100; counter++)); do
- let sum+=$counter
- done
- echo $sum
循环之while语句
while适用于循环次数未知,或不便用for直接生成较大的列表时
- 语句结构:
- while 测试条件; do
- 循环体
- done
- 测试条件为真,进入循环;测试条件为假,退出循环
- 例1:求100以内所有偶数之和,要求使用取模方法
- #!/bin/bash
- declare -i counter=1
- declare -i sum=0
- while [ $counter -le 100 ]; do
- if [ $[$counter%2] -eq 0 ]; then
- let sum+=$counter
- fi
- let counter++
- done
- echo $sum
- 例2:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止
- #!/bin/bash
- read -p "Plz enter a username: " userName
- while [ "$userName" != 'q' -a "$userName" != 'quit' ]; do
- if id $userName &> /dev/null; then
- grep "^$userName\>" /etc/passwd | cut -d: -f3,7
- else
- echo "No such user."
- fi
- read -p "Plz enter a username again: " userName
- done
- while特殊用法:遍历文本文件
- 语句结构:
- while read 变量名; do
- 循环体
- done < /path/to/somefile
- 变量名,每循环一次,记忆了文件中一行文本
- 例:显示ID号为偶数,且ID号同GID的用户的用户名、ID和SHELL
- while read line; do
- userID=`echo $line | cut -d: -f3`
- groupID=`echo $line | cut -d: -f4`
- if [ $[$userID%2] -eq 0 -a $userID -eq $groupID ]; then
- echo $line | cut -d: -f1,3,7
- fi
- done < /etc/passwd
循环之until语句
- 语句结构:
- until 测试条件; do
- 循环体
- done
- 测试条件为假,进入循环;测试条件为真,退出循环
- 例:求100以内所有偶数之和,要求使用取模方法(until实现)
- #!/bin/bash
- declare -i counter=1
- declare -i sum=0
- until [ $counter -gt 100 ]; do
- if [ $[$counter%2] -eq 0 ]; then
- let sum+=$counter
- fi
- let counter++
- done
- echo $sum
- 例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止(until实现)
- #!/bin/bash
- read -p "Plz enter a username: " userName
- until [ "$userName" = 'q' -a "$userName" = 'quit' ]; do
- if id $userName &> /dev/null; then
- grep "^$userName\>" /etc/passwd | cut -d: -f3,7
- else
- echo "No such user."
- fi
- read -p "Plz enter a username again: " userName
- done
循环之循环控制和shift
- 循环控制命令:
- break:提前退出循环
- break [N]: 退出N层循环;N省略时表示退出break语句所在的循环
- continue: 提前结束本轮循环,而直接进入下轮循环
- continue [N]:提前第N层的循环的本轮循环,而直接进入下轮循环
死循环:
- #while体while true; do
- 循环体
- done
- #until体
- until false; do
- 循环体
- done
- 例1:写一个脚本,判断给定的用户是否登录了当前系统
- (1) 如果登录了,则脚本终止;
- (2) 每5秒种,查看一次用户是否登录;
- #!/bin/bash
- while true; do
- who | grep "gentoo" &> /dev/null
- if [ $? -eq 0 ];then
- break
- fi
- sleep 5
- done
- echo "gentoo is logged."
shift:
- 如果没有数字,只有shift 就是跳过一个参数获取下一个参数,如果加上数字,比如shift 2 ,跳过两个参数获取下一个参数。
- 例:写一个脚本,使用形式如下所示
- showifinfo.sh [-i INTERFACE|-a] [-v]
- 要求:
- 1、-i或-a不可同时使用,-i用于指定特定网卡接口,-a用于指定所有接口;
- 显示接口的ip地址
- 2、使用-v,则表示显示详细信息,显示接口的ip地址、子网掩码、广播地址;
- 3、默认表示仅使用-a选项;
- #!/bin/bash
- allinterface=0
- ifflag=0
- verbose=0
- interface=0
- if [ $# -eq 0 ];then
- ifconfig | grep "inet addr:" | awk '{print $2}'
- fi
- while [ $# -ge 1 ];do
- case $1 in
- -a)
- allinterface=1
- shift 1
- ;;
- -i)
- ifflag=1
- interface=$2
- shift 2
- ;;
- -v)
- verbose=1
- shift 1
- ;;
- *)
- echo "error option"
- exit 2
- ;;
- esac
- done
- if [ $allinterface -eq 1 ];then
- if [ $ifflag -eq 1 ];then
- echo "command not found"
- exit 5
- fi
- if [ $verbose -eq 1 ];then
- ifconfig | grep "inet addr:"
- else
- ifconfig | grep "inet addr:" | awk '{print $2}'
- fi
- fi
- if [ $ifflag -eq 1 ];then
- if [ $allinterface -eq 1 ];then
- echo "command not found"
- exit 5
- fi
- if [ $verbose -eq 1 ];then
- ifconfig $interface | grep "inet addr:"
- else
- ifconfig $interface | grep "inet addr:" | awk '{print $2}'
- fi
- fi
bash编程之函数
语法结构:
- function F_NAME {
- 函数体
- }
- F_NAME() {
- 函数体
- }
可调用:使用函数名,函数名出现的地方,会被自动替换为函数
函数的返回值:
函数的执行结果返回值:代码的输出
函数中使用打印语句:echo, printf
函数中调用的系统命令执行后返回的结果
执行状态返回值:
默认取决于函数体执行的最后一个命令状态结果
自定义退出状态码:return [0-255]
注意:函数体运行时,一旦遇到return语句,函数即返回;
函数可以接受参数:
在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:
- 位置参数
- $1, $2, …
- $#, $*, $@
例:写一个脚本,完成如下功能(使用函数):
1、提示用户输入一个可执行命令;
2、获取这个命令所依赖的所有库文件(使用ldd命令);
3、复制命令至/mnt/sysroot/对应的目录中
解释:假设,如果复制的是cat命令,其可执行程序的路径是/bin/cat,那么就要将/bin/cat复到/mnt/sysroot/bin/目录中,如果复制的是useradd命令,而useradd的可执行文件路径为/usr/sbin/useradd,那么就要将其复制到/mnt/sysroot/usr/sbin/目录中;
4、复制各库文件至/mnt/sysroot/对应的目录中;
- #!/bin/bash
- target=/mnt/sysroot/
- [ -d $target ] || mkdir $target
- preCommand() {
- if which $1 &> /dev/null; then
- commandPath=`which --skip-alias $1`
- return 0
- else
- echo "No such command."
- return 1
- fi
- }
- commandCopy() {
- commandDir=`dirname $1`
- [ -d ${target}${commandDir} ] || mkdir -p ${target}${commandDir}
- [ -f ${target}${commandPath} ] || cp $1 ${target}${commandDir}
- }
- libCopy() {
- for lib in `ldd $1 | egrep -o "/[^[:space:]]+"`; do
- libDir=`dirname $lib`
- [ -d ${target}${libDir} ] || mkdir -p ${target}${libDir}
- [ -f ${target}${lib} ] || cp $lib ${target}${libDir}
- done
- }
- read -p "Plz enter a command: " command
- until [ "$command" == 'quit' ]; do
- if preCommand $command &> /dev/null; then
- commandCopy $commandPath
- libCopy $commandPath
- fi
- read -p "Plz enter a command: " command
- done
bash编程之信号捕捉
trap命令用于在shell程序中捕捉到信号,之后可以有三种反应方式:
- (1)执行一段程序来处理这一信号
- (2)接受信号的默认操作
- (3)忽视这一信号
trap对上面三种方式提供了三种基本形式:
第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双引号中的命令串。
- trap 'commands' signal-list
- trap "commands" signal-list
第二种形式的trap命令恢复信号的默认操作:
- trap signal-list
第三种形式的trap命令允许忽视信号:
- trap " " signal-list
- trap 'COMMAND' SIGINT(表示关闭进程)
例:写一个脚本,能够ping探测指定网络内的所有主机是否在线,当没有执行完时可接收ctrl+c命令退出。
- #!/bin/bash
- quitScript() {
- echo "Quit..."
- }
- trap 'quitScript; exit 5' SIGINT
- cnetPing() {
- for i in {1..254}; do
- if ping -c 1 -W 1 $1.$i &> /dev/null; then
- echo "$1.$i is up."
- else
- echo "$1.$i is down."
- fi
- done
- }
- bnetPing() {
- for j in {0..255}; do
- cnetPing $1.$j
- done
- }
- anetPing() {
- for m in {0..255}; do
- bnetPing $1.$m
- done
- }
- netType=`echo $1 | cut -d"." -f1`
- if [ $netType -ge 1 -a $netType -le 126 ]; then
- anetPing $netType
- elif [ $netType -ge 128 -a $netType -le 191 ]; then
- bnetPing $(echo $1 | cut -d'.' -f1,2)
- elif [ $netType -ge 192 -a $netType -le 223 ]; then
- cnetPing $(echo $1 | cut -d'.' -f1-3)
- else
- echo "Wrong"
- exit 2
- fi
bash编程之数组
数组:连续的多个独立内存空间,每个内存空间相当于一个变量
数组元素:数组名+索引(从0开始编号)
索引的表示方式:a[0], a[1]
声明数组:
- declare -a ARRAR_NAME
关联数组:
- declare -A ARRAY_NAME
支持稀疏格式:仅一维数组
数组元素的赋值:
(1) 一次只赋值一个元素
- a[0]=$RANDOM
(2) 一次赋值全部元素
- a=(red blue yellow green)
(3) 指定索引进行赋值
- a=([0]=green [3]=red [2]=blue [6]=yellow)
(4) 用户输入
- read -a ARRAY
数组的访问:
用索引访问:
- ARRAY[index]
数组的长度:
- ${#ARRAY[*]}
- ${#ARRAY[@]}
例:写一个脚本,生成10个随机数,保存至数组中;而后显示数组下标为偶数的元素
- #!/bin/bash
- for i in {0..9}; do
- rand[$i]=$RANDOM
- [ $[$i%2] -eq 0 ] && echo "$i:${rand[$i]}"
- done
从数组中挑选某元素:
- ${ARRAY[@]:offset:number}
切片:
- offset: 偏移的元素个数
- number: 取出的元素的个数
- ${ARRAY[@]:offset}:取出偏移量后的所有元素
- ${ARRAY[@]}: 取出所有元素
数组复制:要使用${ARRAY[@]}
- $@: 每个参数是一个独立的串
- $*: 所有参数是一个串
向数组中追加元素:非稀疏格式
- week,
- week[${#week[@]}]
从数组中删除元素:
- unset ARRAY[index]
例:复制一个数组中下标为偶数的元素至一个新数组中
- #!/bin/bash
- declare -a mylogs
- logs=(/var/log/*.log)
- echo ${logs[@]}
- for i in `seq 0 ${#logs[@]}`; do
- if [ $[$i%2] -eq 0 ];then
- index=${#mylogs[@]}
- mylogs[$index]=${logs[$i]}
- fi
- done
- echo ${mylogs[@]}
例2:生成10个随机数,升序排序
- #!/bin/bash
- for((i=0;i<10;i++))
- do
- rnd[$i]=$RANDOM
- done
- echo -e "total=${#rnd[@]}\n${rnd[@]}\nBegin to sort"
- for((i=9;i>=1;i--))
- do
- for((j=0;j<i;j++))
- do
- if [ ${rnd[$j]} -gt ${rnd[$[$j+1]]} ] ;then
- swapValue=${rnd[$j]}
- rnd[$j]=${rnd[$[$j+1]]}
- rnd[$[$j+1]]=$swapValue
- fi
- done
- done
- echo ${rnd[@]}
例3:打印九九乘法表
- #!/bin/bashfor((i=1;i<=9;i++))
- do
- strLine=""
- for((j=1;i<=9;j++))
- do
- strLine=$strLine"$i*$j="$[$i*$j]"\t"
- [ $i -eq $j ] && echo -e $strLine && break
- done
- done
bash编程之字符串操作
字符串切片:
- ${string:offset:length}
- [root@scholar scripts]# string='hello word'
- [root@scholar scripts]# echo ${string:2:4}
- llo
- 取尾部的指定个数的字符:
- ${string: -length}
- [root@scholar scripts]# echo ${string: -2}
- rd
取子串:基于模式
- ${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;
- ${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;
- file='/var/log/messages'
- ${file#*/}: 返回的结果是var/log/messages
- ${file##*/}: 返回messages
- ${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;
- ${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;
- file='/var/log/messages'
- ${file%*/}: 返回的结果是/var/log
- ${file%%*/}: 返回结果为空
- 例:url="http://www.redhat.com:80"
- 取端口:${url##*:}
- 取协议:${url%%:*}
查找替换:
${variable/pattern/substi}: 替换第一次出现
- #userinfo=`tail -1 /etc/passwd
- #echo $userinfo
- scholar:x:500:500:scholar:/home/scholar:/bin/bash
- #echo ${userinfo/scholar/redhat}
- redhat:x:500:500:scholar:/home/scholar:/bin/bash
${variable//pattern/substi}:替换所有的出现
- #echo ${userinfo//scholar/redhat}
- redhat:x:500:500:redhat:/home/redhat:/bin/bash
${variable/#pattern/substi}:替换行首被pattern匹配到的内容
- #echo ${userinfo/#scholar/redhat}
- redhat:x:500:500:scholar:/home/scholar:/bin/bash
${variable/%pattern/substi}:替换行尾被pattern匹配到的内容
- #echo ${userinfo/%bash/redhat}
- scholar:x:500:500:scholar:/home/scholar:/bin/redhat
pattern可以使用globbing中的元字符:* ?
查找删除:
${variable/pattern}:删除第一次出现
- #echo ${userinfo/scholar}
- :x:500:500:scholar:/home/scholar:/bin/bash
${variable//pattern}:删除所有的出现
- #echo ${userinfo//scholar}
- :x:500:500::/home/:/bin/bash
${variable/#pattern}:删除行首被pattern匹配到的内容
- #echo ${userinfo/#scholar}
- :x:500:500:scholar:/home/scholar:/bin/bash
${variable/%pattern}:删除行尾被pattern匹配到的内容
- #echo ${userinfo/%bash}
- scholar:x:500:500:scholar:/home/scholar:/bin/
大小写转换:
小–>大:${variable^^}
- #echo ${userinfo^^}
- SCHOLAR:X:500:500:SCHOLAR:/HOME/SCHOLAR:/BIN/BASH
大–>小:${variable,,}
- #name="SCHOLAR"
- #echo ${name,,}
- scholar
变量赋值操作:
${variable:-string}:variable为空或未设定,那么返回string,否则,返回variable变量的值;
${variable:=string}:variable为空或未设定,则返回string,且将string赋值给变量variable,否则,返回variable的值;
为脚本使用配置文件,并确保某变量有可用值的方式
variable=${variable:-default vaule}
写个脚本,配置etc目录;
(1) 在配置文件中定义变量;
(2) 在脚本中source配置文件;
- #!/bin/bash
- [ -f /etc/sysconfig/network ] && source /etc/network/network
- [-z "$HOSTAME" -o "$HOSTNAME" = '(none)' ] || HOSTNAME ='localhost'
- /bin/hostname $HOSTNAME
- /bin/hostname
mktemp命令:
mktemp [OPTIONS] filename.XXX
- -d: 创建临时目录
- --tmpdir=/path/to/somewhere :指定临时文件所在的目录
- mktemp /tmp/tmp.XXX #XXX生成相同数量随机字符
- mktemp --tmpdir=/var/tmp tmp.XXX #指定目录创建临时文件
- mktemp --tmpdir=/var/tmp -d tmp.XXX #指定目录创建临时目录
install命令:
install [OPTIONS] SOURCE DEST
install [OPTIONS] SOURCE… DIR
install [OPTIONS] -d DIR …
- 增强型的复制命令:
- -o OWNER
- -g GROUP
- -m MODE
- -d : 创建目录
- install /etc/fstab /tmp #复制文件到指定目录
- install --mode=644 /etc/fstab /tmp/ #复制时指定权限
- install --owner=scholar /etc/fstab /tmp #复制时指定属主
- install --group=scholar /etc/fstab /tmp #复制时指定属组
- install -d /tmp/install #创建目录