Shell脚本编程与sed,awk工具的使用--9月15日课程作业

一、shell程序的运行原理

1.脚本

脚本或程序源文件是一种文本文件,将文本文件转换成机器指令有两种转换方式:

  • 编译执行:预处理-->编译-->汇编-->链接;事先完成,结果:二进制程序文件

    例如:C, C++

  • 解释执行:由解释器全程参与运行过程,每次读取一行,运行一行;

    例如:  Python:程序控制结构,调用编程库完成程序编写;

    库文件:功能模块,在编程中可调用;

Bash:调用机器上命令程序文件进行程序编写;

外部命令:各应用程序提供;

2.原理

当shell运行一个程序时,会要求内核启动一个新的进程(process),以便在该进程里执行所指定的程序。内核知道如何为"编译型"程序做这件事。shell脚本并非编译型程序;当shell要求内核执行它时,内核将无法做这件事,并回应"not executable format file"错误信息。shell收到此错误信息时,就会认为"这不是编译型程序,那么一定是shell脚本","退回到shell"接着会启动一个新的/bin/sh 副本来执行该程序。当系统只有一个shell时,"退回到/bin/sh"的机制非常方便。但现行的系统都会拥有好几个shell,因此需要通过一种方式,告知内核应该以哪个shell来执行所指定的shell脚本。事实上,这么做有助于执行机制的通用化,让用户得以直接引用任何的程序语言解释器,而非只是一个命令shell。方法是,通过脚本文件特殊的第一行来设置:在第一行的开头处使用 #!这两个字符

二、shell编程中基础知识点

1.程序组织方式:

过程式编程:以指令为中心,设计算法,数据服务于算法;

对象式编程:以数据为中心,设计数据结构(类),程序服务于数据结构;

2.bash过程式编程的控制逻辑

顺序执行:逐个执行

选择执行:只执行其中一个分支

循环执行:一段代码要执行0,1或多遍

3.编程元素:

变量、流程、函数

3.1变量:可变化的量,命名的内存空间

本地变量:作用范围是当前shell进程;

环境变量:作用范围是当前shell进程及其子进程;

局部变量:作用范围是某个函数执行过程;

位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;

特殊变量:$?, $*, [email protected], $#, $$

3.2变量类型:数值,字符;

  • 数值:整数,浮点数
  • 字符: ASCII

    例如:

    120:

    字符:1, 2, 0

    数值:120 -->

3.3变量类型的作用:定义存储空间、参与的运算类型、存储格式

3.4语言对变量类型的支持力度:

强类型:变量类型严格区分

弱类型:变量类型不严格区分;因此有默认存储机制,对于bash而言,默认为为字符

3.5 bash的变量使用特点:弱类型、无需事先声明;

4.本地变量

4.1定义: name=value

name: 变量名        =:赋值符号            value:值

4.2变量名命名要求:只能包含数字、字母和下划线;且不能以数字开头;尽量不使用大写字母,可能与环境变量冲突

4.3引用变量:${name}, $name

弱引用: "", 其内部的变量引用会被替换为变量值;

强引用:‘‘,其变量的变量引用会保持原有字符;

命令引用:`COMMAND`,或者$(COMMAND),引用命令的执行结果;

示例:

[[email protected] ~]# animal=pig
[[email protected] ~]# echo $animal
pig
[[email protected] ~]# echo "there are some $animals;"      
there are some ;不加{},bash以为animals是变量,但是animals没有定义,所以无法输出
[[email protected] ~]# echo "there are some ${animal}s;"
there are some pigs;
[[email protected] ~]# echo ‘there are some ${animal}s;‘   单引号强应用
there are some ${animal}s;

4.4本地变量声明为整型:

declare -i name[=value]

let name=value

4.5查看所有变量:set

[[email protected] ~]# set | grep "^\banimal\b"
animal=dog

4.7本地变量的生命周期:从创建开始,到销毁结束

销毁:

  • 自动销毁:shell进程终止;
  • 手动销毁:unset name

5.环境变量

5.1 定义

环境变量可以理解为被"导出"的本地变量

export name[=value]

declare -x name[=value]

示例:

[[email protected] ~]#export animal=‘dog‘
[[email protected] ~]#echo 
[[email protected] ~]#echo $animal
dog
[[email protected] ~]#bash
[[email protected] ~]#echo $animal
dog

5.2查看所有环境变量:env, printenv,export

5.3销毁: unset name

6.脚本

6.1脚本是文本文件,不可直接运行。

6.2运行脚本:事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,而后由bash进程负责解析并运行此逻辑;

6.3运行脚本有2种方法:

(1) 作为解释器参数  bash/PATH/TO/SCRIPT_FILE

/bin/bash  sh01.sh

(2)脚本作为可执行程序,给脚本文件一个执行权限,    ./PATH/TO/SCRIPT_FILE

chmod +x ./sh01.sh      # 使脚本具有执行权限

./sh01.sh               # 执行脚本

