标签:windows python 解释器 linux 知识点
bash脚本编程的所有语法知识点总结第一部分
名词概念
bash脚本编程,从字面意思理解也就是shell脚本编程。bash应该是目前Linux上最流行的shell脚本解释程序。shell是一个命令语言解释器,而shell脚本则是Linux命令的集合,按照预设的顺序依次解释执行,来完成特定的、较复杂的系统管理任务,类似于Windows中的批处理文件。
第一行,顶格。
eg:
#!/bin/bash
#!/usr/bin/python
其它的以#开头的行均为注释,会被解释器忽略;
执行方式:
bash编程属于面向过程编程,执行方式如下:
顺序执行:按命令先后顺寻依次执行
选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支
循环执行:将同一段代码反复执行多次,因此,循环必须有退出条件;否则,则陷入死循环
执行相关选项
bash-n SHELLNAME
#语法测试,测试是否存在语法错误
bash -x SHELLNAME
#模拟单步执行,显示每一步执行过程
只对当前shell进程有效的变量;对其它shell进程无效,包当前shell进程的子进程也无效;
VAR_NAME=VALUE
变量赋值:向变量的存储空间保存数据
变量引用:${VAR_NAME}或者反单引号``
bash中,其用法同$()一样,用``括起来的内容代表一个变量,例如 echo `ls`
根据POSIX规范,要求系统工程师采用的是$(命令)的形式。所以,我们最好还是遵循这个规范,少用``,多用$()
"":弱引用,里面的变量会被替换;
‘‘:强引用,里面的所有字符都是字面量,直接输出;
eg: echo “$name” jerry
echo ‘$name’ $name
对当前shell进程及其子shell有效,对其它的shell进程无效;
定义:export VAR_NAME=VALUE
导出:export VAR_NAME
用户可自义环境变量
bash有许多内置的环境变量
撤消变量:unset VAR_NAME
只读变量:readonly VAR_NAME
对shell脚本中某代码片断有效;通常用于函数本地;
local VAR_NAME=VALUE
用来接受变量指定位置的参数
$1, $2, ..., ${10}
shell对一些参数做特殊处理,这些参数只能被引用而不能被赋值
$# 传递到脚本的参数个数
$*显示所有向脚本传递的参数 #与位置变量不同,此选项参数可超过9个
$$ 获取当前shell的进程号
$! 执行上一个指令的进程号
$? 获取执行的上一个指令的返回值 #0为执行成功,非零为执行失败
$- 显示shell使用的当前选项,与set命令功能相同
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数
查看当前shell进程中的所有变量:set
查看当前shell进程中的所有环境变量:export,printenv, env
a、不能使用程序中的关键字(保留字);
eg:if, case, for
b、只能使用数字、字母和下划线,且不能以数字开头;
c、要见名知义
数值型:
精确数值:整数
近似数值:浮点型
单精度浮点
双精度浮点
字符型:char,string
布尔型:true, false
类型转换:显式转换,隐式转换
bash是弱类型的语言:一切皆字符
为交互式登录的用户提供配置
全局:/etc/profile /etc/profile.d/*.sh 配置文件片段
用户:~/.bash_profile
功用:
1、设定环境变量
2、运行命令或脚本
为非交互式的用户(后台运行,非用户登录)提供配置
全局:/etc/bashrc
用户:~/.bashrc
功用:
1、设定本地变量
2、定义命令别名
交互式:
直接通过终端输入账号和密码登录;
使用su -l USERNAME 或 su -USERNAME;
非交互式:
su USERNAME
图形界面下打开的终端
执行脚本
通过编辑配置文件修改的配置生效
1、退出并重新登录;
2、让bash重读此配置文件;
. FILE
source FILE
用户登录时读取配置文件,越先读取越被先覆盖,有越后读取越有可能最终生效
交互登录的用户:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile--> ~/.bashrc --> /etc/bashrc(最终生效的)
非交互登录的用户:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
for:遍历有限的元素列表,
while:
until:
for VAR_NAME in LIST
do
循环体
done
列表:可包含一个或多个元素
循环体:依赖于调用变量来实现其变化
循环可嵌套
退出条件:遍历元素列表结束
生成数值列表:
{start..end}
例如:{1..100}
seq命令引用
eg:seq 10 1到10
seq 1 10 1到10
seq 2 2 10 2 4 6 8 10 每次进阶2
{301..310} 等价于${seq 301 310} `seq 301 310`
练习:创建10个用户,user301, user310
列表:user301,user310
列表:301, 310
for userNo in {301..310}
for userNo in $(seq 301 310); do
useradduser${userNo} // user$userNo
done
练习:创建目录/tmp/dir-当前日期时间;例如/tmp/dir-20140707-155503在此目录中创建10个空文件,分别为file1-file10;
#!/bin/bash
dstDir=/tmp/-$(date +%Y%m%d-%H%M%S)
mkdir $dstDir
for i in {1..10};do
touch $dstDir/file$i
done
练习:写一个脚本
1、创建用户tuser1-tuser9;
2、创建目录/tmp/dir-当前日期时间;
3、在/tmp/dir-当前日期时间 目录中创建9个空文件file101-file109
4、将file101的属主改为tuser1,依次类推,一直将file109的属主改为tuser9;
#!/bin/bash
dstDir=/tmp/-$(date +%Y%m%d-%H%M%S)
mkdir $dstDir
for i in {1..9};do
useradd tsuer$i
touch $dstDir/file10$i
chown tuser$i $dstDir/file10$i
done
练习:写一个脚本
1、脚本可以接受一个以上的文件路径作为参数;
2、显示每个文件所拥的行数;
3、显示本次共对多少个文件执行了行数统计;
!/bin/bash
#
for file in $*; do
lines=`wc -l $file |cut -d‘ ‘ -f1`
echo "$file has$lines lines."
done
echo "$# files."
练习:写一个脚本
显示/etc/passwd文件中位于文件的第偶数行的用户名;并显示共有多少个这样的用户;
#!/bin/bash
#
totalUsers=`wc -l /etc/passwd | cut -d‘ ‘ -f1`
for i in `seq 2 2 $totalUsers`; do
userName=`head -n$i /etc/passwd | tail -1 | cut -d: -f1`
echo $userName>> /tmp/passwd.tmp
echo $userName
done
users=`wc -l /tmp/passwd.tmp | cut -d‘ ‘ -f1`
echo "Totalusers: $users."
生成列表的方式:
1、手动给个列表:
for i in 1 2 3 4 5; for i in{1..5};
2、数值列表:
{start..end}
`seq [start [increment]] end`
3、$*, $@
4、命令生成列表
for ((初始条件;测试条件;修改表达式)); do
循环体
Done
先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式,否则直接跳出循环。
eg:求100以内所有正整数之和:
while的实现:
#!/bin/bash
declare -i counter=1
declare -i sum=0
while [ $counter -le 100 ]; do
let sum+=$counter
let counter++
done
echo $sum
for的实现:变量赋值时都不能加$,比较时可以
#!/bin/bash
#
declare -i sum=0
for ((counter=1;$counter <= 100; counter++)); do
let sum+=$counter
done
echo $sum
练习:求100以内所有偶数之和;
declare -i evensum=0
for ((counter=2; $counter <=100; counter+=2)); do
let evensum+=$counter
done
while格式:
while 测试条件; do
循环体
done
测试条件为真,进入循环;测试条件为假,退出循环;
测试条件一般通过变量来描述,需要在循环体变量地改变变量的值,以确保某一时刻测试条件为假,进而结束循环;
例:求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
例:提示用户输入一个用户名,如果用户存在,就显示用户的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 read 变量名; do
循环体
done < /path/to/somefile
变量名,每循环一次,记忆了文件中一行文本
练习:显示其ID号为偶数的用户的用户名、ID号和SHELL
#!/bin/bash
while read line; do
userID=`echo $line| cut -d: -f3`
if [ $[$userID%2]-eq 0 ];then
echo $line |cut -d: -f1,3,7
fi
done < /etc/passwd
练习:显示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 测试条件; 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 ausername: " 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 ausername again: " userName
done
break:提前退出循环
break [N]: 退出N层循环;N省略时表示退出break语句所在的循环,用于条件语句中
continue: 提前结束本轮循环,而直接进入下轮循环
用于条件语句中,仅在某些个特殊场景提前进入;
continue [N]:提前第N层的循环的本轮循环,而直接进入下轮循环
死循环:
#while体
while true; do
循环体
done
#until体
until false; do
循环体
done
例如:写一个脚本,判断给定的用户是否登录了当前系统
(1) 如果登录了,则脚本终止;
(2) 每5秒种,查看一次用户是否登录;
eg1:while循环实现
#!/bin/bash
read -p "Plz enter a username: " username
while true; do
if who | grep"\<$userName\>" &> /dev/null; then
break
fi
echo "nothere."
sleep 5
done
echo "$userName is logged on."
eg1:until循环实现
#!/bin/bash
#
read -p "Plz enter a username: " userName
until who | grep "\<$userName\>" &>/dev/null; do
sleep 5
echo "nothere"
done
echo "here"
如果没有数字,只有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 "inetaddr:" | 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 notfound"
exit 5
fi
if [ $verbose -eq 1 ];then
ifconfig | grep "inetaddr:"
else
ifconfig | grep "inetaddr:" | awk ‘{print $2}‘
fi
fi
if [ $ifflag -eq 1 ];then
if [ $allinterface -eq 1 ];then
echo "command notfound"
exit 5
fi
if [ $verbose -eq 1 ];then
ifconfig $interface | grep"inet addr:"
else
ifconfig $interface | grep"inet addr:" | awk ‘{print $2}‘
fi
fi
变量:弱类型
变量=值
任何无需事先声明,可直接使用
值默认都是字符型
a=abc, b=3
a=3 给a指向的内存空间赋值
赋值:
a=4
增强型赋值:
+=, -=, *=, /=, %=
a=$[$a+1] 相当于 let a+=1
自加:var++, var--, ++var, --var
export PATH=$PATH:/usr/local/apache/bin 字串的增强型赋值
unset 撤消
算术运算:bash会对数字执行隐式的类型转换
let VAR_NAME=Integer_Value
declare -i Var_Name=Integer_Value (-I 指明整型数值)
存储为数值和ASCII是不同的,eg:121 分别为1个3个字节
如何定义整型变量:
letVAR_NAME=INTEGER_VALUE
例如:let a=3
declare -i VAR_NAME=INTEGER_VALUE
例如:declare-i a=3
注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算;bash会执行变量类型的隐式类型转换;
letVAR_NAME=ARITHMATIC_EXPRESSION 完整语句
VAR_NAME=$[ARITHMATIC_EXRESSION]表达式
VAR_NAME=$((EXPRESSION)) 表达式,推荐方式
VAR_NAME=$(expr $num1 + $num2)
注意:表达式$num1,$num2和+号间有空格
命令:expr ARG1 OP ARG2
如果计算结果中存在小数,都会被圆整,即舍去小数部分
算术运算符:+,-,*,/,%:取模,取余数
+=,-=,*=,/=,%=
双目运算符:需要至少两个操作数
totalweight=$[ $totalweight+2 ]
lettotalweight+=2
let totalweight++ 相当于totalweight+=1
练习:计算100以内所有正整数之和
#!/bin/bash
#
declare -i sum=0
for i in {1..100}; do
sum=$[$sum+$i] //或者$sum+=$i
done
echo $sum
练习:分别计算100以内所有偶数之和和奇数之和;
#!/bin/bash
#
declare -i evensum=0
declare -i oddsum=0
for i in `seq 1 2 100`; do
oddsum=$[$oddsum+$i]
done
for j in `seq 2 2 100`; do
evensum=$[$evensum+$j]
done
echo "evensum: $evensum, oddsum: $oddsum."
练习:计算当前系统上所有用户的ID之和;
declare -i idsum=0
for i in `cut -d: -f3 /etc/passwd`; do
let idsum+=$i
done
echo $idsum
练习:计算/etc/rc.d/rc.sysinit、/etc/rc.d/init.d/functions和/etc/issue三个文件的字符数之和
#!/bin/bansh
declare –i bytesCount=0
for file in etc/rc.d/rc.sysinit/etc/rc.d/init.d/functions /etc/issue;do
let bytesCount=$bytesCount+`wc –c $file|cut–d‘ ‘ –f1`
done
echo $ bytesCount
练习:新建10个用户tuser401-tuser410,并求他们的ID之和;
#!/bin/bash
#
declare -i idsum=0
for i in {401..410}; do
useradd tuser$i
userID=`id -u tuser$i`
let idsum+=$userID
done
echo "ID sum: $idsum."
练习:写一个脚本
1、脚本可以接受一个以上的文件路径作为参数;
2、显示每个文件所拥有的行数;
3、显示本次共对多少个文件执行了行数统计;
4、显示所有文件的总行数;
#!/bin/bash
#
declare -i totalLines=0
declare -i noFiles=0
for file in $*; do
curFileLines=`wc-l $file | cut -d‘ ‘ -f1`
echo "$filehas $curFileLines."
let noFiles++
lettotalLines+=$curFileLines
done
echo "Total Files: $noFiles."
echo "Total Lines: $totalLines."
练习:写一个脚本
分别统计/etc/rc.d/rc.sysinit、/etc/rc.d/init.d/functions和/etc/inittab文件中以#开头的行的行数和空白行数;
#!/bin/bash
for file in /etc/rc.d/rc.sysinit/etc/rc.d/init.d/functions etc/inittab;do
echo "Thelines contain # in $file is `grep -E"^#" $file | wc -l`."
echo "Thespace lines in $file is `grep -E "^[[:space:]]*$" $file | wc-l`."
done
练习:写一个脚本
显示当前系统上所有默认shell为bash的用户的用户名、UID及其所有此类用户的UID之和;
#!/bin/bash
#
grep "/bin/bash$" /etc/passwd | cut -d: -f1,3
declare -i sum=0
for userID in `grep "/bin/bash$" /etc/passwd |cut -d: -f3`; do
let sum+=$userID
done
echo "$sum"
练习:写一个脚本,显示当前系统上有附加组的用户的用户名;并统计共有多少个此类用户;
for userName in `cut -d: -f1 /etc/passwd`;do
id $userName |
# egrep ‘[^:]$‘ /etc/group | cut -d: -f4 | sort -u | egrep -o‘[[:alnum:]]*‘ | sort -u
实现某种操作:总是测试前提是否满足
逻辑运算:
布尔运算:真,假
与、或、非、异或
与运算:
真,假:
真 &&真 = 真
真 &&假 = 假
假 &&真 = 假
假 &&假 = 假
或运算:
真,假
真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非运算:
真,假
异或运算:
a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0
命令都有其状态返回值:
成功:0,真
失败:1-255, 假
命令执行成功与否即为条件测试
test EXPR
[ EXPR ] 表达式和中括号中间要有空格
[[ EXPR ]] 表达式和中括号中间要有空格
eg: test $num1 > $num2
echo $?
比较运算:
>, <, >=, <=,==, !=
根据比较时的操作数的类型
整型测试:整数比较
字符测试:字符串比较
文件测试:判断文件的存在性及属性等
注意:比较运算通常只在同一种类型间进行
-gt(greater): 例如 [ $num1 -gt $num2 ]
-lt(less小于):
-ge(大于等于):
-le(小于等于):
-eq(等于):
-ne(不等于):
双目
>: [[ "$str1" > "$str2"]]
<:
>=
<=
==
!=
单目:
-n String: 是否不空,不空则为真,空则为假
-z String: 是否为空,空则为真,不空则假
if 测试条件;then
选择分支
fi
表示条件测试状态返回值为值,则执行选择分支;
eg:
if ! id $username &> /dev/null; then
useradd $username
fi
练习:写一个脚本,接受一个参数,这个参数是用户名;如果此用户存在,则显示其ID号;
if [ $# -lt 1 ];then
echo “Usage: `basename $0` username”
exit 2
fi
if id $1 &> /dev/null;then
userid=`id –u $1`
echo “$1 id is $userid”
else
echo “No this user:$1. ”
fi
写脚本的时候有两个易犯错的地方:
1.if [ $# -lt 1 ] if与[ $#与-lt中间都必须带空格
2.id $1 &> /dev/null;这样的只是取命令的返回值不是进行算是运算,if条件时不用加[]
if 测试条件; then
选择分支1
else
选择分支2
fi
两个分支仅执行其中之一。
练习:通过命令行传递两个整数参数给脚本,脚本可以返回其大者。
if [ $1 -gt $2 ];then
echo “The max num is $1.”
else
echo “The max num is $2.”
fi
练习:通过命令行传递任意个整数给脚本,脚本可以返回其大者。
Declare –i max=0
for i in $*;do
if [ $max –lt $i ];then
max=$i
fi
done
练习:通过命令行给定一个文件路径,而后判断:如果此文件中存在空白行,则显示其空白行的总数;否则,则显示无空白行;
if grep"^[[:space:]]*$" $1 &> /dev/null; then
echo "$1 has $(grep"^[[:space]]*$" $1 | wc -l) blank lines."
else
echo"No blank lines"
fi
注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用;而如果把命令的执行结果与某个值做比较,则需要引用了。
if [$(grep "^[[:space:]]*$" $1 | wc -l) -lt 1 ]
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
if 测试条件; then
测试条件:在bash中是命令 (test EXPR, [ EXPR ] ) 或由 [[ EXPR ]]
if 命令;
在bash运行至if时,其后的命令会被执行,其状态结果则作为判断标准:
0: 表示真 $?为0
1-255:表示假
如果条件包含比较之意,则必须使用(test EXPR, [ EXPR ] ) 或由 [[ EXPR ]]
自定义shell进程的状态返回值:
exit[n]
回顾:
条件测试:
整型测试:数值间的大小比较
-gt, -lt, -eq, -ne, -ge, -le
字符串测试:字符串大小比较
>,<, ==, !=, =~, -n, -z
文件测试
例如:如果当前主机的主机名为localhost,则将其修改为www.magedu.com
比较时,
if[ `hostname` == ‘localhost‘ ]; then
hostnamewww.magedu.com
fi
进行比较时若变量有可能为空,则进行弱引用[ "$str3" == ‘localhost‘ ]
例如:如果当前主机的主机名为空,则将其修改为用户通过命令行参数传递过来的用户名
hostName=`hostname`//保存下当前主机名
if[ -z "$hostName" ]; then
hostname$1
fi
在多个条件间实现逻辑运算
与:[ condition1 -a condition2 ]
condition1&& condition2
或:[ condition1 -o condition2 ]
condition1|| condition2
非:[ -not condition ]
!condition
例如:如果当前主机的主机名为空,或者为"localhost",则将其修改为www.magedu.com
#!/bin/bash
#
hostName=`hostname`
if [-z "$hostName" -o "$hostName" == ‘localhost‘ ]; then
hostname www.magedu.com
例如:如果某用户存在,且answer变量的值为“yes",则显示用户的ID号;否则,说用户选择了退出;
id$userName
retVal=$?
if[ $retval -eq 0 -a "$answer" == ‘yes‘ ]; then
上述方式改为:
ifid $userName &> /dev/null && [ "$answer" ==‘yes‘ ];then
练习:给定一个用户,如果其shell为/bin/bash且其ID号大于等于500,则说这是一个可登录普通用户;否则,则显示其为非登录用户或管理员。
#!/bin/bash
#
if! id $1 &> /dev/null; then
echo "No this user."
exit 3
fi
userShell=$(grep"^$1\>" /etc/passwd | cut -d: -f7)
userID=$(id-u $1)
if[ "$userShell" == ‘/bin/bash‘ -a $userID -ge 500 ]; then
echo "Login user."
else
echo "not login user."
fi
练习:给定一个用户,如果其shell为/bin/bash且其ID号大于等于500,则说这是一个可登录普通用户;否则,则显示其为非登录用户或管理员。
#!/bin/bash
#
if! id $1 &> /dev/null; then
echo "No this user."
exit 3
fi
userShell=$(grep"^$1\>" /etc/passwd | cut -d: -f7)
userID=$(id-u $1)
if[ "$userShell" == ‘/bin/bash‘ -a $userID -ge 500 ]; then
echo "Login user."
else
echo "not login user."
fi
练习:写一个脚本
如果某用户不存在,就添加之;
#!/bin/bash
#
if! id $1 &> /dev/null; then
useradd $1
fi
练习:写一脚本
1、添加10个用户:tuser501-tuser510
如果用户不存在,才添加;如果存在,则显示已经有此用户
2、显示一共添加了多少个用户;
#!/bin/bash
#
declare-i count=0
fori in {501..510}; do
if id tuser$i &> /dev/null; then
echo "tuser$i exists."
else
useradd tuser$i
let count++
fi
done
echo"Total add $count users."
练习:写一脚本
1、添加10个用户:tuser601-tuser610
如果用户不存在,才添加,并以绿色显示添加成功;如果存在,则以红色显示已经有此用户;
2、显示一共添加了多少个用户;
#!/bin/bash
#
declare-i count=0
fori in {501..510}; do
if id tuser$i &> /dev/null; then
echo -e "\033[31mtuser$i\033[0mexists."
else
useradd tuser$i
echo -e "add user\033[32mtuser$i\033[0m successfully."
let count++
fi
done
echo"Total add $count users."
练习:写一个脚本
传递用户名给脚本
1、判断此用户的shell是否为/bin/bash,如果是,则显示此用户为basher
2、否则,则显示此用户为非basher
#!/bin/bash
#
userShell=`grep"^$1\>" /etc/passwd | cut -d: -f7`
if[ "$userShell" == ‘/bin/bash‘ ]; then
echo "basher"
else
echo "not basher"
fi
判断文件的存在性及属性等,判定语句需放在[]中:
-aFILE:存在则为真;否则则为假;
-eFILE: 存在则为真;否则则为假;
-fFILE: 存在并且为普通文件,则为真;否则为假;
-d FILE: 存在并且为目录文件,则为真;否则为假;
-L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
-b: 存在并且为块设备,则为真;否则为假;
-c: 存在并且为字符设备,则为真;否则为假
-S: 存在并且为套接字文件,则为真;否则为假
-p: 存在并且为命名管道,则为真;否则为假
-sFILE: 存在并且为非空文件则为真,否则为假;
-r FILE:文件可读为真,否则为假
-w FILE:文件可写为真,否则为假
-x FILE:文件可执行为真,否则为假
file1 -nt file2: file1的mtime新于file2则为真,否则为假;
file1 -ot file2:file1的mtime旧于file2则为真,否则为假;
例如:如果wget命令对应的可执行文件存在且可执行,则使用它下载http://172.16.0.1/centos6.5.repo至当前目录中;
#!/bin/bash
#
downURL=‘http://172.16.0.1/centos6.5.repo‘
downloader=`which wget`
if [ -x $downloader ]; then
$downloader $downURL
Fi
练习:给定一个文件路径
1、判断此文件是否存在;不存在,则说明文件不存,并直接结束脚本;
2、如果文件是否普通文件,则显示为“regularfile”;
如果文件是目录,则显示为“directory”;
如果文件是链接文件,则显示为“Symbolic file";
否则,则显示为“unknown type.”
#!/bin/bash
#
if [ ! -e $1 ]; then
echo "file notexist."
exit 8
fi
if [ -L $1 ]; then
echo "Symbolicfile"
elif [ -d $1 ]; then
echo"Directory"
elif [ -f $1 ]; then
echo "regularfile."
else
echo"unknown."
Fi
写一个脚本,完成如下任务,其使用形式如下所示:
script.sh {start|stop|restart|status}
其中:
如果参数为空,则显示帮助信息,并退出脚本;
如果参数为start,则创建空文件/var/lock/subsys/script,并显示“starting scriptsuccessfully.”
如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop scriptsuccessfully.”
如果参数为restart,则删除文件/var/locksubsys/script并重新创建,而后显示“Restartingscript successfully.”
如果参数为status,那么:
如果文件/var/lock/subsys/script存在,则显示“Script is running...”,否则,则显示“Script isstopped.”
#!/bin/bash
#
srv=`basename $0`
lockFile="/var/lock/subsys/$srv"
[ $# -lt 1 ] && echo "Usage: $srv{start|stop|restart|status}" && exit 4
[ $UID -ne 0 ] && echo "Only root."&& exit 5
if [ "$1" == ‘start‘ ]; then
if [ -f $lockFile ];then
echo "$srvis running."
exit 7
else
touch $lockFile
[ $? -eq 0 ]&& echo "Starting $srv OK."
fi
elif [ "$1" == ‘stop‘ ]; then
if [ -f $lockFile]; then
rm -f $lockFile
[ $? -eq 0 ]&& echo "Stopping $srv OK."
else
echo "$srvis stopped yes."
exit 6
fi
elif [ "$1" == ‘restart‘ ]; then
if [ -f $lockFile];then
rm -f $lockFile
[ $? -eq 0 ]&& echo "Stopping $srv OK."
else
echo "$srvis stopped yet."
fi
touch $lockFile
[ $? -eq 0 ]&& echo "Starting $srv OK."
elif [ "$1" == ‘status‘ ];then
if [ -f $lockFile];then
echo "$srvis running."
else
echo "$srvis stopped."
fi
else
echo "Usage:$srv {start|stop|restart|status}" && exit 9
fi
字串测试中的模式匹配
[[ "$var" =~PATTERN ]]
例如:让用户给定一个用户名,判断其是否拥有可登录shell;
/bin/sh, /bin/bash, /bin/zsh, /bin/tcsh, /sbin/nologin,/sbin/shutdown
#!/bin/bash
#
read -p "Plz input a username: " userName
userInfo=`grep "^$userName\>" /etc/passwd`
if [[ "$userInfo" =~ /bin/.*sh$ ]]; then
echo "canlogin"
else
echo "cannotlogin"
fi
case语句:有多个测试条件时,case语句会使得语法结构更明晰
case 变量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac
PATTERN:类同于文件名通配机制,但支持使用|表示或者;
a|b: a或者b
*:匹配任意长度的任意字符
?: 匹配任意单个字符
[]: 指定范围内的任意单个字符
例如:用户键入字符后判断其所属的类别
#!/bin/bash
#
read -p "Plz enter a char: " char
case $char in
[0-9])
echo "adigit"
;;
[a-z])
echo "achar"
;;
*)
echo "a specialword"
;;
Esac
写一个脚本,使用格式:
script.sh {start|stop|restart|status}
1) start: 创建/var/lock/subsys/script.sh
2) stop: 删除此文件
3) restart: 先删除文件,再创建文件
4) status: 如文件存在,显示running,否则,显示stopped
#!/bin/bash
#
srv=`basename $0`
lockFile="/var/lock/subsys/$srv"
[ $# -lt 1 ] && echo "Usage: $srv{start|stop|restart|status}" && exit 4
[ $UID -ne 0 ] && echo "Only root."&& exit 5
case $1 in
start)
if [ -f $lockFile ];then
echo "$srvis running."
exit 7
else
touch $lockFile
[ $? -eq 0 ] && echo "Starting $srv OK."
fi
;;
stop)
if [ -f $lockFile]; then
rm -f $lockFile
[ $? -eq 0 ] && echo "Stopping $srv OK."
else
echo "$srv is stopped yes."
exit 6
fi
;;
restart)
if [ -f $lockFile];then
rm -f $lockFile
[ $? -eq 0 ] && echo "Stopping $srv OK."
else
echo "$srv is stopped yet."
fi
touch $lockFile
[ $? -eq 0 ]&& echo "Starting $srv OK."
;;
status)
if [ -f $lockFile];then
echo "$srv is running."
else
echo "$srv is stopped."
fi
;;
*)
echo "Usage:$srv {start|stop|restart|status}" && exit 9
esac
练习:写一个脚本,对/etc/目录及内部的所有文件打包压缩
1、显示一个菜单,让用选择使用的压缩工具:
xz) xz compress tool
gz) gzip compress tool
bz2) bzip2 compress tool
2、根据用户选择的工具,对/etc执行相应的操作并保存至/backups目录,文件形如/backups/etc-日期时间.tar.压缩后缀
#!/bin/bash
#
[ -d /backups ] || mkdir /backups
cat << EOF
xz) xz compress tool
gz) gzip compress tool
bz2) bzip2 compress tool
EOF
read -p "Plz choose an option: " choice
case $choice in
xz)
tar -jcf/backups/etc-`date +%F-%H-%M-%S`.tar.xz /etc/*
;;
gz)
tar -zcf/backups/etc-`date +%F-%H-%M-%S`.tar.gz /etc/*
;;
bz2)
tar -jcf/backups/etc-`date +%F-%H-%M-%S`.tar.bz2 /etc/*
;;
*)
echo "wrongoption."
exit 1
;;
esac
练习:写一个脚本,使用形式如下所示
showifinfo.sh [-i INTERFACE|-a] [-v]
要求:
1、-i或-a不可同时使用,-i用于指定特定网卡接口,-a用于指定所有接口;
显示接口的ip地址
2、使用-v,则表示显示详细信息
显示接口的ip地址、子网掩码、广播地址;
3、默认表示仅使用-a选项;
#!/bin/bash
#
verbose=0
allInterface=0
ifflag=0
interface=0
while [ $# -ge 1 ]; do
case $1 in
-a)
allInterface=1
shift 1
;;
-i)
ifflag=1
interface="$2"
shift 2
;;
-v)
verbose=1
shift
;;
*)
echo "wrong option"
exit 2
;;
esac
done
if [ $allInterface -eq 1 ]; then
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 [ $verbose -eq 1]; then
ifconfig $interface | grep "inet addr:"
else
ifconfig $interface | grep "inet addr:" | awk‘{print $2}‘
fi
fi
标签:windows python 解释器 linux 知识点
原文地址:http://heroleilei0627.blog.51cto.com/4835750/1651084