Linux脚本入门
shell script
P 450
生成随机数
#$RANDOM 会随机生成0到32767之间的数
#一下生成0~30之间的数
declare -i num=$RANDOM*30/36767;echo $num
- 在编写script时经常需要用户输入信息,那么我们需要判断该变量是否赋值了,或者为空串,如何操作?
filename=${fileuser:-"filename"}
#表示 如果变量filename不存在或为空白字符串,则将后面的值赋给filename变量。
#其中 ilename=${fileuser-"filename"} 仅能给不存在的变量赋值
#而加上 : 后则可以给不存在或为空白字符串赋值(类似于c语言中的默认参数,有则不变,无则用默认)
创建最近三天的文件,文件名包含日期
#!/bin/bash
echo -e "该脚本将使用 'touch' 命令创建三个文件"
read -p "请输入文件名称:" filename
#判断文件名是否输入,若未输入则使用默认值
filename=${filename:-"filename"}
date1=$(date --date='2 days ago' +%Y%m%d) #两天前的日期
date2=$(date --date='1 days ago' +%Y%m%d) #一天前的日期
date3=$(date +%Y%m%d) #今天的日期
file1=${filename}${date1}
file2=${filename}${date2}
file3=${filename}${date3}
#创建文件
touch "$file1"
touch "$file2"
touch "$file3"
echo "创建成功,分别为:[$file1,$file2,$file3]"
数值运算
echo -e "You SHOULD input 2 numbers, I will cross them! \n"
read -p "first number: " firstnu
read -p "second number: " secnu
total=$(($firstnu*$secnu))
echo -e "\nThe result of $firstnu x $secnu is ==> $total"
- 这个档案是否存在,若不存在则给予一个『Filename does not exist』的讯息,并中断程序;
- 若这个档案存在,则判断他是个档案或目录,结果输出『Filename is regular file』或
『Filename is directory』 - 判断一下,执行者的身份对这个档案或目录所拥有的权限,并输出权限数据!
#!/bin/bash
#判断文件是否存在
echo "该脚本用于判断文件是否存在!"
read -p "请输入要判断的文件名称:" filename
#判断使用者是否输入了文件名
test -z $filename && echo "您必须输入一个文件名!" && exit 0
#判断文件是否存在
test ! -e $filename && echo "名为 '$filename' 的文件不存在" && exit 0
#判断文件类型
test -f $filename && filetype="是文件"
test -d $filename && filetype="是文件夹"
test -r $filename && perm="$perm 可读"
test -w $filename && perm="$perm 可写"
test -x $filename && perm="$perm 可执行"
#输出
echo "文件 '$filename' 是 $filetype"
echo "权限是:$perm"
判断符号[]
除了我们很喜欢使用的 test 之外,其实,我们还可以利用判断符号『 [ ] 』(就是中括号啦) 来进行数据的判断呢!
如果我想要知道 $HOME 这个变量是否为空的,可以这样做:
[root@www ~]# [ -z "$HOME" ] ; echo $?
注意
使用中括号必须要特别注意,因为中括号用在很多地方,包括通配符与正规表示法等等,所以如果要在
bash 的语法当中使用中括号作为 shell 的判断式时,必须要注意中括号的两端需要有空格符来分隔
喔! 假设我空格键使用『□』符号来表示,那么,在这些地方你都需要有空格键:
[□"$HOME"□==□"$MAIL"□]
↑ ↑ ↑ ↑
- 中括号使用规范
- x 在中括号 [] 内的每个组件都需要有空格键来分隔;
- x 在中括号内的变数,最好都以双引号括号起来;
- x 在中括号内的常数,最好都以单或双引号括号起来。
为什么要这么麻烦啊?直接举例来说,假如我设定了 name="VBird Tsai" ,然后这样判定:
[root@www ~]# name="VBird Tsai"
[root@www ~]# [ $name == "VBird" ]
bash: [: too many arguments
见鬼了!怎么会发生错误啊?bash 还跟我说错误是由于『太多参数 (arguments)』所致! 为什么呢?
因为 $name 如果没有使用双引号刮起来,那么上面的判定式会变成:
[ VBird Tsai == "VBird" ]
上面肯定不对嘛!因为一个判断式仅能有两个数据的比对,上面 VBird 与 Tsai 还有 "VBird" 就有三个
资料! 这不是我们要的!我们要的应该是底下这个样子:
[ "VBird Tsai" == "VBird" ]
例
- 当执行一个程序的时候,这个程序会让用户选择 Y 或 N ,
- 如果用户输入 Y 或 y 时,就显示『 OK, continue 』
- 如果用户输入 n 或 N 时,就显示『 Oh, interrupt !』
- 如果不是 Y/y/N/n 之内的其他字符,就显示『 I don't know what your choice is 』
#!/bin/bash
read -p "请输入(y/n):" yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK,continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh,interupt!" && exit 0
echo "I dot't know what you choice is" && exit 0
脚本参数
我们知道指令可以带有选项与参数,例如 ls -la 可以察看包含隐藏文件的所有属性与权限。那么 shell
script 能不能在脚本档名后面带有参数呢?
script 是怎么达成这个功能的呢?其实 script 针对参数已经有设定好一些变量名称了!对应如下:
/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4
- $# :代表后接的参数『个数』,以上表为例这里显示为『 4 』;
- $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
- $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字符,默认为空格键, 所以本例中代表『 "$1
$2 $3 $4" 』之意。
例
- 程序的文件名为何?
- 共有几个参数?
- 若参数的个数小于 2 则告知使用者参数数量太少
- 全部的参数内容为何?
- 第一个参数为何?
- 第二个参数为何
#!/bin/bash
echo "$0"
echo "$#"
[ "$#" -lt 2 ] && echo "参数太少" && exit 0
echo "$@"
echo "$1"
echo "$2"
条件判断式 (if...then)
如果你只有一个判断式要进行,那么我们可以简单的这样看:
if [ 条件判断式 ]; then
当条件判断式成立时,可以进行的指令工作内容;
fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意!
除了 sh06.sh 那个案例所写的,也就是『将多个条件写入一个中括号内的情况』之外, 我还可以有多
个中括号来隔开喔!而括号与括号之间,则以 && 或 || 来隔开,他们的意义是:
x && 代表 AND ;
x || 代表 or ;
所以,在使用中括号的判断式中, && 及 || 就与指令下达的状态不同了。举例来说, sh06.sh 里面的
判断式可以这样修改:
[ "$yn" == "Y" -o "$yn" == "y" ]
上式可替换为
[ "$yn" == "Y" ] || [ "$yn" == "y" ]
多重、复杂条件判断式
# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况执行
if [ 条件判断式一 ]; then
当条件判断式一成立时,可以进行的指令工作内容;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可以进行的指令工作内容;
fi
如果考虑更复杂的情况,则可以使用这个语法:
# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况执行
if [ 条件判断式一 ]; then
当条件判断式一成立时,可以进行的指令工作内容;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可以进行的指令工作内容;
else
当条件判断式一与二均不成立时,可以进行的指令工作内容;
fi
#!/bin/bash
read -p "请输入(y/n)" yn
if [ "$yn"== "Y" ] || [ "$yn" == "y" ]; then
echo "OK,continue"
elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
echo "On,interrupt!"
else
echo "I dot't know what your choice is"
fi
- 判断 $1 是否为 hello,如果是的话,就显示 "Hello, how are you ?";
- 如果没有加任何参数,就提示使用者必须要使用的参数下达法;
- 而如果加入的参数不是 hello ,就提醒使用者仅能使用 hello 为参数。
#!/bin/bash
if [ "$1" == "hello" ]; then
echo "hello"
elif [ "$1" == "" ]; then
echo "you MUST input param ex> {$0 someword}"
else
echo "the only param is 'hello'> {$0 hello}"
fi
检测 80 ,21,22,25端口是否占用
#!/bin/bash
echo "开始检测 www(80),ftp(21),ssh(22),mail(25) 端口是否占用!"
testing=$(netstat -tuln | grep ":80") #查看80端口是否被占用
if [ "$testing" != "" ]; then
echo "www(80) 端口正在使用"
else
echo "www(80) 端口未被占用"
fi
testing=$(netstat -tuln | grep ":22") #查看80端口是否被占用
if [ "$testing" != "" ]; then
echo "ssh(22) 端口正在使用"
else
echo "ssh(22) 端口未被占用"
fi
testing=$(netstat -tuln | grep ":21") #查看80端口是否被占用
if [ "$testing" != "" ]; then
echo "ftp(21) 端口正在使用"
else
echo "ftp(21) 端口未被占用"
fi
testing=$(netstat -tuln | grep ":25") #查看80端口是否被占用
if [ "$testing" != "" ]; then
echo "mail(25) 端口正在使用"
else
echo "mail(25) 端口未被占用"
fi
case ..... esac
#!/bin/bash
# 判断第一个参数
case $1 in
"start")
echo "正在启动中..."
;;
"stop")
echo "停止中..."
;;
*)
echo "参数错误,请输入 start or stop"
;;
esac
function 函数
#!/bin/bash
function printit(){
echo "你传入的参数是$1,$2" # 这里$1是调用函数传入的参数
}
case $1 in
"one")
printit 1 3 #这里传入的参数是1
;;
"two")
printit 2 3
;;
"three")
printit 3 3
;;
*)
echo "请输入 one | two | three"
;;
esac
test
[root@10-9-69-125 scripts]# sh function.sh one
你传入的参数是1,3
[root@10-9-69-125 scripts]# sh function.sh three
你传入的参数是3,3
[root@10-9-69-125 scripts]# sh function.sh aaa
请输入 one | two | three
循环(loop)
while do done, until do done (不定循环)
- while do done
while [ condition ] <==中括号内的状态就是判断式
do <==do 是循环的开始!
程序段落
done <==done 是循环的结束
说明
当 condition 条件成立时,就进行循环,直到 condition 的条件不成立才停止
- until do done
until [ condition ]
do
程序段落
done
说明
这种方式恰恰与 while 相反,它说的是『当 condition 条件成立时,就终止循环, 否则就持续进行循 环的程序段。』是否刚好相反啊~
示例:
从1累加到100
#!/bin/bash
#从1累加到100
sum=0 #计数总和
i=0 #累计值
while [ "$i" != "100" ]
do
i=$(($i+1)) #i加1
s=$(($s+$i)) #累加
done
echo "1...100总和为:=>$s"
for...do...done (固定循环)
for var in con1 con2 con3 ...
do
程序段
done
以上面的例子来说,这个 $var 的变量内容在循环工作时:
1. 第一次循环时, $var 的内容为 con1 ;
2. 第二次循环时, $var 的内容为 con2 ;
3. 第三次循环时, $var 的内容为 con3 ;
4. ....
示例
1、 获取系统用户名
#!/bin/bash
users=$(cut -d ':' -f1 /etc/passwd) # 获取账号
for username in $users
do
echo "username: $username"
done
2、ping 局域网内192.168.1.1 ~ 192.168.1.100 的网络是否连通
#!/bin/bash
network="192.168.1" #定义前面部分
for sitenu in $(seq 100 130) #seq 为 sequence(连续) 的缩写
do
#判断是否ping通
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
#显示结果
if [ "$result" == 0 ];then
echo "ip ${network}.${sitenu} Ok"
else
echo "ip ${network}.${sitenu} Error"
fi
done
for 的第二种写法
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
示例
计算从1到用户输入值的和
#!/bin/bash
#计算从1到你指定的数的和
read -p "计算从1到您指定的数的和,请输入:" nu
s=0
for ((i=1;i<=$nu;i=i+1))
do
s=$(($s+$i))
done
echo "从1计算到$nu的和为:$s"
shell debug
sh [-nvx] scripts.sh
-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!
范例一:测试 sh16.sh 有无语法的问题?
[root@www ~]# sh -n sh16.sh
# 若语法没有问题,则不会显示任何信息!
范例二:将 sh15.sh 的执行过程全部列出来~
[root@www ~]# sh -x sh15.sh
+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin
+ export PATH
+ for animal in dog cat elephant
+ echo 'There are dogs.... ' There are dogs....
+ for animal in dog cat elephant + echo 'There are cats.... ' There are cats....
+ for animal in dog cat elephant
+ echo 'There are elephants.... '
There are elephants....
合并以.txt
结尾的文件到新文件中
#!/bin/bash
dirs=`ls /home/mgy/data|grep '\.txt$'` # 查找.txt结尾的文件
newfile=`touch mar.txt` # 创建新文件
for file in $dirs # 循环文件列表
do
`cat $file >> mar.txt` # 依次将.txt结尾文件内容写入mar.txt
done