一、shell基本使用
1、第一行指定要使用的shell,例 #!/bin/bash
2、# 用作注释行
3、给脚本赋予可运行的权限,chmod u+x file
4、输出 echo text 例 $ echo This is a test
或者echo ”text“ 例 $ echo " you're paying attention" (用在text里面含有引号的时候)
取消echo后面的换行符 echo -n text / ”text“
5、变量:Shell脚本临时存储信息
5.1、使用环境变量 $ENVIRONMENT 例 echo UID: $UID (此时环境变量被替换成一个值,可以直接输出)
5.2、正常使用美元符号时,需要加转义字符‘\’
5.3、用户变量定义后再整个脚本有效,相当于全局变量,函数里的变量是局部变量
5.4、用户变量右字母数字下划线组成,长度不超过20,区分大小写
5.5、用户变量赋值 key=value或key=”text“ , 当文本中含有空格时加上双引号
5.6、用户变量使用 $key ,注意区分美元号使用,例如更新值时,key2=$key1
6、命令替换:将命令输出的信息赋值给变量,运行脚本的shell创建子shell执行对应命令,所以命令中不能含脚本创建的变量
6.1、使用反引号 var=·command· 例 testing='date'
6.2、使用$() : var=$(command) 例 testing=$(date)
6.3、常用当前时间生成唯一的日志文件 today=$(date +%y%m%d) ; data > log.$today
7、重定向与管道
7.1、输入重定向 command > outputfile 例 date > test6 若文件名已存在,会覆盖源文件
7.2、输入重定向追加 command >> outputfile
7.3、输入重定向 command < inputfile 例 wc < test6
7.4、内联输入重定向 command << marker 例 $ wc << EOF (右边不是文件,而是正常的键盘输入)
data > test string 1
marker > test string 2
> EOF
7.5、管道用于将一个命令的输出作为另一个命令的输入 command1 | command2
例 cat numberfile | sort 例 $ rpm -qa | sort | more
8、数学运算
8.1、expr运算命令 expr n1 opration n2 例 $ expr 1 + 5 计算乘法需要转义因为乘号定义有其他运算 expr 2 \* 5
数学算式赋值给变量需要使用命令替换 例 var3=$(expr $var2 / $var1)
8.2、方括号运算赋值 (仅整数运算) var=$[ operation ] 例 var1=$[1 + 5] var4=$[$var1 * ($var2 - $var3)] 不用转义乘号
8.4、bc计算能计算浮点表达式 variable=$(echo "options; expression" | bc)
9、脚本退出,每个命令都含有退出状态码,范围0-255整数,$?保存上个已执行命令的退出状态码
成功时是0,否则是正数,126无权限,1无效参数
9.1、exit退出脚本并返回一个指定的退出状态码 exit n 例 exit 5 ,若大于255会对256取余
二、结构化选择命令
1、选择结构
执行哪个分支由command的退出状态码决定,0则执行then
if command1
then
commands
else
commands
fi
1.1、结构语句也可以嵌套,嵌套可以转化为单个选择结构,使用elif
if command1
then
commands
elif command2
then
commands
elif
commands
then
commands
fi
1.2、使用text命令来进行if的条件判断实现高级语言类似的选择结构
test condition condition是要测试的条件,真则返回退出状态0,若condition为空,则直接返回非零退出状态码
condition可是变量,若有内容返回0,空返回正数
1.3、方括号进行条件测试,方括号旁边必须是空格
if [ condition ]
then
commands
fi
1.3.1、数值比较 [ n1 option n2 ],option:-eq等于,-gt大于,-lt小于,-ge大于等于,-le小于等于,-ne不等于
无法处理浮点数
1.3.2、字符串比较 [ str1 option str2 ],option:=相同,!=不相同,\<小,\>大,(-n非零,-z长度为零,str2为空时的两 种) 大和小的比较注意使用转义,否则是重定向;ASCII码顺序和sort不同,这里的比较是标准ASCII比较, sort是本地化语言的比较
1.3.3、文件比较 option file ,option:-d目录,-e存在,-f文件,-rwx读写可执行,-s空,-O属主,-G属组
1.4、条件测试可以复合进行 [ condition1 ] option [ condition2 ],option:&&与,||或
1.5、双括号进行高级数值条件比较 (( expression )) 可以用前后自增,位运算,位左右移,位逻辑,逻辑,幂运算等
例 if (( $val1 ** 2 > 90 )) , 双括号><不需要转义
1.6、双方括号进行高级字符串比较 [[ expression ]],使用test命令中的标准字符串比较,支持模式匹配
1.7、case分支选择命令
case varieable in
pattern1 | pattern2) commands;;
pattern3) commands;;
*) default commands;;
esac
三、结构化循环命令
1、for循环:重复执行一组命令,每次迭代var使用list中的一个值,$var使用该值,迭代完$var保存的值直到shell结束均有效
for var in list
do
commands
done
例
for test in ala ari ark cal col
do
echo the next is $test
done
1.1、解决list中存在单引号,可用转义字符或双引号
1.2、解决list中单个值存在空格,使用双引号
1.3、解决list是一个列表类型变量,直接使用
1.4、解决list是一个命令替换的输出,直接使用
1.5、解决存入list各字段的字段分隔符,内部字段分隔符环境变量IFS默认将空格、制表符、换行符作为字段分隔,通过更改 IFS来解决,例 IFS.OLD=$IFS IFS=$'\n' IFS=IFS.OLD 指定换行符:IFS=: ,指定多换行符IFS=$'\n':;"
$'String'可进行正确的转义\n
1.6、list可通过通配符获得列表,list也可以是多个用空格隔开的多个值 例 for file in /home/rich/.b* /home/rich/badtest
2、C语言风格 for (( variable assignment ; condition ; iteration process )) 例
for (( a=1, b=10; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
3、while循环
while test command
do
other commands
done
3.1、while中的判断条件与if-else相同
3.2、while中可用多个测试命令,但循环结束由最后一个条件退出状态决定
4、until命令,与while类似
until test commands
do
other commands
done
5、嵌套循环 例
while [ $var1 -ge 0 ]
do
echo "Outer loop: $var1"
for (( var2 = 1; $var2 < 3; var2++ ))
do
var3=$[ $var1 * $var2 ]
echo " Inner loop: $var1 * $var2 = $var3"
done
var1=$[ $var1 - 1 ]
done
6、跳出循环 break 可以用在循环的if-else语句中的then部分跳出循环,
也可以跳出外部循环。 break n ,n指定了要跳出的循环层级,默认为1
7、继续执行 continue 中止某次循环中的指令,继续下一次循环
也可以继续提下剩余命令,继续下一次外部循环 , continue n
四、脚本中的重定向
1、循环的输出使用管道或重定向,在done命令后添加一个处理命令来实现
例,此时将for命令结果的所有输出重定向到txt文件中
for file in /home/rich/*
do
if [ -d "$file" ]
then
echo $file is a directory"
elif
echo "$file is a file"
fi
done > output.txt
例,使用管道将for输出传到sort排序并输出
for state in "North Dakota" Connecticut Illinois Alabama Tennessee
do
echo "$state is the next place to go"
done | sort
例,使用重定向从csv文件中读取内容存到list
input="users.csv"
while IFS=',' read -r userid name
do
echo "adding $userid"
useradd -c "$name" -m $userid
done < "$input"
2、每个对象都当作文件处理,包括输入输出进程。每个文件都有文件描述符来标识,是一个大于等于0的数。
每个进程最多有九个文件描述符,0标识STDIN,1标识STDOUT,2标识STDERR。
2.1、STDIN表示标准输入,对终端就是键盘。使用重定向<后,就会用指定的文件替换STDIN,读取文件数据
2.2、STDOUT表示标准输出,终端就是显示器,可以使用重定向>改变,输出到指定的文件,或>>
2.3、STDERR表示错误信息输出,终端就是显示器,重定向错误使用command 2> file
2.4、同时重定向STDOUT和STDERR,例 ls -al test test2 test3 badtest 2> test6 1> test7
同时重定向STDOUT和STDERR到一个文件,command &> file , 并且错误输出的优先级更高
3、脚本重定向输出
3.1、临时重定向一条命令, echo text >&2 ./script 2> file,如果没有后面一行则依然输出到屏幕
第一条命令表示这个输出重定向给STDERR而不是STDOUT,第二行会将SRDERR重定向给指定的文件
并且第二行对于整个脚本都有效
3.2、永久重定向,令脚本所有输出都重定向到指定文件,而不是使用n次 >&2 。exec , 相当与3.1的第二条命令
例 exec 1>testout ,则接下来所有STDOUT的输出都会送到testout文件
4、脚本重定向输入
4.1、exec 0< textfile 文件中获得输入,而不是STDIN。
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
5、创建自己的输出重定向。exec 3> file 结合 echo "string" >&3使用,追加 :使用>>
6、创建自己的输入重定向 , 先从文件读,再从键盘读
exec 6<&0
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
exec 0<&6
7、关闭文件描述符,exec 3>&- 关闭再开启且文件相同,则会覆盖文件
8、查看所有的文件描述符 lsof
9、关闭输出,重定向到/dev/null ;从/dev/null/重定向输入进行快速清除数据
10、记录消息 tee filename,STDIN的输入同时重定向到STDOUT和日志文件,选项:-a追加
例 $ date | tee -a testfile
五、处理用户输入
1、运行脚本时添加参数 例 ./addem 10 30 , 这些参数必须用空格分开,参数中存在空格必须使用引号
bashshell使用称为位置参数的特殊变量分配给运行时输入的参数,$0表示程序名,$1表示第一个参数,
$2表示第二个参数 ... $9表示第九个参数 , ${10}表示第是个参数,以此类推
1.1、脚本使用参数时一定要判断参数是否存在,否则会报错。例 if [ -n "$1" ]
1.2、特殊参数变量$# 表示命令行参数的个数,${!#}表示最后一个参数
1.3、获取所有参数 $*单个变量存储所有参数并当作一个单词,$@单个变量存取所有参数当作一个列表
2、移动变量shift , 移动命令行参数,默认向左移动一个位置,$1的值被删除,$2会移动到$1,$3会移动到$2,依次类推
2.1、移出后无法恢复
2.2、可一次移动多个位置 shift n ,例 shift 2
3、运行脚本时添加选项,选项就是 -a 这样
3.1、可将选项当作参数进行处理。使用$1获得等,判断选项存在,可使用shift
3.2、分离参数和选项,使用双破折线--表明选项结束,检测到双破折线shift
例 ./test16.sh -c -a -b -- test1 test2 test3
4、使用getopt处理选项和参数 ,getopt optstring parameters,optstring定义了有效的选项,及哪些选项含有参数值
例 getopt ab:cd -a -b test1 -cd test2 test3 , b选项需要参数,所以后面加上冒号,处理后cd会分离,在选项参数之间加入--
4.1、选项:-q 忽略因多余选项等产生的错误信息
4.2、脚本处理 set -- $(getopt -q ab:cd "$@")
4.3、含有双引号的参数里面的空格会被当作参数分隔符而不是一个整体参数
5、使用getopts命令 getopts optstring variable , 处理完后返回大于0的退出状态码
5.1、OPTARG环境变量保存选项使用的参数值,OPTIND环境变量保存getopts正在处理的参数位置
例
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG";;
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt";;
esac
done
5.2、会移出选项前的-,并且没有--
5.3、参数中可以由空格,结合引号使用
5.4、未定义选项输出为?
5.5、选项处理过程中,每处理一个选项,OPTIND自增,选项处理完,使用shift和 OPTIND来移动参数
例
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1 ]
done
6、用户在脚本运行时输入并读取:read 从标准输入或另一个文件描述符中接收输入并放入变量
例 read name 选项:-p,只用提示符 例 read -p "Please enter your age: " age
6.1、提示符后输入的所有数据都会指定给一个变量,若有多个变量,则每个数据都会分配给下一个变量,多余的数值分配给最 后一个变量
6.2、不指定变量时,数据分配给REPLY环境变量
6.3、选项:-t 指定计时器,过期后返回非零状态码;-n 接受的字符数量;-s隐藏方式读取
七、函数 - 代码块的多次复用
1、创建函数 , 函数名在一个脚本内唯一
形式1
fucntion name {
commands
}
形式2
name() {
commands
}
2、使用函数,必须先定义后使用 ,直接使用函数名即可调用 例 func1
3、函数的返回值,默认情况是函数中最后一条命令返回的退出状态码,通过$?获得函数退出状态码
4、函数返回值,使用return命令退出函数并返回特定的退出状态码
4.1、范围0-255。且函数以结束就要$?获得返回值,否则将丢失
4.2、函数返回其他类型的函数输出,可以将输出保存到变量,例 result='func1' , 不会读取read的输出,仅仅是echo的输出
5、向函数传递参数,shell将函数当作小型脚本,可以用向shell脚本传递参数的形式
5.1、函数内使用$1 $2 $0等获取参数内容
5.2、向函数传递时,必须将函数和参数放在一行 例 func1 $value1 10 例 value=$(addem 10 15)
5.3、函数不可以通过$1等获得运行脚本时传递的参数
6、脚本的变量分为全局变量和局部变量
6.1、函数外定义的变量时全局变量,在函数内修改后的新值在函数外依然有效
6.2、局部变量是在函数内声明的变量 ,声明时 例 local temp ,赋值时 例 local temp=$[ $value + 5 ] ,只在函数内有效
函数内若全局变量和局部变量同名,修改同名变量的值不会改变全局变量,使用同名变量也只会使用局部变量
6.3、也可以在函数内定义全局变量,并修改。声明时不加local,函数外依然可以使用
7、传递数组参数,若将数组变量当单个参数传递将不会起作用,此时函数只会取数组变量第一个值
7.1、必须将数组变量拆成单个值再作为函数参数使用,可以在函数内部重组成新数组变量
myarray=(1 2 3 4 5)
func1 ${myarray[*]}
或
myarray=(1 2 3 4 5)
func1=$(echo ${myarray[*]})
fuunc1() {
newarray=($(echo "$@"))
for value in ${newarray[*]}
do
commands
done
}
8、函数返回数组, 按正确顺序输出单个数组值,脚本再将他们放进一个新的数组变量
result=($(arraydblr $arg1))
9、函数可递归使用,注意设置基准条件
10、添加函数库 , 使用source 命令或者 点操作符’.‘
例 ../myfuncs