shell+中sum的用法_shell高级用法

1.if语句

1.1.回顾

在运行脚本前,我们一般先对脚本的语法进行检查,如果脚本有bug,我们再调试脚本;

(1)语法检查:bash -n 脚本路径

(2)脚本调试:bash -x 脚本路径

1.2.过程式编程语言的执行流程

顺序执行

选择执行

循环执行

选择执行

1.2.1.&&,||

command1 && command2:如果command1正确,也执行command2;如果command1不正确,不执行command2

command1 || command2:如果command1正确,不执行command2;如果command1不正确,执行command2

1.2.2.if语句

if单分支语句;

if多分支语句

if嵌套语句

(1)if 多分支语句格式(注意:多个分支只会执行一个,执行首先为真的分支)

if [ 条件1 ];then

条件1为真执行这里的代码

elif [ 条件2 ];then

条件2为真执行这里的代码

elif [ 条件3 ];then

条件3为真执行这里的代码

......

elif [ 条件n ];then

条件n为真执行这里的代码

else

如果所有的条件都不满足时,执行这里的代码

fi

(2)if嵌套语句格式

if [ 条件 ];then

if [ 条件 ];then

执行这里的代码

fi

fi

if [ 条件 ];then

if [ 条件 ];then

执行这里的代码

fi

else

if [ 条件 ];then

执行这里的代码

fi

fi

1.3.示例

1.通过脚本参数传递一个文件路径给脚本,判断此文件的类型;

#!/bin/bash

#

if [ $# -lt 1 ];then

echo "A argument is needed."

exit 1

fi

if ! [ -e $1 ];then

echo "No such file or directory."

exit 2

fi

if [ -f $1 ];then

echo "Common file"

elif [ -d $1 ];then

echo "Directory"

elif [ -L $1 ];then

echo "Symbolic link"

elif [ -b $1 ];then

echo "block special file"

elif [ -c $1 ];then

echo "character special file"

elif [ -S $1 ];then

echo "Socket file"

else

echo "Unknow"

fi

2.写一个脚本

(1)传递一个参数给脚本,此参数为用户名 ;

(2)根据其ID号来判断用户类型:0:管理员 ,1-499:系统用户,500+:为登入用户, 输出用户是那种类型的用户;

#!/bin/bash

#(1)传递一个参数给脚本,此参数为用户名

# (2)根据其ID号来判断用户类型:0:管理员 ,1-999:系统用户,1000+:为登入用户

if [ $# -lt 1 ]; then

echo "A argument is needed."

exit 1

fi

# 如何输入的用户名存在

# 注意通过命令来判断成功与否不能加[]

if id -u $1 &>/dev/null;then

userid=$(id -u $1)

if [ $userid -eq 0 ];then

echo "Administrator"

elif [ $userid -gt 1 -a $userid -lt 499 ];then

echo " System user"

elif [ $userid -ge 500 ];then

echo "Login user"

fi

else

echo "NO such user."

fi

3.写一个脚本

(1)列出如下菜单给用户

disk) show disks info

mem)show memory info

cpu)show cpu info

*)quit

(2)提示用户给出自己的选择,而后显示对应其选择的相应系统信息

#!/bin/bash

cat << EOF

disk) show disks info

mem)show memory info

cpu)show cpu info

*)quit

EOF

read -p "Please input your option:" option

# 如果用户输入的是大写,直接将大写转变为小写

option=$(echo $option | tr [A-Z] [a-z])

if [ $option == "disk" ]; then

fdisk -l

elif [ $option == "mem" ]; then

free -m

elif [ $option == "cpu" ]; then

lscpu

elif [ $option == "*" ]; then

exit 1

else

echo "Wrong option"

fi

2.循环语句

2.1.bash的循环分类:

for循环

while循环

until循环

2.1.1.for 循环

1.两种格式

第一种格式:遍历列表

第二种格式:控制变量

(1)遍历列表

for 变量 in 列表; do

循环体

done

进入条件:只要列表中有元素,即可进入循环

退出循环:列表中的元素遍历完成

列表生成的方式

1)直接取出

例如: user1 user2 user3

2)整数列表

例如 {1..100}

例如 `seq 1 2 100` 注意:中间的2表示步长

3)返回列表的命令

`ls /var/log/`

4)glob

