linux&shell
Posted CLAY&Loser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux&shell相关的知识,希望对你有一定的参考价值。
Linux常用命令
- 登录时显示信息放在/etc/motd和/etc/profile.d/xxx.sh
- motd放置字符串
- profile.d下放置脚本文件
echo
- echo -e 处理特殊字符,若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
- \a 发出警告声;
- \b 删除前一个字符;
- \c 最后不加上换行符号;
- \f 换行但光标仍旧停留在原来的位置;
- \n 换行且光标移至行首;
- \r 光标移至行首,但不换行;
- \t 插入tab;
- \v 与\f相同;
- \ 插入\字符;
- \nnn 插入nnn(八进制)所代表的ASCII字符;
- echo -n 不换行输出
- echo -e 处理特殊字符,若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
date +%T 以格式化输出当前时间
- ls -lrt 按时间升序列表显示
- dirname 路径 dirname $0
- basename 文件名
- 在环境变量文件中使用alias vi=’vim’即可实现vi代替vim命令
Shell
Shell脚本的建立与执行
Shell 脚本的建立
- 使用文本编辑器编辑脚本文件
- vi script-file
- 为脚本文件添加可执行权限
- chmod +x script-file
Shell 脚本的执行
- 在子Shell中执行
- 变量及结果在结束时从内存销毁,外部shell无法引用
- bash script-file
- 或者./script-file
- 在当前Shell中执行
- 当前shell可继续引用运行结束shell的变量及结果
- source script-file
- . script-file
Shell脚本的编码规范
以 #! 开头:通知系统用何解释器执行此脚本
- #!/bin/bash
- 或者#!/bin/sh
以注释形式说明如下的内容:
- # 脚本名称
- # 脚本功能
- # 作者及联系方式
- # 版本更新记录
- # 版权声明
- # 对算法做简要说明(如果是复杂脚本)
示例
#!/bin/bash # This is the first Bash shell program # Scriptname: greetings.sh echo echo -e "Hello $LOGNAME, \c" echo "it‘s nice talking to you." echo -n "Your present working directory is: " pwd # Show the name of present directory echo echo -e "The time is `date +%T`!. \nBye" echo
时间同步shell脚本
#!/bin/bash ## Script Name:/etc/cron.daily/ntpdate # 使用NTP的客户端命令ntpdate与远程NTP服务器进行同步 # 也可以用局域网内的NTP服务器替换 pool.ntp.org /usr/sbin/ntpdate -s pool.ntp.org # 更改硬件时钟时都会记录在/etc/adjtime文件中 # 使hwclock根据先前的记录来估算硬件时钟的偏差, # 并用来校正目前的硬件时钟 /sbin/hwclock --adjust # 将系统时钟同步到硬件时钟 /sbin/hwclock –systohc
脚本调试方法
在 bash 调用脚本时使用参数
- bash [-x] [-n] [-v] scriptName
- sh –x 脚本名
- 该选项可以使用户跟踪脚本的执行,此时 shell 对脚本中每条命令的处理过程为:先执行替换,然后显示,再执行它。shell 显示脚本中的行时,会在行首添加一个加号 “ + ”
- 以调试模式执行脚本
- sh –v 脚本名
- 在执行脚本之前,按输入的原样打印脚本中的各行
- 显示脚本中每个原始命令行及其执行结果
- sh –n 脚本名
- 对脚本进行语法检查,但不执行脚本。如果存在语法错误,shell 会报错,如果没有错误,则不显示任何内容
- 对脚本进行语法检查
- sh –x 脚本名
在脚本中使用 bash 内置的 set 命令使整个或部分脚本处于调试模式
- 开启:set [-x] [-n] [-v]
- 在脚本内使用set命令开启调试选项
- set -x :显示由shell执行的命令及其参数
- set -v :显示由shell读入的命令行
- set -n :读取命令但不执行他们,用于语法检查
- 在脚本内使用set命令开启调试选项
- 结束:set [+x] [+n] [+v]
- 在脚本内使用set命令关闭已开启的调试选项
- set +x
- set +v
- set +n
- 在脚本内使用set命令关闭已开启的调试选项
示例
#!/bin/bash # This is the first Bash shell program # Scriptname: greetings.sh set -x ### Turn ON debug mode ### echo echo -e "Hello $LOGNAME, \c" echo "it‘s nice talking to you." echo -n "Your present working directory is: " pwd # Show the name of present directory echo set +x ### Turn OFF debug mode ### echo -e "The time is `date +%T`!. \nBye" echo
Shell脚本的类型
非交互式脚本
- 不需要读取用户的输入, 也不用向用户反馈某些信息
- 每次执行都是可预见的, 因为它不读取用户输入, 参数是固定的
- 可以在后台执行
交互式脚本
- 脚本可以读取用户的输入, 实时向用户反馈信息(输出某些信息)
- 这样的脚本更灵活, 每次执行时的参数可由用户动态设定
- 用户界面更友好,但不适用于自动化任务(如cron任务)
Shell变量操作
- 变量替换扩展
- 变量测试
- 变量的字符串操作
- 变量的间接引用
- 变量的数值计算
- $[expression]
- $((expression))
- expr
- let
- declare -i
- 输入
- 变量赋值
- name=value
- readonly
- 从标准输入读取
- read
- 变量赋值
- 输出
- echo
- printf
变量替换扩展
变量测试
示例
字符串计数、截取
示例
字符串替换
示例
变量的间接引用
通过 str2 的值来引用 str1 的值
错误示例
str1="Hello World" str2=str1 echo $str2
正确示例
str1="Hello World" str2=str1 newstr=${!str2} echo $newstr Hello World 或 echo ${!str2} Hello World 或 eval newstr=\$$str2 echo $newstr Hello World 或 eval echo \$$str2 Hello World
x=”CENTOS”
- CENTOS_URL=”http://mirrors.163.com/centos/”
通过 x 的值来引用 CENTOS_URL 的值
# bash2.0以上才支持 newstr=${x}_URL echo $newstr CENTOS_URL echo ${!newstr} http://mirrors.163.com/centos/ 或 eval newstr=\$${x}_URL echo $newstr 或 eval echo \$${x}_URL
Shell内置命令——eval
eval arg1 [arg2] … [argN]
* 对参数进行两次扫描和替换
* 将所有的参数连接成一个表达式,并计算或执行该表达式
* 参数中的任何变量都将被展开
listpage="ls -l | more"
eval $listpage
eval $(ssh-agent)
eval newstr=\$$str2
eval echo \$${x}_URL
Shell 变量的分类
- 用户自定义变量
- 由用户自己定义、修改和使用
- Shell 环境变量
- 由系统维护,用于设置用户的Shell工作环境
- 只有少数的变量用户可以修改其值
- 位置参数变量(Positional Parameters)
- 通过命令行给程序传递执行参数
- 可用 shift 命令实现位置参数的迁移
- 专用参数变量(Special Parameters)
- Bash 预定义的特殊变量
- 用户不能修改其值
位置变量
- 是一组特殊的内置变量
- 跟在脚本名后面的用空格隔开的每个字符串
1表示第1个参数值,……, 9 表示第9个参数值10表示第10个参数值, {11} 表示第11个参数值, ……
- 位置参数的用途
- 从 shell 命令/脚本 的命令行接受参数
- 在调用 shell 函数时为其传递参数
专用参数变量
命令行参数相关
$* 获取当前shell脚本所有传参的参数,将所有位置参量看成一个字符串(以空格间隔),相当于""$1$2$3$4$5 。 [email protected] 将每个位置参量看成单独的字符串(以空格间隔)"$!" "$2" "...."。 "$*" 将所有位置参量看成一个字符串(以$IFS间隔)。 "[email protected]" 将每个位置参量看成单独的字符串(以空格间隔) 。 $0 命令行上输入的Shell程序名。 $# 表示命令行上参数的个数。
进程状态相关
$? 表示上一条命令执行后的返回值 $$ 当前进程的进程号 $! 显示运行在后台的最后一个作业的 PID $_ 在此之前执行的命令或脚本的最后一个参数
示例
位置参数和 shift 命令
- shift [n]
- 将位置参量列表依次左移n次,缺省为左移一次
- 一旦位置参量列表被移动,最左端的那个参数就会从列表中删除
经常与循环结构语句一起使用,以便遍历每一个位置参数
#!/bin/sh # ScriptName: pp_shift.sh # To test Positional Parameters & Shift. echo "The script name is : $0" echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4 -- ‘$#‘="$#" echo ‘[email protected]‘: "[email protected]" shift # 向左移动所有的位置参数1次 echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4 -- ‘$#‘="$#" echo ‘[email protected]‘: "[email protected]" shift 2 # 向左移动所有的位置参数2次 echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4 -- ‘$#‘="$#" echo ‘[email protected]‘: "[email protected]" $ ./pp_shift.sh 1 b 3 d 4 f
退出/返回状态
$?:返回上一条语句或脚本执行的状态
- 0:成功
- 1-255:不成功
- 1:执行正确
- 126:命令或脚本没有执行权限
- 127:命令没有找到
exit 命令
- exit 命令用于退出脚本或当前Shell
- exit n
- n 是一个从 0 到 255 的整数
- 0 表示成功退出,非零表示遇到某种失败
- 返回值 被保存在状态变量 $? 中
示例
$ echo $$ # 显示当前进程的 PID
9245
$ echo $? # 显示在此之前执行的命令的返回值
0
$ bash # 调用子Shell
$ echo $$ # 显示当前进程的 PID
9474
$ exit 1 # 指定返回值并返回父Shell
$ echo $? # 显示上一个Shell/脚本的返回值
1
$ list # 执行不存在的命令
bash: list: command not found
$ echo $?
127
$ touch bbb.sh
$ ./bbb.sh # 执行不具有执行权限的命令
bash: ./bbb.sh: Permission denied
$ echo $?
126
read
- 从键盘输入内容为变量赋值
- read [-p “信息”] [var1 var2 …]
- 若省略变量名,则将输入的内容存入REPLY变量
- 结合不同的引号为变量赋值
- 双引号 ” ”:允许通过$符号引用其他变量值
- 单引号 ’ ’:禁止引用其他变量值,$视为普通字符
- 反撇号
:将命令执行的结果输出给变量
示例
#!/bin/bash
# This script is to test the usage of read
# Scriptname: ex4read.sh
echo "=== examples for testing read ==="
echo -e "What is your name? \c"
read name
echo "Hello $name"
echo
echo -n "Where do you work? "
read
echo "I guess $REPLY keeps you busy!"
echo
read -p "Enter your job title: "
echo "I thought you might be an $REPLY."
echo
echo "=== End of the script ==="
只读变量
- 是指不能被清除或重新赋值的变量
- readonly variable
示例
[[email protected] ~]$ myname=Osmond
[[email protected] ~]$ echo $myname
Osmond
[[email protected] ~]$ readonly myname
[[email protected] ~]$ unset myname
-bash: unset: myname: cannot unset: readonly variable
[[email protected] ~]$ myname="Osmond Liang"
-bash: myname: readonly variable
同时输出多行信息
- 使用 echo
- 使用 here file
整数运算
- Bash 变量没有严格的类型定义
- 本质上 Bash 变量都是字符串
- 若一个字面常量或变量的值是纯数字的,不包含字母或其他字符, Bash可以将其视为长整型值,并可做算数运算和比较运算。
- Bash 也允许显式地声明整型变量
- declare -i 变量名
算数运算符
算术运算扩展—在此没有空格的问题
$ var=test
$ echo $var
test
$ echo $varAA
$varAA
$ echo ${var}AA
testAA
$ ls
a b c
$ echo $(ls)
a b c
$ echo `ls`
a b c
Shell内置命令
let
let 内置命令用于算术运算
num2=1; echo $num2 let num2=4+1; echo $num2 let num2=$num2+1; echo $num2
- 赋值符号和运算符两边不能留空格!
- 如果将字符串赋值给一个整型变量时,则变量的值为 0
如果变量的值是字符串,则进行算术运算时设为 0
let num2=4 + 1 let "num2=4 + 1" # 用引号忽略空格的特殊含义
- 用 let 命令进行算术运算时,最好加双引号
expr
- 通用的表达式计算命令
- 表达式中参数与操作符必须以空格分开。
表达式中的运算可以是算术运算,比较运算,字符串运算和逻辑运算。
expr 5 % 3 expr 5 \* 3 # 乘法符号必须被转义 expr 2 + 5 \* 2 - 3 % 2 expr \( 2 + 5 \) \* 2 – 3 # 括号必须被转义
浮点数运算
- bash 只支持整数运算
可以通过使用 bc 或 awk 工具来处理浮点数运算
n=$(echo "scale=3; 13/2" | bc ) echo $n m=`awk ‘BEGIN{x=2.45;y=3.123;printf "%.3f\n", x*y}‘` echo $m
printf
- printf 可用来按指定的格式输出变量
- printf format 输出参数列表
示例
数组变量
- Bash 2.x 以上支持一维数组,下标从 0 开始
使用 declare 声明或直接给变量名加下标来赋值
declare -a variable variable=(item1 item2 item2 ... )
数组的引用
${variable[n]}
示例
declare
- 内置命令 declare 可用来声明变量
- declare [选项] variable[=value]
示例
declare myname=osmond
declare –r myname=osmond
unset myname
declare myname=“Osmond Liang"
declare –x myname2=lrj
myname2=lrj
declare –x myname2
变量及相关命令小结
条件测试
- 条件测试可以判断某个特定条件是否满足
- 测试之后通常会根据不同的测试值选择执行不同任务
- 条件测试的种类
- 命令成功或失败
- 表达式为真或假
- 条件测试的值
- Bash中没有布尔类型变量
- 退出状态为 0 表示命令成功或表达式为真
- 非0 则表示命令失败或表达式为假
- 状态变量 $? 中保存了退出状态的值
- Bash中没有布尔类型变量
示例
条件测试语句
- 语句
- 格式1: test <测试表达式>
- 格式2: [ <测试表达式> ]
- 格式3: [[ <测试表达式> ]] (bash 2.x 版本以上)
- 说明
- 格式1 和 格式2 是等价的,格式3是扩展的 test 命令
- 在 [[ ]] 中可以使用通配符进行模式匹配
- &&, ||, <, 和>能够正常存在于[[ ]]中,但不能在 [] 中出现
- [和[[之后的字符必须为空格,]和]]之前的字符必须为空格
- 要对整数进行关系运算也可以使用 (()) 进行测试
条件测试操作符
- 条件测试表达式中可用的操作符
- 文件测试操作符
- 字符串测试操作符
- 整数二元比较操作符
- 使用逻辑运算符
文件测试
- 测试:文件是否存在,文件属性,访问权限等
字符串测试
- 字符串按从左到右对应字符的ASCII码进行比较
字符串空值检查
检查空值
检查非空值
整数测试
- 操作符两边必须留空格!
- 操作符两边的空格可省略
示例
逻辑测试
示例
流程控制——分支
- 流程控制语句
- 分支
- if 条件语句
- case 选择语句
- 循环
- for 循环语句
- while 循环语句
- until 循环语句
- select 循环与菜单
- 循环控制
- break 语句
- continue 语句
- 位置参数处理
- shift 命令
- getopts 命令
- 分支
if 语句
if expr1 # 如果 expr1 为真(返回值为0)
then # 那么
commands1 # 执行语句块 commands1
elif expr2 # 若 expr1 不真,而 expr2 为真
then # 那么
commands2 # 执行语句块 commands2
... ... # 可以有多个 elif 语句
else # else 最多只能有一个
commands4 # 执行语句块 commands4
fi # if 语句必须以单词 fi 终止
- elif 可以有任意多个(0 个或多个)
- else 最多只能有一个(0 个或 1 个)
- if 语句必须以 fi 表示结束
- exprX 通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值。
- commands 为可执行语句块,如果为空,需使用 shell 提供的空命令 “ : ”,即冒号。该命令不做任何事情,只返回一个退出状态 0
- if 语句可以嵌套使用
示例
case语句
case expr in # expr 为表达式,关键词 in 不要忘!
pattern1) # 若 expr 与 pattern1 匹配,注意括号
commands1 # 执行语句块 commands1
;; # 跳出 case 结构
pattern2) # 若 expr 与 pattern2 匹配
commands2 # 执行语句块 commands2
;; # 跳出 case 结构
... ... # 可以有任意多个模式匹配
*) # 若 expr 与上面的模式都不匹配
commands # 执行语句块 commands
;; # 跳出 case 结构
esac # case 语句必须以 esac 终止
- 表达式 expr 按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命令,然后退出 case。
- 如果 expr 没有找到匹配的模式,则执行缺省值 “ ) ” 后面的命令块 ( 类似于 if 中的 else );“ ) ” 可以不出现。
- 所给的匹配模式 pattern 中可以含有通配符和“ | ”。
- 每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面。
流程控制——循环
for variable in list
# 每一次循环,依次把列表 list 中的一个值赋给循环变量
do # 循环体开始的标志
commands # 循环变量每取一次值,循环体就执行一遍
done # 循环结束的标志,返回循环顶部
- 列表 list 可以是命令替换、变量名替换、字符串和文件名列表 ( 可包含通配符 ),每个列表项以空格间隔
- for 循环执行的次数取决于列表 list 中单词的个数
可以省略 in list ,省略时相当于 in “[email protected]”
首先将 list 的 item1 赋给 variable
- 执行do和done之间的 commands
- 然后再将 list 的 item2 赋给 variable
- 执行do和done之间的 commands
*如此循环,直到 list 中的所有 item 值都已经用完
- 执行do和done之间的 commands
示例
break 和 continue
- break [n]
- 用于强行退出当前循环
- 如果是嵌套循环,则 break 命令后面可以跟一数字 n,表示退出第 n 重循环(最里面的为第一重循环)
- continue [n]
- 用于忽略本次循环的剩余部分,回到循环的顶部,继续下一次循环
- 如果是嵌套循环,continue 命令后面也可跟一数字 n,表示回到第 n 重循环的顶部
示例
for循环(C语言型)语法
for ((expr1;expr2;expr3)) # 执行 expr1
do # 若 expr2的值为真时进入循环,否则退出 for循环
commands # 执行循环体,之后执行 expr3
done # 循环结束的标志,返回循环顶部
- 通常 expr1和 expr3是算数表达式; expr2是逻辑表达式
- expr1 仅在循环开始之初执行一次
- expr2 在每次执行循环体之前执行一次
expr3 在每次执行循环体之后执行一次
首先执行 expr1
- 执行 expr2
- 其值为假时,终止循环
- 其值为真时,执行do和done之间的 commands
- 执行expr3,进入下一次循环
示例
while 循环语句
while expr # 执行 expr
do # 若expr的退出状态为0,进入循环,否则退出while
commands # 循环体
done # 循环结束标志,返回循环顶部
示例
* While 和输入重定向
* 使用管道为 while 传递输入
until 循环语句
until expr # 执行 expr
do # 若expr的退出状态非0,进入循环,否则退出until
commands # 循环体
done # 循环结束标志,返回循环顶部
示例
将循环结果通过管道传递给其他命令处理(done |)
后台执行循环(done &)
循环与菜单
- 一般地,使用 while 循环配合 case实现
- Bash 提供了专门的 select 循环
- select 循环主要用于创建菜单
- select 是个无限循环
- 通常要配合 case 语句处理不同的选单及退出
- select 循环的退出
- 按 ctrl+c 退出循环
- 在循环体内用 break 命令退出循环
- 或用 exit 命令终止脚本
示例
- 使用while循环实现菜单
循环结构——select 语法
select variable in list
do # 循环开始的标志
commands # 循环变量每取一次值,循环体就执行一遍
done # 循环结束的标志
- 按数值顺序排列的菜单项(list item)会显示到标准输出
- 菜单项的间隔符由环境变量 IFS 决定
- 用于引导用户输入的提示信息存放在环境变量 PS3 中
- 用户输入的值会被存储在内置变量 RELAY 中
- 用户直接输入回车将重新显示菜单
- 与 for 循环类似,省略 in list 时等价于 in “$*”
示例
位置参数和命令行参数处理
- 在脚本中经常使用流程控制处理位置参数
- 循环结构:while、for
- 多分支结构:case
- 在脚本中经常使用如下命令配合位置参数处理
- shift
- getopts
示例
- 参数位置遍历
- 位置参数处理举例
选项和参数
- mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
- -z是个选项(option),以减号开始的单字符
- -c也是个选项,/etc/mybackup.conf 是该选项的附加参数(additional argument )
- -r和-v也是选项,且不带附加参数
./foo.txt 和 ./mydir 是脚本的处理对象,他们是不与任何选项相关的参数,在POSIX?标准中称其为“操作 对象/数”(operands)
按照Linux的命令行书写规范,如下命令行
- mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
也可以写成如下的等价形式
- mybackup -zr -c /etc/mybackup.conf -v ./foo.txt ./mydir
- mybackup -zv -c /etc/mybackup.conf -r ./foo.txt ./mydir
- mybackup -vr -c /etc/mybackup.conf -z ./foo.txt ./mydir
- mybackup -vz -c /etc/mybackup.conf -r ./foo.txt ./mydir
- mybackup -zrv -c /etc/mybackup.conf ./foo.txt ./mydir
- mybackup -zrvc /etc/mybackup.conf ./foo.txt ./mydir
- 用户使用自己的代码分析这些选项将变得十分困难
- Shell的内置命令getopts可以识别所有常见的选项格式,为用户处理选项和参数提供了方便
内置命令——getopts
- getopts OPTSTRING VARNAME [ARGS…]
- OPTSTRING
- 是由若干有效的选项标识符组成的选项字符串
- 若某选项标识符后有冒号,则表示此选项有附加参数
- 若整个字符串前有冒号,将使用“安静”的错误模式
- VARNAME :每次匹配成功的选项保存在变量中
ARGS : 参数列表,省略时为 ”[email protected]”
getopts c:zrv opt
getopts :c:zrv opt
getopts的执行过程
- 通常需要以循环的方式执行多次 getopts 来解析位置参数中的选项以及可能存在的选项附加参数
*每次调用 getopts,将会处理参数列表中的“下一个”选项
- 将选项存储在VARNAME变量中
- 将此选项对应的附加参数存储在环境变量OPTARG中
- 对环境变量OPTIND进行自增操作,使 $OPTIND 总是指向原始参数列表中“下一个”要处理的元素位置
- 若
VARNAME与 OPTSTRING的所有选项均不匹配,则做“invalid option”的错误设置 - 若某选项的参数不存在,则做“required argument not found”的错误设置
- 通常需要以循环的方式执行多次 getopts 来解析位置参数中的选项以及可能存在的选项附加参数
getopts的错误报告模式
- 冗余(Verbose)模式( OPTSTRING 不以:开头)
- “invalid option”
- VARNAME=“?” ; unset OPTARG
- “required argument not found”
- VARNAME=“?” ; unset OPTARG 并输出错误信息
- “invalid option”
- 安静(Silent)模式( OPTSTRING 以:开头)
- “invalid option”
- VARNAME=“?” ; OPTARG=‘无效的选项字符’
- “required argument not found”
- VARNAME=“:” ; OPTARG=‘与参数对应的选项字符’
- “invalid option”
while循环与getopts处理
while getopts OPTSTRING VARNAME
do
case $VARNAME in
…) ………… ;;
…) ………… ;;
:) ………… ;;
\?) ………… ;;
esac
done
- getopts 返回假时终止 while 循环
- 当 getopts 遭遇到第一个非选项参数时终止解析
- 当 getopts 遭遇到 “–”参数时终止解析
getopts的注意事项
- getopts 不能解析 GNU-style 长参数 (–myoption)
- getopts从不改变原始位置参数
- 若希望移动位置参数,需手工执行 shift
- getopts会自动对变量 OPTIND 做自增处理
- OPTIDX的初始值为 1
- 若要重新解析命令行参数,需将OPTIDX的值置为 1
- getopts 遭遇到第一个非选项参数时终止解析
- 终止解析后执行命令
- shift ((OPTIND-1))
- 可以使 ”[email protected]” 只包含“操作 对象/数”(operands
- 终止解析后执行命令
示例
示例1
#!/bin/bash ## filename : pp_parse_getopts_1.sh while getopts "abc:def:ghi" flag do echo "$flag" $OPTIND $OPTARG done echo "Resetting" OPTIND=1 while getopts "bc:def:ghi" flag do echo "$flag" $OPTIND $OPTARG done $ ./pp_parse_getopts_1.sh -a -bc foo -f "foo bar" -h –gde $ ./pp_parse_getopts_1.sh -abf "foo bar" -h -gde –c $ ./pp_parse_getopts_1.sh -abf “foo bar” -h –c -gde
示例2
#!/bin/bash ## filename : pp_parse_getopts_2.sh while getopts ":abc:def:ghi" flag do echo "$flag" $OPTIND $OPTARG done echo "Resetting" OPTIND=1 while getopts ":bc:def:ghi" flag do echo "$flag" $OPTIND $OPTARG done $ ./pp_parse_getopts_2.sh -a -bc foo -f "foo bar" -h -gde $ ./pp_parse_getopts_2.sh -abf "foo bar" -h -gde –c $ ./pp_parse_getopts_1.sh -abf “foo bar” -h –c -gde
* 示例3
#!/bin/bash
## filename : mybackup_getopts.sh
while getopts :zc:x:rv opt
do
case $opt in
c) ConfFile=$OPTARG ;;
x) ExcludeFile=$OPTARG ;;
z) Compress=true ;;
r) Recursive=true ;;
v) Verbose=true ;;
:)
echo "$0: Must supply an argument to -$OPTARG." >&2
exit 1
;;
\?) echo "Invalid option -$OPTARG ignored." >&2 ;;
esac
done
shift $((OPTIND-1)) ; echo $0 ; echo "[email protected]"
示例4
#!/bin/bash ## filename : mybackup_getopts2.sh while getopts :zc:x:rv opt do case $opt in c) if [[ $OPTARG = -* ]]; then ((OPTIND--)) ; continue ; fi ConfFile=$OPTARG ;; x) ExcludeFile=$OPTARG ;; z) Compress=true ;; r) Recursive=true ;; v) Verbose=true ;; :) echo "$0: Must supply an argument to -$OPTARG." >&2 exit 1 ;; \?) echo "Invalid option -$OPTARG ignored." >&2 ;; esac done shift ((OPTIND-1)) ; echo $0 ; echo "[email protected]"
函数
- 为了避免大型脚本变得复杂、晦涩而使用函数
- 将大型脚本代码分割成小块,将这些被命名的代码块称为函数
- 一个函数就是一个子程序,用于完成特定的任务
- 如:添加一个用户、判断用户是否为管理员 等
- 一个函数就是一个子程序,用于完成特定的任务
- 函数定义之后可以被使用它的主程序调用
- 调用函数的方法与执行Shell命令无异
- 可以在Shell脚本中调用(函数需先定义而后调用)
- 在命令行上直接调用(定义函数的文件需先加载
合理使用Shell函数
- 简化程序代码,实现代码重用
- 实现一次定义多次调用。如:is_root_user()函数可以由不同的shell脚本重复使用。
- 实现结构化编程
- 使脚本内容更加简洁,增强程序的易读性
- 提高执行效率
- 将常用的功能定义为多个函数并将其保存在一个文件中
- 类似其他语言的“模块”文件
- 在 ~/bashrc 或命令行上使用 source 命令调用这个文件
- 此文件中定义的多个函数一次性地调入内存,从而加快运行速度
- 将常用的功能定义为多个函数并将其保存在一个文件中
函数的定义和调用
函数定义
函数调用
- 只需输入函数名即可调用函数
- 函数名
- 函数名 参数1 参数2 …
- 函数必须在调用之前定义
函数的存储和显示
- 函数的存储
- 函数和调用它的主程序保存在同一个文件中
*函数的定义必须出现在调用之前
*函数和调用它的主程序保存在不同的文件中
- 保存函数的文件必须先使用 source 命令执行,之后才能调用其中的函数
- 函数和调用它的主程序保存在同一个文件中
- 函数的显示
- 显示当前Shell可见的所有函数名
- $ declare -F
- 显示当前Shell可见的所有(指定)的函数定义
- $ declare -f
- $ declare -f
- 显示当前Shell可见的所有函数名
示例
函数的定义和调用
示例1
#!/bin/bash ## filename: all_in_one_backup_select.sh ### User define Function (UDF) ### sql_bak () { echo "Running mysqldump tool..."; } sync_bak () { echo "Running rsync tool..."; } git_bak () { echo "Running gistore tool..."; } tar_bak () { echo "Running tar tool..."; } ### Main script starts here ### PS3="Please choose a backup tools : " select s in mysqldump rsync gistore tar quit ; do case $REPLY in 1) sql_bak ;; 2) sync_bak ;; 3) git_bak ;; 4) tar_bak ;; 5) exit ;; esac done
示例2
#!/bin/bash ## filename: /root/bin/my_backup_functions.sh ### User define Function (UDF) ### sql_bak () { echo "Running mysqldump tool..."; } sync_bak () { echo "Running rsync tool..."; } git_bak () { echo "Running gistore tool..."; } tar_bak () { echo "Running tar tool..."; }
示例3
#!/bin/bash ## filename: all_in_one_backup_select.sourcefunc.sh source /root/bin/my_backup_functions.sh ### Main script starts here ### PS3="Please choose a backup tools : " select s in mysqldump rsync gistore tar quit ; do case $REPLY in 1|[mM]ysqldump) sql_bak ;; 2|[rR]sync) sync_bak ;; 3|[gG]istore) git_bak ;; 4|[tT]ar) tar_bak ;; 5) exit ;; esac done
函数与变量
- 参数(Arguments)
- 调用函数时,使用位置参数的形式为函数传递参数
- 函数内的
1? {n} 、?和 @ 表示其接收的参数 - 函数调用结束后位置参数
1? {n} 、?和 @ 将被重置为调用函数之前的值 - 在主程序和函数中,$0始终代表脚本名
- 变量(Variables)
*函数内使用 local 声明的变量是局部(Local)变量
*局部变量的作用域是当前函数以及其调用的所有函数
- 函数内未使用 local 声明的变量是全局(Global)变量
*即主程序和函数中的同名变量是一个变量(地址一致
- 函数内未使用 local 声明的变量是全局(Global)变量
示例
函数与位置参数
示例1
#!/bin/bash ## filename: pp_and_function.sh echo "===Print positional parameters in main :" echo "$0: $*" pp1(){ echo ‘f1--Print $* parameters in fun1 :‘ ; echo "$0: $*" } pp2(){ echo ‘f2--Print $* parameters in fun1 :‘ ; echo "$0: $*" pp1 1st 2nd 3th 4th 5th 6th 7th 8th 9th echo ‘f2--Print $* parameters in fun1 :‘ ; echo "$0: $*" } pp1 1 2 3 4 5 6 7 8 9 echo "===Print positional parameters in main :" echo "$0: $*" pp2 I II III IV V VI VII VIII IX ./pp_and_function.sh a b c d e f g h i
示例2
#!/bin/bash ## filename: function_max.sh # User define Function (UDF) usage () { echo "List the MAX of the positive integers in command line. " echo "Usage: `basename $0` <num1> <num2> [ <num3> ... ]" exit } max () { [[ -z $1 || -z $2 ]] && usage largest=0 for i ; do ((i>largest)) && largest=$i ; done } ### Main script starts here ### max "[email protected]" echo "The largest of the numbers is $largest." ./function_max.sh 1 58 111 32768 66
由于largest变量在函数max内没有使用local声明,所以它是全局的
函数的结束与返回值
- 当函数的最后一条命令执行结束函数即结束
- 函数的返回值就是最后一条命令的退出码
- 其返回值被保存在系统变量$?中
- 可以使用 return 或 exit 显式地结束函数
- return [N]
- return 将结束函数的执行
- 可以使用 N 指定函数返回值
- exit [N]
- exit 将中断当前函数及当前Shell的执行
- 可以使用 N 指定返回值
- return [N]
示例
#!/bin/bash
## filename: function_max2.sh
# User define Function (UDF)
max2 () {
if [[ -z $1 || -z $2 ]] ; then
echo "Need 2 parameters to the function." ; exit
fi
[ $1 -eq $2 ] &&
{ echo "The two numbers are equal." ; exit ; }
(($1>$2)) && return $1 || return $2
}
### Main script starts here ###
read -p "Please input two integer numbers : " n1 n2
echo "n1=$n1 , n2=$n2“
max2 $n1 $n2
return_val=$?
echo "The larger of the two numbers is $return_val."
函数返回值
- 使用全局变量引用函数的值不利于结构化编程
- 使用 return 或 exit 只能返回整数值
- 使用标准输出实现函数的返回值
- 是一种通用的方法,既能返回整数又能返回字符串
- 函数结束前使用 echo 命令将结果显示到标准输出
- 调用函数时使用如下的格式将函数的输出结果存到变量 RES 中,之后便可使用变量 $RES 的值(或输出、或执行测试、或进一步处理等)
- RES=$(functionName)
- echo $RES
示例
使用标准输出返回函数值
#!/bin/bash ## filename: function_to-upper.sh # User define Function (UDF) to_upper () { local str="[email protected]" local output output=$(tr ‘[a-z]‘ ‘[A-Z]‘<<<"${str}") echo $output } ### Main script starts here ### to_upper "This Is a TEST" res=$(to_upper "[email protected]") echo "$res" res=$(to_upper "$1") [[ $res == "YES" ]] && echo "Continue..." || echo "Stop" ./function_to-upper.sh YES we are ./function_to-upper.sh No we are not
系统INIT 启动脚本的结构——/etc/rc.d/init.d/*
以上是关于linux&shell的主要内容,如果未能解决你的问题,请参考以下文章
Linux Shell脚本 && Linux C程序 获取指定的范围内 or 系统可用端口