6.4 shebang(或者sha-bang):是一个由井号和叹号构成的字符串行(#!),其出现在文本文件的第一行的最前两个字符。 在文件中存在sha-bang的情况下,类Unix操作系统的程序载入器会分析sha-bang后的内容,将这些内容作为解释器指令,并调用该指令,并将载有sha-bang的文件路径作为该解释器的参数[1]。#! (magic number)为了让Linux内核识别这是什么格式的文件。

6.5 bash的常用选项:

-n: 检查脚本中的语法错误;

-x:调试执行脚本,就是单步执行;

示例:作为解释器参数

[[email protected] bashtest]# vim sh01.sh
[[email protected] bashtest]# bash -n sh01.sh
[[email protected] bashtest]# bash -x sh01.sh
+ useradd shtest1
+ echo shtest1
+ passwd --stdin shtest1
Changing password for user shtest1.
passwd: all authentication tokens updated successfully.
[[email protected] bashtest]# cat sh01.sh
#!/bin/bash
useradd shtest1
echo shtest1 | passwd --stdin shtest1

示例:作为可执行文件

[[email protected] bashtest]# vim sh02.sh
[[email protected] bashtest]# chmod +x sh02.sh
[[email protected] bashtest]# ll
total 8
-rw-r--r--. 1 root root 67 Sep 25 17:50 sh01.sh
-rwxr-xr-x. 1 root root 66 Sep 25 17:54 sh02.sh
[[email protected] bashtest]# ./sh02.sh
Changing password for user shtest2.
passwd: all authentication tokens updated successfully.
[[email protected] bashtest]# cat ./sh02.sh
#!/bin/bash
useradd shtest2
echo shtest1 | passwd --stdin shtest2

6.7命令状态结果:

bash进程用于追踪执行的命令成功与否的状态:

0: 成功           1-255:失败

6.8特殊变量: $?:上一条命令的执行状态结果;属于布尔型

6.9自定义脚本的状态结果: exit [n]

注意:脚本中任何位置执行了exit命令即会终止当前shell进程;

三、条件测试

1.条件测试作用:界定程序执行环境;

2.测试机制:

(1)根据运行的命令的状态结果;

(2) 测试表达式

test EXPRESSION

[EXPRESSION ]

[[EXPRESSION ]]

3.shel下测试的命令: test, [ 和关键字 [[ ]], 可以针对 数字、字符串、文件进行测试。

"["是一个可执行程序,路径是"/bin/[", [ 是一个命令,它是内置命令test的简写形式,只不过它要求最后一个参数必须是 ]。在使用[ ] 进行判定的时候有一个事项要注意的是,在括号两边以及符号两边均要有空格。

3.1 bash [ ] 单双括号

基本要素:

[ ] 两个符号左右都要有空格分隔

内部操作符与操作变量之间要有空格:如  [  “a”  =  “b”  ]

字符串比较中,> < 需要写成\> \< 进行转义

[ ] 中字符串或者${}变量要使用"" 双引号扩住,避免值未定义引用而出错

[ ] 中可以使用 –a –o进行逻辑运算

[ ] bash 内置命令:[ is a shell builtin

-a 逻辑与(and缩写),操作符两边均为真,结果为真,否则为假

-o 逻辑或(or缩写),操作符两边有一边为真,结果为真

3.2 bash  [[  ]] 双方括号

基本要素:

[[ ]] 两个符号左右都要有空格分隔

内部操作符与操作变量之间要有空格:如  [[  “a” =  “b”  ]]

字符串比较中,可以直接使用 > < 无需转义

[[ ]] 中字符串或者${}变量要使用"" 双引号扩住,否则会进行模式和元字符匹配

[[] ] 内部可以使用&&  || 进行逻辑运算

[[ ]] bash keyword[[ isa shell keyword

4,整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;

$A -gt $B:是否大于;是则为“真”,否则为“假”;

$A -ge $B: 是否大于等于;

$A -lt $B:是否小于(less than);

$A -le $B: 是否小于等于;

$A -eq $B: 是否等于;

$A -ne $B:是否不等于;

5. 字符串测试:ASCII数值越大,字符比较时其值越大;

"$A" >"$B":是否大于;

"$A" <"$B":是否小于;

"$A" =="$B":是否等于;

"$A" !="$B":是否不等于;

注意:应该使用[[ EXPRESSION ]]

例如:

[[email protected]]# [[ a > c ]]
[[email protected]]# echo $?
1
[[email protected]]# [[ a < c ]]
[[email protected]]# echo $?
0
[[email protected]]# [[ a == c ]]
[[email protected]]# echo $?
1
[[email protected]]# [[ a != c ]]
[[email protected]]# echo $?
0

-z "$A":是否为空;空则为“真”,否则为“假”

-n "$A":是否不空;不空则“真”,空则为“假”

例如:

[[email protected]]# name=mage
[[email protected]]# [[ -z $name ]]
[[email protected]]# echo $?
1
[[email protected]]# [[ -n $name ]]
[[email protected]]# echo $?
0

6.文件测试:测试文件的存在性以及属性;

-e $file: 是否存在;存在则为“真”,否则为“假”;

-a $file: 同上;

-f $file:文件是否存在且为普通文件;

-d $file:文件是否存在且为目录;

-h $file:是否存在且为符号链接文件;

-L $file: 同上

-b $file:是否存在且为块设备文件;

-c $file:是否存在且为字符设备文件;

-S $file:是否存在且为套接字文件;

-p $file: 是否存在且为管道文件;

-r $file: 当前用户对文件是否拥有读权限;

-w $file:当前用户对文件是否拥有写权限;

-x $file:当前用户对文件是否拥有执行权限;

-u $file:文件是否拥有SUID权限;

-g $file:文件是否拥有SGID权限;

-k $file:文件是否拥有sticky权限;

-O $file: 当前用户是否为指定文件的属主;

-G $file: 当前用户是否为指定文件的属组;

7.双目操作符:

$file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的;

$file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的;

$file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;

例如:

[[email protected]]# cd ./bashtest/
[[email protected]]# ll
total 8
-rw-r--r--. 1 rootroot 67 Sep 25 17:50 sh01.sh
-rwxr-xr-x. 1 rootroot 66 Sep 25 17:54 sh02.sh
[[email protected]]# file1="/tmp/bashtest/sh01.sh" 
 [[email protected] bashtest]#file2="/tmp/bashtest/sh02.sh" 
[[email protected]]# [ -d "$file1" ]
[[email protected]]# echo $?
1
[[email protected]]# [ -f "$file1" ]
[[email protected]]# echo $?
0
[[email protected]]# [ "$file1" -nt "$file2" ]
[[email protected]]# echo $?
1
[[email protected]]# [ "$file1" -ot "$file2" ]
[[email protected]]# echo $?
0

8.特殊设备:

/dev/null: 空,bit buckets,吞下所有数据,并直接丢弃;

/dev/zero:吐出一堆0;

四、条件判断

1.单分支if语句

if CONDITION; then

if-true-分支

fi

2.双分支if语句

if CONDITION; then

if-true-分支

else

if-false-分支

fi

3.多分支if语句格式:

if CONDITION1; then

if-CONDITION1-true-分支

elif CONDITION2; then

if-CONDITION2-true-分支

else

if-ALL-false-分支

fi

示例:通过脚本参数传递一个文件路径给脚本,判断其类型;

#!/bin/bash
if [ $# -lt 1 ]; then
         echo"Usage: $0 <path>"
exit 1
fi
if [ -f $1 ]; then
   echo "Rgular file."                         
elif [ -d $1 ]; then
   echo "Directory."                          
elif [ -h $1 ]; then
   echo "Symbolic link."                              
elif [ -b $1 ]; then
   echo "Block special."
elif [ -c $1 ]; then
   echo "Charactoer special."
elif [ -S $1 ]; then
   echo "Socket file."
else                               
   echo "file not exist or unknown type."
fi

练习1

写一个脚本如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;

[[email protected] bashtest]# vim test1.sh
#!bin/bash
fname="/tmp/testdir"
if [ -e $fname ]; then
   echo "$fname exists."
   file $fname
else
   mkdir -p $fname
fi
[[email protected] bashtest]# bash -n test1.sh
[[email protected] bashtest]# bash -x test1.sh
+ fname=/tmp/testdir
+ ‘[‘ -e /tmp/testdir ‘]‘
+ mkdir -p /tmp/testdir
[[email protected] bashtest]# echo $?
0

3.脚本参数(位置参数变量):

3.1 # ./script.sh  /etc/fstab  /etc/grub2.cfg

$0                $1              $2

位置参数变量:$1, $2, ……两位数字以后加花括号${10}

例如:传递一个文件路径给脚本,如果文件存在且为普通文件,就显示文件不存在或不是普通文件

[[email protected] bashtest]# vim test2.sh
#!/bin/bash
if [ -f $1 ];then
       wc -l $1
else
       echo "$1 not exists or is not a file."
fi
[[email protected] bashtest]# bash -n test2.sh
[[email protected] bashtest]# chmod +xtest2.sh
[[email protected] bashtest]# ./test2.sh/etc/fstab
11 /etc/fstab
[[email protected] bashtest]# ./test2.sh/etc/grub2.cfg
129 /etc/grub2.cfg
[[email protected] bashtest]# ./test2.sh /etc
/etc not exists or is not a file.

3.2.特殊变量:

$?: 命令的状态结果;

$#: 传递给脚本或函数的参数的个数;

$*和[email protected]: 列出传递给脚本或函数的参数列表;

例如:

[[email protected] bashtest]# cp ./test3.sh./test4.sh
[[email protected] bashtest]# vim ./test4.sh
#!/bin/bash
if [ -f $1 ];then
       lines=$(wc -l $1 | cut -d‘ ‘ -f1)
       echo "$1 has $lines lines."
else
       echo"$1 not exits or is not a file"
fi
echo "Total arguments : $#"
echo "They are $*"
[[email protected] bashtest]# ./test4.sh/etc/fstab /etc/grub2.cfg
/etc/fstab has 11 lines.
Total arguments : 2
They are /etc/fstab /etc/grub2.cfg

例如:

[[email protected] bashtest]# vim ./test4.sh
#!/bin/bash
if [ $# -lt 1 ]; then
       echo "Usage: $0 need a path"
exit 1
fi
if [ -f $1 ];then      
       lines=$(wc -l $1 | cut -d‘ ‘ -f1)
       echo "$1 has $lines lines."
else
       echo"$1 not exits or is not a file"
fi
[[email protected] bashtest]# ./test4.sh
Usage: ./test4.sh need a path
[[email protected] bashtest]# ./test4.sh/etc/fstab
/etc/fstab has 11 lines.

shift[n]:轮替

例如:

[[email protected] bashtest]# vim shif.sh
#!/bin/bash
echo $*
echo $1
shift
echo $1
shift
echo $1
shift
[[email protected] bashtest]# ./shif.sh a b c
a b c
a
b
c

4.与用户交互read命令

4.1作用:Read aline from the standard input and split it into fields.

详情: help read

例如:

[[email protected] bashtest]# read f1 f2
/etc/fstab /etc/grub2.conf
[[email protected] bashtest]# echo $f1
/etc/fstab
[[email protected] bashtest]# echo $f2
/etc/grub2.conf

常用参数:

-p prompt     outputthe string PROMPT without a trailing newline before attempting to read

-ttimeout    time out and return failure ifa complete line of input is

例如:

[[email protected] bashtest]# read -p"What‘s your name ?" -t 10 name
What‘s your name ?lan
[[email protected] bashtest]# echo $name
lan

示例:写一个脚本能够添加用户,并提示输入用户名和密码

[[email protected] bashtest]# vim read.sh
#!/bin/bash
read -p "Please input a username:" -t 30 uname
if [ -z "$uname" ];then
      echo “Time out!”
exit 1
fi
 
if id $uname &> /dev/null;then
       echo "$uname has existd."
else
       useradd $uname
       read -p "Please input password : " -t 30 upasswd
       echo $upasswd | passwd --stdin $uname
       echo "Add User:$uname successfully "
fi

结果:

5. 命令引用

5.1格式:`COMMAND`,$(COMMAND)

5.2引用命令的执行结果示例:

[[email protected] bashtest]# vim test3.sh

#!/bin/bash

if [ -f $1 ];then

lines=$(wc -l $1 | cut -d‘ ‘ -f1)

echo "$1 has $lines lines."

else

echo"$1 not exits or is not a file"

fi

[[email protected] bashtest]# bash -n test3.sh

[[email protected] bashtest]# chmod +xtest3.sh

[[email protected] bashtest]# ./test3.sh/etc/fstab

/etc/fstab has 11 lines.

练习2:

写一个脚本,完成如下功能,判断给定的两个数值,孰大孰小。给定数值的方法:脚本参数,命令交互。

[[email protected] bashtest]# vim big.sh

#!/bin/bash

read -p " Enter 2 integers : " -t30 num1 num2

if [ -z "$num1" -o -z"$num2" ];then

echo "Time Out! You need input two integers."

exit 1

fi

if [ $num1 -gt $num2 ];then

echo "Max:$num1,Min:$num2"

elif [ $num1 -lt $num2 ];then

echo "Max:$num2,Min:$num1"

else

echo "$num1 equal $num2 "

fi

运行结果:

五、循环语句

1.for语句

1.1格式:

for VARIABLE in LIST; do

循环体

done

1.1.1     LIST:是由一个或多个空格或换行符分隔开的字符串组成;把列表的每个字符串逐个赋值给VARIABLE表示的变量;

进入条件:列表非空;

退出条件:列表遍历结束;

1.1.2     LIST的生成方法:

(1) 整数列表

(a) {start..end}

(b) $(seq [start [[step]] end)

(2) 直接给出列表

(3) glob

(4) 命令生成

例如:    使用添加5个用户,user1-user10;

直接给出列表:

[[email protected] bashtest]# vim for1.sh
#!bin/bash
for uname in user1 user2 user3 user4user5;do
       if id $uname &> /dev/null; then
                echo "$uname exists."
       else
               useradd $uname
       echo "Add user $uname successfully."
       fi
done

正数列表:

[[email protected] bashtest]# vim ./for2.sh
#!bin/bash
for i in {6..10};do
       if id user$i &> /dev/null; then
                echo "user$i exists."
       else
                useradd user$i
       echo "Add user user$i successfully."
       fi
done

示例:glob

[[email protected] bashtest]# vim glob.sh
#!bin/bash
for fname in /tmp/bashtest/*;do
       file $fname
done

示例:命令生成列表

[[email protected] bashtest]# vim comand.sh
#!/bin/bash
for username in $(cut -d: -f1 /etc/passwd);do
echo "$username primary group: $(id -n -g $username)."
done

1.1.3  for循环的特殊用法:

for((expr1;expr2;expr3)); do

循环体

done

expr1:定义控制变量,并初始赋值;

expr2:循环控制条件;

expr3:修正控制变量

进入条件:控制条件为“真”

退出条件:控制条件为“假”

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

#!/bin/bash
declare -i sum=0
for ((i=1;i<=100;i++)); do
         letsum+=$i
done
echo "Sum: $sum."

2.算术运算

(1)$[$A+$B]

(2)$(($A+$B))

(3)let VARIABLE=$A+$B

(4)VARIABLE=$(expr $A + $B)

例如:

[[email protected] bashtest]# a=3
[[email protected] bashtest]# b=4
[[email protected] bashtest]# sum=$a+$b
[[email protected] bashtest]# echo $sum
3+4
[[email protected] bashtest]# sum=$[$a+$b]
[[email protected] bashtest]# echo $sum
7
[[email protected] bashtest]# sum2=$(($a+$b))
[[email protected] bashtest]# echo $sum2
7
[[email protected] bashtest]# let sum3=$a+$b
[[email protected] bashtest]# echo $sum3
7
[[email protected] bashtest]# sum4=$(expr $a +$b)
[[email protected] bashtest]# echo $sum4
7

练习3:

求100以内所有偶数之和

1.for语句

[[email protected] bashtest]# vim oddsum1.sh
#!bin/bash
declare -i sum=0
for i in $(seq 1 2  99);do
       sum=$(($sum+$i))
done
       echo $sum

或者

#!bin/bash
declare -i sum=0
for i in {1..100}; do
   if [ $[$i%2] -eq 1 ]; then
        sum=$[$sum+$i]
   fi
done
echo $sum

2.while语句

#!/bin/bash
declare -i m=1
declare -i sum=0
while [ $m -le 100 ]
do
       sum+=m
        let m+=2
done
echo $sum

3.until语句

#!/bin/bash
declare -i m=1
declare -i sum=0
until [ $m -gt 99 ]
do
       sum+=m
       let m+=2
done
echo $sum

3.增强型赋值

3.1 +=

sum=$[$sum+$i]表达式可以写成let sum+=$i

3.2   -=, *=, /=, %=

let count=$[$count+1]  --> let count+=1 --> let count++

let count=$[$count-1] --> let count-=1--> let count--

例如:显示/etc目录下所有普通文件列表,而后统计一共有多少个文件;

#!/bin/bash
declare -i count=0
for file in /etc/*; do
if [ -f $file ]; then
         letcount++
         echo"$count $file"
fi
done
echo"Total: $count files."

4.测试表达式

4.1 整数测试:-gt, -lt, -ge,-le, -eq, -ne

4.2字符串测试:==, >, <,!=, -z, -n, =~

注意:

(1) 字符串等会比较测试:["$hostname" == ‘localhost‘  ]

(2) 模式匹配测试:[["STRING" =~ PATTERN ]]

4.3组合测试条件:

4.3.1条件间逻辑运算::多个条件要同时满足;:多个条件满足其一即可;:对指定的条件取反;

4.3.2表达式组合:

与:[[CONDITION1 -a CONDITION2 ]]

或:[[CONDITION1 -o CONDITION2 ]]

非:[ ! CONDITION]

4.3.3命令组合:

与:COMMAND1 && COMMAND2

或:COMMAND1 || COMMAND2

非:! COMMAND

4.4短路操作符:&&,只要左侧为真时即为真,其余都为假

类似于:

if COMMAND1; then

COMMAND2

fi

4.6短路操作符:||,左侧为真时,或者右侧为真时,即为真;其余

true || true = true           true || false = true             false || true = true          false || false = false

类似于:

if ! COMMAND1; then

COMMAND2

fi

4.7   COMMAND1 && COMMAND2 || COMMAND3 该命令组合类似于:

ifCOMMAND1; then

COMMAND2

else

COMMAND3

fi

例如:写一个脚本实现如下功能:获取当前主机的主机名,如果当前主机的主机名为空,或者为localhost,则将其修改为www.magedu.com

#!/bin/bash
hostname=$(hostname)
if [ -z "$hostname" -o"$hostname" == "localhost" ]; then
         hostnamewww.magedu.com
fi
if [ $line1 -lt $line2 ];then
       echo "$fpath2 has max total lines : $line2"
elif [ $line1 -gt $line2 ];then
       echo "$fpath2 has max total lines : $line1"
else
       echo "They have the same total lines:$line1"

练习4:

写一个脚本:(1) 传递两个文本文件路径给脚本;(2) 显示两个文件中空白行数较多的文件及其空白行的个数;(3) 显示两个文件中总行数较多的文件及其总行数;

[[email protected] bashtest]# vim zero.sh
#!bin/bash
read -p "Input two file paths:"-t 30 fpath1 fpath2
if [ -z $fpath1 -o -z $fpath2 ];then
       echo "Error!"
       exit 1
fi
if [ ! -e $fpath1 -o ! $fpath2 ];then
       echo "$fpath1 OR $fpath2 does not exist."
       exit 2
fi
blank1=$(grep ‘^$‘ $fpath1 | wc -l)
blank2=$(grep ‘^$‘ $fpath2 | wc -l)
if [ $blank1 -lt $blank2 ];then
       echo "$fpath2 has max blank lines : $blank2"
elif [ $blank1 -gt $blank2 ];then
       echo "$fpath1 has max blank lines : $blank1"
else
       echo "They have the same blank lines:$blank1"
fi
line1=$(wc -l $fpath1 | cut -d ‘ ‘ -f1)
line2=$(wc -l $fpath2 | cut -d ‘ ‘ -f1)
if [ $line1 -lt $line2 ];then
       echo "$fpath2 has max total lines : $line2"
elif [ $line1 -gt $line2 ];then
       echo "$fpath1 has max total lines : $line1"
else
       echo "They have the same total lines:$line1"
fi
[[email protected] bashtest]# bash zero.sh
Input two file paths:/tmp/c1 /tmp/c2
/tmp/c2 has max blank lines : 3
/tmp/c2 has max total lines : 6

练习5:

写一个脚本:(1) 提示用户输入一个字符串;(2) 判断:如果输入的是quit,则退出脚本;否则,则显示其输入的字符串内容;

[[email protected] bashtest]# vim test5.sh
#!bin/bash
read -p "Enter a string:" -t 30s1
if [ -z $s1 ];then
       echo "Error:$s1 is blank"
       exit 1
fi
if [ "$s1" == "quit"];then
        echo "Quit script!"
       exit 0
else
       echo $s1
fi
[[email protected] bashtest]# bash test5.sh
Enter a string:s
s
[[email protected] bashtest]# bash test5.sh
Enter a string:quit
Quit script!

练习6:写一个脚本,打印2^n表;n等于一个用户输入的值;

[[email protected] bashtest]# vim test6.sh
#!bin/bash
read -p "Input Number:" -t 20 num
if [ -z "$num" -o $num -lt 0];then
       echo "Error:NO valid Number!"
       exit 1
fi
declare -i sum=1
echo "2^0=1 "
if [ $num -gt 0 ];then
       for m in $(seq 1 $num)
       do
               let sum=$sum*2
                echo  "2^$m = $m "
       done
fi

5.循环嵌套

示例:九九乘法表

#!/bin/bash                     
for j in {1..9}; do
 for i in $(seq 1 $j); do
         echo-n -e "${i}X${j}=$[$i*$j]\t"
done
echo
done

结果:

6.case语句

6.1 使用场景:判断某变量的值是否为多种情形中的一种时使用;

6.2语法:

case$VARIABLE in

PATTERN1)

分支1

;;

PATTERN2)

分支2

;;

PATTERN3)

分支3

;;

...

*)

分支n

;;

esac

PATTERN可使用glob模式的通配符:

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

?:任意单个字符;

[]:指定范围内的任意单个字符;

a|b:多选1;

示例:提示键入任意一个字符;判断其类型;

#!/bin/bash
read-p "Plz enter a character: " char
 case$char in
    [a-z])
   echo "A character."
    ;;
    [0-9])
   echo "A digit."
    ;;
   *)
  echo "A special character."
   ;;                                    
esac

7.while语句

7.1语法格式:

while CONDTION; do

循环体

(控制变量的修正表达式)

done

7.2  进入条件:当CONDITION为“真”;

退出条件:当CONDITION为“假”;

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

#!/bin/bash
declare -i sum=0
declare -i i=1
while [ $i -le 100 ]; do
         letsum+=$i
         leti++
done
echo "Sum: $sum."

示例:打印九九乘法表

#!/bin/bash
declare -i i=1
declare -i j=1
while [ $j -le 9 ]; do
         while[ $i -le $j ]; do
                   echo-e -n "${i}X${j}=$[$i*$j]\t"
                   leti++
         done
                echo
         let i=1
         let j++
done

7.3 while循环的特殊用法:遍历文件的每一行

whileread VARIABLE; do

循环体

done< /PATH/FROM/SOME_FILE

示例:找出UID为偶数的所有用户,显示其用户名和ID号;

#!/bin/bash
while read line; do
   userid=$(echo $line | cut -d: -f3)
   if [ $[$userid%2] -eq 0 ]; then
       echo $line | cut -d: -f1,3
   fi     
done < /etc/passwd

结果:

[[email protected] bashtest]# bash while.sh
root:0
daemon:2
lp:4
shutdown:6
mail:8
games:12
ftp:14
colord:998
ntp:38
saslauth:996
rpc:32
rtkit:172
nfsnobody:65534
sssd:994
avahi-autoipd:170
gdm:42
gnome-initial-setup:992
sshd:74
avahi:70
tcpdump:72
lan:1000
apache:48
shtest1:1002
huawei:1004
hua:1006
51cto:1008
mage:1010
user1:1012
user3:1014
user5:1016
user7:1018
user9:1020

8.unitl语句

8.2 语法格式:

until CONDITION; do

循环体

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

done

8.2  进入条件:当CONDITION为“假”时

退出条件:当CONDITION为“真”时

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

#!/bin/bash

declare -i sum=0

declare -i i=1

until [ $i -gt 100 ]; do

letsum+=$i

leti++

done

echo "Sum: $sum."

9.循环控制

9.1  continue [n]:提前结束本轮循环,而直接进入下一轮;

break [n]:提前结束循环;break 本身是结束本轮循环,加上数值后可以指明跳出哪个循环

9.2  while循环:

9.2.1    while CONDITION; do

.......

ifCONDITION2; then

break[n]

fi

done

9.2.2   while CONDITION; do

......

ifCONDITION2; then

continue[n]

fi

......

done

示例:求100以内所有偶数之和;

#!/bin/bash
declare -i sum=0
declare -i i=0
while [ $i -le 100 ]; do
         leti++
         if[ $[$i%2] -eq 1 ]; then
                   echo"$i is a odd."
                   continue
         fi
         letsum+=$i
done
echo "Sum: $sum."

9.3 死循环:

9.3.1  while true; do

循环体

ifCONDTION; then

break

fi

done

9.3.2   until false; do

循环体

ifCONDITION; then

break

fi

done

示例:每隔3秒钟查看当前系统上是否有名为“hua”的用户登录;如果某次查看hua登录了,则显示hua已经登录;如果未登录,就显示仍然未来,并显示这是已经是第多少次查看了;

#!/bin/bash
username=$1
declare -i count=0
while true; do
if who | grep "^$username"&> /dev/null; then
           echo "$username is logged."
break
else
         letcount++
         echo"$count $username is not login."
fi
         sleep3
done

#!/bin/bash

declare -i count=0
username=$1
if [ $# -lt 1 ]; then
         echo"At lease one argument."
         exit1
fi
if ! id $username &> /dev/null; then
         echo"No such user."
         exit2
fi
 
until who | grep "^$username"&> /dev/null; do
         letcount++
         echo"$count $username is not login."
         sleep3
done
echo "$username is logged on."

五、函数的使用

1. 函数

1.1  function:把一段具有独立功能代码封装在一起,并给予命名;后续用到时,可直接通过给定函数名来调用整体代码;

1.2  函数作用:代码重用;模块化编程;

1.3函数的使用方法:

先定义:编写函数代码

后调用:给出函数名,还可按需传递参数

1.4 定义方法:

(1)function f_name {

函数体

}

(2)f_name() {

函数体

}

1.5 调用函数: f_name [argu1,argu2, ...]

自定义函数状态返回值:

return[#]     0: 成功              1-255:失败

注意:函数代码执行时,一旦遇到return,函数代码终止运行,函数返回;

2.模块化编程

2.1 功能:把脚本文件中的代码分隔为多段,放在不同的文件中。假设/root/bin/srv目录有两个文件:(1) 函数文件   (2) 脚本文件

2.2为脚本使用配置文件,一个文件中只定义变量,脚本文件source此变量定义的文件

2.3 变量的作用域:

局部变量: localVARIABLE=value

2.4存活时间:函数执行开始,至函数返回结束;

练习7:写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、两个数值的大小都将通过交互式输入来提供。

求解最大公约数思路:辗转相除法

#!/bin/bash
input() {
read -p "Input two integers:" -t30 m n
if [ -z $m -o -z $n ]
then
   echo  "Error:No ValidNumbers"
   exit 1
fi
}
#求和
sum() {
input
sum=$[$m+$n]
echo "$m+$n = $sum"
}
#最大公约数
gcd() {
input
while [ ! $m -eq $n ]; do
  if[[ $m -gt $n ]]; then
   let m-=n
 else
   let n-=m
  fi
done
 echo "gcd:$m"
}
#最小公倍数=====================================================
lcm() {
input
if [ $m -gt $n ]
then
       for j in `seq 1 $[$m*$n]`
       do
       if [ $[$m*$j%$n] -eq 0 ]
       then
                echo "$[$m*$j]"
                break
       fi
       done
elif [ $m -le $n ]
then
                for j in `seq 1 $[$m*$n]`
       do
       if [ $[$n*$j%$m] -eq 0 ]
       then
                echo "$[$n*$j]"
                break
        fi
       done
fi
}
read -p "Choose‘sum‘or‘gcd‘or‘lcm‘:" -t 20 cal
case $cal in
sum)
  sum
;;
gcd)
  gcd
;;
lcm)
  lcm
;;
*)
 echo "input error:Usg:‘sum‘|‘gcd‘|‘lcm‘"
esac

结果:

六、数组的使用

1.数组:连续的多个独立内存空间;每个内存空间相当于一个变量;数组的各个变量称为数组的元素,有时也称为下标变量。

2.传统数组:索引为数字,从0开始编号;

declare-a ARRAY_NAME

关联数组:索引可以自定义,可以使用任意字符串做索引;

declare-A ARRAY_NAME

3.数组元素的赋值方式

(1) 一次只赋值一个元素

array[index]=value

(2) 一次赋值全部元素

array=(val1   val2   val3 ...)

(3) 指定索引进行赋值

array=([0]="val1"[3]="val2")

(4) read -a array

4.引用元素:${array[index]}

5.获取长度:${#array[*]},${#array[@]}

6.数组删除:unset 数组[下标]

示例:

[[email protected] ~]$ animal=(dog cat tigerpanda)
 [[email protected]~]$ echo ${#animal[*]}
4
 [[email protected]~]$ echo ${animal[0]}
dog
 [[email protected]~]$ echo ${animal[1]}
cat
[[email protected] ~]$ echo ${animal[2]}
tiger
[[email protected] ~]$ echo ${animal[3]}
panda
[[email protected] ~]$ echo ${animal[*]}
dog cat tiger panda

七、sed,awk工具的使用

时间: 2024-10-10 20:20:14

Shell脚本编程与sed,awk工具的使用--9月15日课程作业的相关文章

2015年9月13日课程作业--关于SHELL的问题

1.描述shell程序的运行原理(可附带必要的图形说明): SHELL是一种特殊的程序,官方定义为是和内核的接口,类似于内核的代理人.人类和LINUX系统对话时,需要一个翻译,而shell就是这个翻译.我们用SHELL编辑自己想要执行的一系 列命令后,SHELL可以翻译给系统内核听,然后系统内核执行. 2.总结shell编程中所涉及到的所有知识点(如:变量.语法.命令状态等等等,要带图的哟): //以下实例来自iredmail的安装脚本 tmprootdir="$(dirname $0)&quo

shell脚本编程之正则表达式(二)(扩展正则表达式、sed)

shell脚本编程之正则表达式(二) 一.前言 ? 本文主要是对扩展正则表达式的介绍,同时,继续按照上篇文章的风格介绍sed文本处理工具,sed作为shell编程中"三剑客"之一,在对文本处理上有巨大作用.关于正则概念以及grep命令结合正则使用的案例请参照:https://blog.51cto.com/14557673/2455588 二.扩展正则表达式 ? 扩展正则表达式主要是为了简化指令而产出的.例如,使用基础正则表达式查询文件中空白行与行首为#号之外的行(一般用于查看生效的配置

第三周、文本处理工具、shell脚本编程

文本处理工具 1.cut -d指定分隔符.比如-d: -d' ' -f指定取第几列.比如-f1,3 --output-delimiter指定显示的分隔符 tr -s压缩 -d删除 -c除了 2.使用tr和cut取磁盘的百分比 [[email protected] data]# df -h | tr -s ' ' | cut -d' ' -f5 | tr -dc '[0-9]\n' 0 0 5 0 32 67 32 0 3.取IP [[email protected] data]# ifconfi

文本处理工具和正则表达式、shell脚本编程基础-第四周

第四周-文本处理工具和正则表达式.shell脚本编程基础1. 统计出/etc/passwd文件中其默认shell为非/sbin/nologin的用户的个数,并将用户都显示出来grep -v '/sbin/nologin' /etc/passwd|wc -lgrep -v '/sbin/nologin' /etc/passwd|cut -d: -f12. 查出用户UID最大值的用户名,UID及shell类型.cut -d: -f1,3,7 /etc/passwd|sort -t: -k2 -nr

文本处理工具和正则表达式、SHELL脚本编程

一.文本编辑工具VIM ●命令模式 --> 插入模式 i     insert, 在光标所在处输入 I     在当前光标所在行的行首输入 a    append, 在光标所在处后面输入 A    在当前光标所在行的行尾输入 o    在当前光标所在行的下方打开一个新行 O   在当前光标所在行的上方打开一个新行 ●插入模式 --- ESC-----> 命令模式 ●命令模式 ----:----> 扩展命令模式 ●扩展命令模式 ---ESC,enter---->命令模式 1.进入编辑

Shell脚本编程30分钟入门

什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_tut for ((i=0; i<10; i++)); do touch test_$i.txt done 示例解释 第1行:指定脚本解释器,这里是用/bin/sh做解释器的 第2行:切换到当前用户的home目录 第3行:创建一个目录shell_tut 第4行:切换到shell_tut目录 第5行:循环条件,一共循环10次 第6行:创建一个test_1…10.txt文件 第7

Linux Shell脚本编程学习笔记和实战

http://www.1987.name/141.html shell基础 终端打印.算术运算.常用变量 Linux下搜索指定目录下特定字符串并高亮显示匹配关键词 从键盘或文件中获取标准输入 [read命令] 文件的描述符和重定向 数组.关联数组和别名使用 函数的定义.执行.传参和递归函数 条件测试操作与流程控制语句 获取时间日期格式和延时 [date.sleep命令] 内部字段分隔符IFS和脚本的调试DEBUG 显示.读取或拼接文件内容 [cat命令] 文件查找与打印文件列表 [find命令]

shell脚本编程30分钟入门上手

什么是Shell脚本 Shell脚本(英语:Shell script),又称Shell命令稿.程序化脚本,是一种电脑程序与文本文件,内容由一连串的shell命令组成,经由Unix Shell直译其内容后运作.被当成是一种脚本语言来设计,其运作方式与直译语言相当,由Unix shell扮演命令行解释器的角色,在读取shell脚本之后,依序运行其中的shell命令,之后输出结果.利用shell脚本可以进行系统管理,文件操作等. 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell

#7 shell脚本编程之正则表达式

多命令执行方法: 脚本组成: 1.shengbang 2.# 3.空白行--没有任何内容的行.只包含空白字符或制表符(TAB) 4.逻辑判断 shell脚本编程: 1.加执行权限,通过路径来调用脚本: 2.利用解释器直接执行: 本文处理工具: vim.vi.nano 文本处理三剑客: grep系: grep.egrep.fgrep,文本搜索工具,基础"pattern"对于给定的文本进行模糊搜索,grep系默认工作于贪婪模式下: sed:stream editor,流数据器,行编辑器,文