例如: /var/log/*

5)变量引用,如:@* ,

示例

示例1:

#!/bin/bash

for username in user1 user2 user3;do

if id $username &>/dev/null;then

echo "$username is already exists."

else

useradd $username

echo "Add &username success"

done

示例:2:求100内所有正整数之和;

#!/bin/bash

#

declare -i sum=0

for i in {1..100}; do

sum=$[ $sum+$i ]

done

echo "$sum"

示例3:列出/var/log/目录下所有文件的类型;

#!/bin/bash

#

for option in /var/log/*; do

if [ -f $option ];then

echo "$option is Common file"

elif [ -d $option ];then

echo "$option is Directory"

elif [ -L $option ];then

echo "$option is Symbolic link"

elif [ -b $option ];then

echo "$option is block special file"

elif [ -c $option ];then

echo "$option is character special file"

elif [ -S $option ];then

echo "$option is Socket file"

else

echo "Unknow"

fi

done

练习

练习1:分别求100以内所有偶数之和,奇数之和;

#!/bin/bash

#

declare -i oven=0

declare -i odd=0

for i in {1..100}; do

count=$[ $i % 2 ]

if [[ $count == 0 ]]; then

oven=$[ $oven + $i ]

else

odd=$[ $odd + $i ]

fi

done

echo "oven is $oven"

echo "odd is $odd"

练习2:计算当前用户的id之和;

#!/bin/bash

#

declare -i idcount=0

userRow=$(wc -l /etc/passwd|cut -d" " -f1)

# 这里不能使用{},作为列表,用seq:for i in `seq 1 $userRow`; do

for i in $(seq 1 $userRow); do

userName=$(cut -d: -f1 /etc/passwd|sed -n "$i"p)

idcount=$[ $idcount + $(id -u $userName) ]

done

echo "$idcount"

练习3:通过脚本参数传递一个目录,计算所有的文本文件的行数之和,并说明文件的总数;

#/bin/bash

#

if [[ $# < 1 ]];then

echo "A argument is needed."

exit 1

fi

declare -i fileCounts=0

declare -i rowsCounts=0

# 文件数

fileCounts=$( find $1 -type f | wc -l )

for i in `seq 1 $fileCounts`; do

#这里的egrep其实可以不要,也可以取出行数

rowCount=$(find $1 -type f -exec wc -l {} \; | cut -d" " -f1 | sed -n "$i"p)

rowsCounts=$[ $rowsCounts + $rowCount ]

done

echo "fileCounts is $fileCounts , rowsCounts is $rowsCounts"

(2)控制变量

for((i=1;i<10;i++));do

进入循环代码

done

2.1.2.while 循环

格式

while CONDITION ; do

循环体

循环控制变量的修正表达式

done

进入条件:CONDITION测试为“真”

退出条件:CONDITION测试为“假”

示例

示例1:求100以内所有正整数之和;

#!/bin/bash

#

declare -i sum=0

declare -i i=1

while [ $i -le 100 ]; do

sum=$[ $sum+$i ]

let i++

done

echo "sum is $sum"

2.1.3.until循环

格式

until CONDITION ; do

循环体

循环控制变量

done

进入条件:CONDITION测试为“假”

退出条件:CONDITION测试为“真”

示例

示例1:求100以内所有正整数之和

#!/bin/bash

#

declare -i sum=0

declare -i i=1

until [ $i -gt 100 ];do

sum=$[ $sum+$i ]

let i++

done

echo "sum to $sum"

练习

练习1:分别使用while for until实现,求100以内所有的偶数之和,100以内奇数之和;

#!/bin/bash

#

declare -i oven=0

declare -i odd=0

#for循环

for i in {1..100}; do

count=$[ $i%2 ]

if [ $count -eq 0 ]; then

oven=$[ $oven+$i ]

else

odd=$[ $odd+$i ]

fi

done

echo "odd is $odd"

echo "oven is $oven"

oven=0

odd=0

i=1

#while循环

while [ $i -le 100 ]; do

count=$[ $i%2 ]

if [ $count -eq 0 ]; then

let oven+=$i

else

let odd+=$i

fi

let i++

done

echo "odd is $odd"

echo "oven is $oven"

oven=0

odd=0

i=1

#until循环

until [ $i -gt 100 ]; do

count=$[ $i%2 ]

if [ $count -eq 0 ]; then

let oven+=$i

else

let odd+=$i

fi

let i++

done

echo "odd is $odd"

echo "oven is $oven"

练习2:创建9个用户,user101-user109;密码同用户名, 如果这些用户存在就删除,不存在就创建;

#!/bin/bash

for i in `seq 1 10`;do

if id user10"$i" &> /dev/null;then

userdel -r user10"$i"

else

useradd user10"$i"

echo "user10$i" | passwd --stdin user10"$i" &> /dev/null

echo "create user user10$i"

fi

done

练习3:打印九九乘法表

#!/bin/bash

# 注意:这里的echo 的 -n选项表示不换行

for((i=1;i<9;i++));do

for((j=1;j<=$i;j++));do

echo -n "$j X $i = $[ $j*$i ] "

done

echo

done

练习4:打印逆序的九九乘法表

#!/bin/bash

#

declare -i k=9

while [ $k -ge 1 ]; do

for i in `seq 1 $k| sort -n -r`;do

echo -n "$i X $k = $[ $i*$k ] "

done

echo ""

let k--

done

3.循环控制语句

continue:跳出本次循环,进入下一轮循环;

break:跳出整个循环;

sleep:程序睡眠一个时间段;

死循环:条件为true,永远为死循环

3.1.continue语句

格式

while [ 条件1 ]; do

满足条件执行这里的代码

if [ 条件2 ]; then

# 跳出当前循环进入下一轮循环

continue

fi

满足条件执行这里的代码

done

示例:

求100以内所有的偶数之和;

#/bin/bash

#

declare -i evensum=0

for i in {1..100}; do

if [ $[ $i%2 ] -eq 1 ];then

continue

fi

let evensum+=$i

done

echo "evensum is $evensum"

#/bin/bash

#

declare -i evensum=0

declare -i i=0

while [ $i -lt 100 ]; do

let i++

if [ $[ $i%2 ] -eq 1 ];then

continue

fi

let evensum+=$i

done

echo "evensum is $evensum"

3.2.break :直接跳出整个循环

格式

while [条件1]; do

执行这里的代码

if [条件2]; then

break

fi

执行这里的代码

done

死循环:如何创建死循环

while true;do

循环体

done

退出方式:某个测试条件满足的时候,让循环体执行break命令就是

示例:

计算100以内奇数之和

#/bin/bash

# description

# author

declare -i oddsum=0

declare -i i=1

while true; do

let oddsum=$oddsum+$i

let i=$i+2

if [ $i -gt 100 ];then

break

fi

done

echo "oddsum is $oddsum"

3.3.sleep命令

示例:

每隔3秒钟到系统上获取已经登入的用户的信息,其中,如果sb用户登入了系统,则给QQ发送邮件,主题为“sb user is login”,并退出;

#/bin/bash

#

while true; do

if who | grep "^logstash\>" &> /dev/null; then

break;

fi

sleep 3

done

echo "$(date +"%F %T")logstash logged on" >> /tmp/users.log

#/bin/bash

#

until who | grep "^logstash\>" &> /dev/null; do

sleep 3

done

echo "$(date +"%F %T")logstash logged on" >> /tmp/users.log

4.while和for循环的特殊用法

4.1.while循环的特殊用法(遍历文件的行)

格式

while read VARIABLE;do

循环体

done < /PATH/TO/FILE

意思是:依次读取/PATH/TO/FILE文件中的每一行,且将其赋值给VARIABLE变量

示例:

找出ID号为偶数的用户,显示其用户名、ID、及默认的shell;

#/bin/bash

#

while read line; do

ID=$(echo $line|cut -d: -f3)

if [ $[ $ID%2 ] -eq 0 ];then

username=$(echo $line | cut -d: -f1)

shell=$(echo $line | cut -d: -f7)

echo "username is $username, ID is $ID , shell is $shell"

fi

done < /etc/passwd

4.2.for循环的特殊用法

格式

for((控制变量初始化;条件判断表达式;控制变量修正语句));do

循环体

done

示例:

示例1:1到100的和

#/bin/bash

#

declare -i sum=0

for((i=1;i<=100;i++));do

let sum+=$i

done

echo "sum is $sum"

示例2:打印九九乘法表

#/bin/bash

#

for((i=1;i<=9;i++));do

for((j=1;j<=i;j++));do

echo -ne "${j}X${i}=$[ ${j}*${i} ]\t"

done

echo

done

5. case语句

语法格式:

case $VARAIBLE in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

分支n

;;

esac

case支持glob风格的通配符:

*:任意长度的任意字符;

?:任意单个字符;

[]:任意单个字符;

a|b:a或b;

注意:

(1)每一个分支的两个分号一定不能少,如果没有两个分号,那么每一个case 的分支都会执行

(2)虽然这里的PAT可以只用模式匹配,但是只是支持glob模式的匹配,有:* ? [ ] [^ ] a|b 这几种方式

示例:显示一个菜单给用户

cpu)display cpu information

mem)display memory information

disk)display disk information

quit)quit

(1)提示用户给出自己的选择

(2)正确的选择给出相应的信息,否则,提示用户,让用户重新选择正确的选项,直到用户选择正确为止

#!/bin/bash

#

cat << EOF

cpu)display cpu information

mem)display memory information

disk)display disk information

quit)quit

=============================

EOF

read -p "Enter your option:" option

# 这里的while,通过read命令循环输入option,使得循环可以继续进行

while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ]; do

echo "please input cpu , mem , disk , quit "

read -p "Enter your option:" option

done

if [ "$option" == "cpu" ];then

lscpu

elif [ "$option" == "mem" ];then

free -m

elif [ "$option" == "disk" ];then

fdisk -l /dev/sd[a-z]

elif [ "$option" == "quit" ];then

echo "quit"

exit 0

fi

将上述题目if else示例改写为case的判断,会使得代码的可读性增强

#/bin/bash

#

cat << EOF

cpu)display cpu information

mem)display memory information

disk)display disk information

quit)quit

=============================

EOF

read -p "Enter your option:" option

# 这里的while,通过read命令循环输入option,使得循环可以继续进行

while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ]; do

echo "please input cpu , mem , disk , quit "

read -p "Enter your option:" option

done

case $option in

cpu)

lscpu ;;

mem)

free -m ;;

disk)

fdisk -l /dev/sd[a-z] ;;

*)

echo "quit"

exit 0 ;;

esac

示例:写一个服务框架脚本;

$lockfile,值/var/lock/subsys/SCRIPT_NAME

(1)此脚本可接受start,stop,restart,status四个参数之一;

(2)如果参数非此四者,则提示使用帮助后退出;

(3)start,则创建lockfile,并显示启动;stop则删除lockfile,并显示停止;restart,则先删除此文件再创建此文件,而后显示重启完成;status,如果lockfile存在,则显示running,否则,则显示为stopped.

#!/bin/bash

#

# chkconfig: - 50 50

# description: test service script

prog=$(basename $0)

lockfile=/var/lock/subsys/$prog

case $1 in

start)

if [ -f $lockfile ]; then

echo "$prog is running yet."

else

touch $lockfile

[ $? -eq 0 ] && echo "start $prog finshed."

fi

;;

stop)

if [ -f $lockfile ]; then

rm -f $lockfile

[ $? -eq 0 ] && echo "start $prog finshed."

else

echo "$prog is running yet."

fi

;;

restart)

if [ -f $lockfile ]; then

rm -f $lockfile

touch $lockfile

echo "start $prog finshed."

else

touch -f $lockfile

echo "start $prog finshed."

fi

;;

status)

if [ -f $lockfile ]; then

echo "$prog is running yet."

else

echo "$prog is stopped."

fi

;;

*)

echo "Usage:$prog {start|stop|restart|status}"

esac

6.函数:代码重用

模块化编程

结构化编程

注意:定义函数的代码段不会自动执行,在调用时执行,所谓调用函数,在代码中给定函数名称即可,函数名出现的任何位置,在代码执行时候,都会自动替换为函数代码;

6.1.语法格式:

语法一:

function f_name{

函数体

}

语法二:

f_name(){

函数体

}

函数的生命周期:每次被调用时,被创建,返回时,终止

其状态返回结果为函数体中运行的最后一条命令的状态结果

自定义状态返回值,需要使用:return

return [0-255]

0: 成功

1-255:失败

6.2.示例:

示例1:给定一个用户名,取得用户名的ID号,和默认的shell

#!/bin/bash

#

userinfo() {

if id "$username" &> /dev/null; then

grep "^$username\>" /etc/passwd | cut -d: -f3,7

else

echo "No such user."

fi

}

username=$1

userinfo

username=$2

userinfo

练习:

写一个服务框架脚本名为create_file,接受start 、stop、 restart、 status 四个参数之一(这次用函数实现)

(1):如果参数非此四者,则提示使用帮助后退出

(2):如果传递start参数,则在/var/log目录下创建一个与脚本名相同的文件,并显示启动。

(3):如果传递stop参数,就在/var/log目录下删除一个与脚本名相同的文件 ,并显示停止。

(4):如果传递restart参数,就先删除再创建此文件,而后显示重启完成。

(5):如果传递status参数, 如果文件存在,则显示running, 否则显示为stopped

#!/bin/bash

#

# chkconfig: - 50 50

# description: test service script

#

prog=$(basename $0)

FILE=/var/log/$prog

start() {

if [ -f $FILE ]; then

echo "$prog is running yet."

else

touch $FILE

[ $? -eq 0 ] && echo "start $prog OK."

fi

}

stop() {

if [ -f $FILE ]; then

rm -f $FILE

[ $? -eq 0 ] && echo "stop $prog finished."

else

echo "$prog is not running."

fi

}

status() {

if [ -f $FILE ]; then

echo "$prog is running"

else

echo "$prog is stopped."

fi

}

usage() {

echo "Usage: $prog {start|stop|restart|status}"

}

case $1 in

start)

start ;;

stop)

stop ;;

restart)

stop

start ;;

status)

status ;;

*)

usage

exit 1 ;;

esac

6.3.函数的返回值分为两类

1.函数的执行结果返回值

(1):使用echo或printf命令进行输出

(2):函数体中调用的命令的执行结果

2.函数的退出状态码

(1):默认取决于函数体中执行的最后一条命令的退出状态码

(2):自定义:return (相当于脚本中的exit)

6.4.函数可以接受参数

在调用函数的时候可以给函数传递参数;

在函数体中,可以使用$1, $2...引用传递给函数的参数,还可以使用$* 或$@调用所有的参数,$#表示传递的参数的个数;

在调用函数时候,在函数名后面以空白字符分割给定参数列表即可,例如:functionName arg1 arg2 arg3 arg4...

示例:

示例1:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数。这里有一个注意点,就是如果直接return $? ,在函数外面是不能拿到值的。

#!/bin/bash

#

# 5: user exists

addusers() {

if id $1 &> /dev/null; then

return 5

else

useradd $1

retval=$?

return $retval

fi

}

for i in {1..10}; do

addusers ${1}${i}

# 在这里需要注意的是:每次函数的放回结果虽然可以使用$?来引用,但是在后面多次用到的时候,一定要将其使用一个变量保存起来,这里使用一个retval=$?保存了函数执行之后的状态码,以后为了规范起见,所有的函数返回的状态码都使用一个变量将其保存起来,如: variable=$? ,这样就不怕以后引用$?是出现错误。

retval=$?

if [ $retval -eq 0 ]; then

echo "Add user ${1}${i} finished."

elif [ $retval -eq 5 ]; then

echo "user ${1}${i} exists."

else

echo "Unkown Error."

fi

done

练习:

练习1:写一个脚本:要求

(1)使用函数实现ping一个主机来测试主机的在线状态,主机地址通过参数传递给函数

(2)主程序:测试192.168.7.130 - 192.168.7.139 范围内的各个主机的在线状态

(3)如果主机在线,那么打印黄色的Online字符串,如果主机不在线打印红色的Offline字符串

#!/bin/bash

#

if [ $# -lt 2 ];then

echo "请输入两个主机地址作为IP地址的检测范围"

exit 1

fi

START=$1

END=$2

# 检测IP的范围

Ping(){

ping -c1 -w1 192.168.7.13$1 &> /dev/null && echo -e "\E[1;33m 192.168.7.13$1 Online \033[0m" || echo -e "\E[1;31m 192.168.7.13$1 Offline \033[0m"

}

for i in `seq $1 $2`; do

Ping $i

done

练习2:写一个脚本 :要求

打印NN乘法表,使用函数实现, 例如:给脚本传递了一个11,那么就是打印11 X 11 的乘法表

#!/bin/bash

# 注意:这里的echo 的 -n选项表示不换行

for((i=1;i<=$1;i++));do

for((j=1;j<=$i;j++));do

echo -n "$j X $i = $[ $j*$i ] "

done

echo

done

7.变量作用域

局部变量:作用域是函数的生命周期,在函数结束时被自动销毁。定义局部变量的方法:local 变量=值

本地变量:作用域是运行脚本的shell进程的生命周期,因此,其作用域范围是当前的shell脚本程序文件

示例

#!/bin/bash

#

name=tom

# 记得以后为了避免函数中的变量与本地变量同名,如果同名,会使得具备变量修改本地变量的值,使得本地变量的指针直接指向函数中变量的存储空间。为了避免同名产生的错误,以后在函数中定义的变量都使用局部变量,在变量名前面加上一个local关键字

setname() {

local name=jerry

echo "Function: $name"

}

setname

echo "Shell: $name"

8.递归

bash shell中和其他编程语言一样可以使用递归。那什么是递归:程序调用自身技巧称为递归( recursion)

示例:

写一个脚本,给脚本传递一个数值,脚本输出这个数值的阶层。例如:5!= 120

#!/bin/bash

func() {

if [ $1 -eq 0 -o $1 -eq 1 ]; then

echo 1

else

echo $[$1*$(func $[$1-1])]

fi

}

func $1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值