shell脚本

  • shell脚本已关闭评论
  • 109 次浏览
  • A+
所属分类:linux技术
摘要

执行shell脚本的方式方式一:bashbash test.sh 方式二:././test.sh 方式三: 使用脚本完整路径

  1. shell

执行shell脚本的方式

方式一:bash

bash test.sh

 

方式二:./

./test.sh

 

方式三: 使用脚本完整路径

/root/test.sh

 

方式四:使用source,以当前默认 Shell 解释器执行

source test.sh

常用系统变量

在命令行提示符直接执行 env、set 查看系统或环境变量。

系统变量 作用

$HOME 当前用户家目录

$SHELL 默认 Shell

$IFS 内部字段分隔符

$LANG 默认语言

$PATH 默认可执行程序路径

$PWD 当前目录

$UID 当前用户 ID

$USER 当前用户

$HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间

$RANDOM 随机生成一个 0 至 32767 的整数

$BASHPID 当前bash的PID号

$HOSTNAME 主机名

ps axjf 输出的第一列是 PPID(父进程 ID),第二列是 PID(子进程 ID)

位置变量

位置变量指的是函数或脚本后跟的第 n 个参数。

$1-n,需要注意的是从第 10 个开始要用花括号调用,例如${10}

shift 可对位置变量控制,例如:

#!/bin/bash

echo "1: $1"

shift

echo "2: $2"

shift

echo "3: $3"

# bash test.sh a b c

1: a

2: b

3: c

 

每执行一次 shift 命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动n位。

特殊变量

变量名 作用

$0 脚本自身名字

$1 脚本后跟的第一个位置参数,如果个数超过10,需要使用{}

$* 显示脚本后跟的所有参数,所有的位置参数被看做一个字符串

$@ 显示脚本后跟的所有参数,每个位置参数被看做独立的字符串

$# 显示参数的个数

$? 显示上条命令的执行结果,0为成功,非0失败,范围0-255

$$ 当前进程 PID

$! 上一条运行后台进程的 PID

变量引用

赋值运算符 示例

= 变量赋值

+= 两个变量相加

自定义变量与引用

[root@zhongxiaofei ~]# VAR=123

[root@zhongxiaofei ~]# echo $VAR

123

[root@zhongxiaofei ~]# VAR+=666

[root@zhongxiaofei ~]# echo $VAR

123666

Shell 中所有变量引用使用$符,后跟变量名。

有时个别特殊字符会影响正常引用,那么需要使用${VAR},例如:

[root@zhongxiaofei ~]# VAR=123

[root@zhongxiaofei ~]# echo $VAR

123

[root@zhongxiaofei ~]# echo $VAR_

[root@zhongxiaofei ~]# echo ${VAR}

123

还有时候变量名与其他字符串紧碍着,也会误认为是整个变量:

[root@zhongxiaofei ~]# echo $VAR666

[root@zhongxiaofei ~]# echo ${VAR}666

123666

将命令结果作为变量值

[root@zhongxiaofei ~]# VAR=`date`

[root@zhongxiaofei ~]# echo $VAR

Mon Oct 25 18:05:14 CST 2021

[root@zhongxiaofei ~]#

[root@zhongxiaofei ~]# VAR=$(date)

[root@zhongxiaofei ~]# echo $VAR

Mon Oct 25 18:05:27 CST 2021

这里的反撇号等效于$(),都是用于执行 Shell 命令。

双引号和单引号

在变量赋值时,如果值有空格,Shell 会把空格后面的字符串解释为命令:

[root@zhongxiaofei ~]# VAR=2 3 4

bash: 3: command not found

[root@zhongxiaofei ~]# VAR="2 3 4"

[root@zhongxiaofei ~]# echo $VAR

2 3 4

[root@zhongxiaofei ~]# VAR='3 3 4'

[root@zhongxiaofei ~]# echo $VAR

3 3 4

看不出什么区别,再举个说明:

[root@zhongxiaofei ~]# N=2

[root@zhongxiaofei ~]# VAR="1 $N"

[root@zhongxiaofei ~]# echo $VAR

1 2

[root@zhongxiaofei ~]# VAR='1 $N'

[root@zhongxiaofei ~]# echo $VAR

1 $N

单引号是告诉 Shell 忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。

单引号:所见即所得

反引号:先执行里面的命令

双引号:会对具有特殊意义的字符做解析

shell注释

Shell 注释也很简单,只要在每行前面加个#号,即表示 Shell 忽略解释。

变量赋值总结

变量赋值语句

向变量中写入内容。vimvv

shell脚本

#read

-p 交互的时候提示信息。

-t 超过这个时间没有操作,则自动退出.

-s 不显示用户的输入.记录密码才用.

#基本用法

read -p "请输入密码:" pass

请输入密码:*******'''

echo $pass

*******'''

read -p "请输入密码:" pass

请输入密码:zhongfei123

echo $pass

zhongfei123

 

不显示用户的输入.

[root@centos7 ~]# read -s -p "请输入密码:" pass

请输入密码:[root@centos7 ~]#

[root@centos7 ~]# echo $pass

zhong

 

同时向2个变量赋值。

read -p "请输入2个数字num1 num2:" num1 num2

请输入2个数字num1 num2:zhong fei

echo $num1 $num2

zhong fei

案例:用户输入1个字符串,然后进行显示

[root@centos7 scripts]# cat 09.fake_guess.sh

#!/bin/bash

read -s -p "请偷偷的输入你心中所想的内容:" guess

echo ""

sleep 1

echo "我与你心连心,心有灵犀一点通"

sleep 2

echo "我似乎知道你想的内容了"

sleep 3

echo "是不是这个: $guess"

字符串处理

获取字符串长度

# VAR='hello world!'

# echo $VAR

hello world!

# echo ${#VAR}

12

字符串切片

格式:

${parameter:offset}

${parameter:offset:length}

 

截取 hello 字符串:

# VAR='hello world!'

# echo ${VAR:0:5}

hello

截取 wo 字符:

# echo ${VAR:6:2}

wo

截取 world!字符串:

# echo ${VAR:5}

world!

截取最后一个字符:

# echo ${VAR:(-1)}

!

截取最后二个字符:

# echo ${VAR:(-2)}

d!

截取从倒数第 3 个字符后的 2 个字符:

# echo ${VAR:(-3):2}

ld

替换字符串

格式:${parameter/pattern/string}

${变量名/要替换谁/替换成什么}

 

# VAR='hello world world!'

将第一个 world 字符串替换为 WORLD:

# echo ${VAR/world/WORLD}

hello WORLD world!

将全部 world 字符串替换为 WORLD:

# echo ${VAR//world/WORLD}

hello WORLD WORLD!

替换正则匹配为空:

# VAR=123abc

# echo ${VAR//[^0-9]/}

123

# echo ${VAR//[0-9]/}

abc

pattern 前面开头一个正斜杠为只匹配第一个字符串,两个正斜杠为匹配所有字符。

字符串截取

格式:

${parameter#word} #从变量左边开始删除,按照最短匹配删除

${parameter##word} #从变量左边开始删除,按照最长匹配删除

${parameter%word} # 从变量右边开始删除,按照最短匹配删除

${parameter%%word} #从变量右边开始删除,按照最长匹配删除

# 去掉左边,最短匹配模式,##最长匹配模式。

% 去掉右边,最短匹配模式,%%最长匹配模式。

 

# URL="http://www.baidu.com/baike/user.html"

以//为分隔符截取右边字符串:

# echo ${URL#*//}

www.baidu.com/baike/user.html

以/为分隔符截取右边字符串:

# echo ${URL##*/}

user.html

以//为分隔符截取左边字符串:

# echo ${URL%%//*}

http:

以/为分隔符截取左边字符串:

# echo ${URL%/*}

http://www.baidu.com/baike

以.为分隔符截取左边:

# echo ${URL%.*}

http://www.baidu.com/baike/user

以.为分隔符截取右边:

# echo ${URL##*.}

html

变量状态赋值

${VAR:-string} 如果 VAR 变量为空则返回 string

${VAR:+string} 如果 VAR 变量不为空则返回 string

${VAR:=string} 如果 VAR 变量为空则重新赋值 VAR 变量值为 string

${VAR:?string} 如果 VAR 变量为空则将 string 输出到 stderr

 

例:如果变量不为空就返回 hello world!: # VAR="hello"

# echo ${VAR:+'hello world!'}

hello world!

如果变量为空就重新赋值:

# VAR=

# echo ${VAR:=hello}

hello

# echo $VAR

hello

如果变量为空就将信息输出 stderr: # VAR=

# echo ${VAR:?value is null}

-bash: VAR: value is null

字符串颜色

https://blog.csdn.net/yetugeng/article/details/89978787

Shell 表达式与运算符

整数比较符

比较符 描述 示例

-eq,equal 等于 [ 1 -eq 1 ]为 true

-ne,not equal 不等于 [ 1 -ne 1 ]为 false

-gt,greater than 大于[ 2 -gt 1 ]为 true

-lt,lesser than 小于 [ 2 -lt 1 ]为 false

-ge,greater or equal 大于或等于 [ 2 -ge 1 ]为 true

-le,lesser or equal 小于或等于 [ 2 -le 1 ]为 false

#示例:测试一下 10 是否大于 10 以及 10 是否等于 10(通过输出的返回值内容来判断):

[root@shell ~]# [ 10 -gt 10 ]

[root@shell ~]# echo $?

1

[root@shell ~]# [ 10 -eq 10 ]

[root@shell ~]# echo $?

0

字符串比较符

运算符

描述

示例

==

等于

[ "a" == "a" ]为 true

!=

不等于

[ "a" != "a" ]为 false

<=

小于等于

在(())表达式中:(( 3 <= 2 ))为 false

>=

大于等于

在(())表达式中:(( 3 >= 2 ))为 true

-n

字符串长度不等于 0 为真

VAR1=1;VAR2=""

[ -n "$VAR1" ]为 true

-z

字符串长度等于 0 为真

VAR1=1;VAR2=""

[ -z "$VAR1" ]为 false

str

字符串存在为真

VAR1=1;VAR2=""

[ $VAR1 ]为 true

||

或者

 

[ -z $a ] && echo yes || echo no

# [ -z $a ] && echo yes || echo no

yes

# [ -n $a ] && echo yes || echo no

yes

# 加了双引号才能正常判断是否为空

# [ -z "$a" ] && echo yes || echo no

yes

# [ -n "$a" ] && echo yes || echo no

no

# 使用了双中括号就不用了双引号

# [[ -n $a ]] && echo yes || echo no

no

# [[ -z $a ]] && echo yes || echo no

yes

文件测试

测试符 描述

-e 文件或目录存在为真 [ -e path ] path 存在为 true

-f 文件存在为真 [ -f file_path ] 文件存在为 true

-d 目录存在为真 [ -d dir_path ] 目录存在为 true

-r 有读权限为真[ -r file_path ] file_path 有读权限为 true

-w 有写权限为真[ -w file_path ] file_path 有写权限为 true

-x 有执行权限为真 [ -x file_path ] file_path 有执行权限为 true

-s 文件存在并且大小大于0为真 [ -s file_path ] file_path 存在并且大小大于 0为true

#判断/etc/fstab 是否为一个目录类型的文件

[root@shell ~]# [ -d /etc/fstab ]

[root@shell ~]# echo $?

1

 

#判断/etc/fstab是否为一般文件,如果返回值为0,则代表文件存在,反之

[root@shell ~]# [ -f /etc/fstab ]

[root@shell ~]# echo $?

0

布尔运算符

运算符

描述

示例

非关系,取反

[ ! 1 -eq 2 ]为 true

-a

和关系,在【】表达式中使用

[ 1 -eq 1 -a 2 -eq 2 ]为 true

-o

或关系,在【】表达式中使用

[ 1 -eq 1 -o 2 -eq 1 ]为 true

逻辑判断符

判断符

描述

示例

&&

逻辑和,在[[]]和(())表达式中或判断表达

式是否为真时使用

[[ 1 -eq 1 && 2 -eq 2 ]]为 true

(( 1 == 1 && 2 == 2 ))为 true

[ 1 -eq 1 ] && echo yes 如果&&前面表达式

为 true 则执行后面的

||

逻辑或,在[[]]和(())表达式中或判断表达

式是否为真时使用

[[ 1 -eq 1 ||2 -eq 1 ]]为 true

(( 1 == 1 ||2 == 2 ))为 true

[ 1 -eq 2 ] ||echo yes 如果||前面表达式为

false 则执行后面的

整数运算

运算符 描述

+ 加法

- 减法

* 乘法

/ 除法

%取余

运算表达式 :

$(())$((1=1))

$[ ] $[1+1]

$(())表达式还有一个用途,三目运算:

在此处所谓的单双,指的是参与运算的运算数个数。

单目运算

* 如大多数编程语言中都有的 i++、i-- 就是一种典型的单目运算。逻辑运算中的“非”运算,即 !a

,也是一种单目运算。

二目运算

* 二目运算同理,a + b , a - b , a ∩ b 等等

三目运算

* 三目运算稍复杂一些,下面给出一个表达式然后尽量通俗的解释:

status = hungry ? eat : notEat

这个表达式可以理解成:

* 肚子饿吗?

* 如果饿的话(status = hungry),就去吃饭。

* 如果不饿 (status != hungry),就不吃了。

* 参与运算的运算数有:hungry、eat、notEat三个。

 

# 如果条件为真返回 1,否则返回 0

# echo $((1<0))

0

# echo $((1>0))

1

指定输出数字:

# echo $((1>0?1:2))

1

# echo $((1<0?1:2))

2

注意:返回值不支持字符串

其他运算工具(let/expr/bc)

let

赋值并运算,支持++、--

例:

let VAR=(1+2)*3 ;

echo $VAR

x=10 ; y=5

let x++;echo $x 每执行一次 x 加 1

let y--;echo $y 每执行一次 y 减 1

let x+=2 每执行一次 x 加 2

let x-=2 每执行一次 x 减 2

 

expr

乘法*需要加反斜杠转义*

例:

expr 1 * 2 运算符两边必须有空格

expr ( 1 + 2 ) * 2 使用双括号时要转义

 

bc

计算器,支持浮点运算、平方等

例:

bc 本身就是一个计算器,可直接输入命令,进入解释器。

echo 1 + 2 |bc 将管道符前面标准输出作为 bc 的标准输入

echo "1.2+2" |bc

echo "10^10" |bc

echo 'scale=2;10/3' |bc 用 scale 保留两位小数点

由于 Shell 不支持浮点数比较,可以借助 bc 来完成需求:

# echo "1.2 < 2" |bc

1

# echo "1.2 > 2" |bc

0

# echo "1.2 == 2.2" |bc

0

# echo "1.2 != 2.2" |bc

1

看出规律了嘛?运算如果为真返回 1,否则返回 0,写一个例子:

# [ $(echo "2.2 > 2" |bc) -eq 1 ] && echo yes || echo no

yes

# [ $(echo "2.2 < 2" |bc) -eq 1 ] && echo yes || echo no

no

 

expr 还可以对字符串操作:

获取字符串长度:

# expr length "string"

6

截取字符串:

# expr substr "string" 4 6

ing

获取字符在字符串中出现的位置:

# expr index "string" str

1

# expr index "string" i

4

获取字符串开始字符出现的长度:

# expr match "string" s.*

6

# expr match "string" str

3

Shell 括号用途总结

( )

用途 1:在运算中,先计算小括号里面的内容

用途 2:数组

用途 3:匹配分组

 

(( ))

用途 1:表达式,不支持-eq 这类的运算符。不支持-a 和-o,支持<=、>=、<、>这类

比较符和&&、||

用途 2:C 语言风格的 for(())表达式

 

$( )

执行 Shell 命令,与反撇号等效

 

$(( ))

用途 1:简单算数运算

用途 2:支持三目运算符 $(( 表达式?数字:数字 ))

 

[ ]

条件表达式,里面不支持逻辑判断符,比如&& || 不支持

 

[[ ]]

条件表达式,里面不支持-a 和-o,不支持<=和>=比较符,支持-eq、<、>这类比较符。支持=~模式匹

配,也可以不用双引号也不会影响原意,比[]更加通用

 

$[ ]

简单算数运算

 

{ }

对逗号(,)和点点(...)起作用,比如 touch {1,2}创建 1 和 2 文件,touch {1..3}创建 1、

2 和 3 文件

 

${ }

用途 1:引用变量

用途 2:字符串处理

shell流程控制

if语句

单分支

if [条件表达式]

then

命令

fi

[root@centos7 ~]# vim if1.sh

#!/bin/bash

if [ -d /etc ]

then

echo "is a directory"

fi

[root@centos7 ~]# bash if1.sh

is a directory

##优化

[root@centos7 ~]# vim if1.sh

#!/bin/bash

DIR1="/etc"

if [ -d $DIR1 ]

then

echo "$DIR1 is a directory"

fi

[root@centos7 ~]# bash if1.sh

/etc is a directory

双分支

if [条件表达式]

then

命令。。

else

命令

fi

shell脚本

##编写脚本

[root@centos7 ~]# vim if3.sh

#!/bin/bash

NUM=`ps -ef | grep httpd | grep -vc grep` ##把该服务产生的进程数量显示出来赋值给变量NUM

if [ $NUM -ge 1 ] ##判断进程数量是否大于等于1(如果大于等于

1说明,服务是启动的)

then ##然后

echo "service is running" ##显示服务正在运行

else ##除此之外

echo "service is down" ##显示服务是关闭的

fi #结束

[root@centos7 ~]# bash if3.sh

service is running

##优化脚本,优化后,后续只需要对应的修改SER变量对应的值即可,想判断哪个服务就写哪个服务名

[root@centos7 ~]# vim if3.sh

#!/bin/bash

SER=nfs

NUM=`ps -ef | grep $SER | grep -vc grep`

if [ $NUM -ge 1 ]

then

echo "$SER service is running"

else

echo "$SER service is down"

fi

##方法二

[root@centos7 ~]# vim httpd.sh

#!/bin/bash

SER2=httpd

systemctl status $SER2 &> /dev/null

if [ $? -eq 0 ]

then

echo "$SER2 is running"

else

echo "$SER2 is not running"

fi

[root@centos7 ~]# chmod +x httpd.sh

[root@centos7 ~]# ./httpd.sh

httpd is running

##方法三:

[root@centos7 ~]# vim http1.sh

#!/bin/bash

if systemctl status httpd &> /dev/null

then

echo "service is running"

else

echo "service is down"

fi

[root@centos7 ~]# ./http1.sh

service is running

多分支

if 条件表达式

then

命令

elif 条件表达式

then

命令

else

命令

fi

shell脚本

发送邮件

 

dnf -y install postfix s-nail

vim /etc/s-nail.rc

#在文件最后添加

set from=295255180@qq.com #你的邮箱

set smtp=smtp.qq.com

set smtp-auth-user=295255180@qq.com #你的邮箱

set smtp-auth-password=gostoxmhcmkzcabb #你的邮箱授权码

set smtp-auth=login

#发送测试邮件

echo "123" | mail -s hihh 你的收件邮箱地址

#发送时候会报错,因为是老版本的写法,但是可以正常用

 

shell脚本

循环语句

循环for

for 变量名 in 取值列表

do

命令

done

示例:

#!/bin/bash

for i in {1..3}

do

echo $i

done

for 的语法也可以这么写:

#!/bin/bash

for i in "$@" # $@是将位置参数作为单个来处理

{

echo $i

}

# bash test.sh 1 2 3

1

2

3

默认 for 循环的取值列表是以空白符分隔,即系统变量里的$IFS:

#!/bin/bash

for i in 12 34

do

echo $i

done

# bash test.sh

12

34

以命令结果作为列表

#!/bin/bash

for file in $(ls) 这里可以写成`ls`

do

echo $file

done

如果想指定分隔符,可以重新赋值$IFS 变量:

#!/bin/bash

OLD_IFS=$IFS

IFS=":"

for i in $(head -1 /etc/passwd)

do

echo $i

done

IFS=$OLD_IFS # 恢复默认值

# bash test.sh

root

x

00

root

/root

/bin/bash

for 循环还有一种 C 语言风格的语法,常用于计数、打印数字序列:for (( expr1 ; expr2 ; expr3 )) ; do list ;done

#!/bin/bash

for ((i=1;i<=5;i++)) # 也可以 i--

do

echo $i

done

例:

for ((zf=1;zf<10;zf=zf+2))

do

echo $zf

done

#!/bin/bash

for var in {1..9..2}

do

echo $var

done

这种叫做for语句的步长,也就是循环变量每次增加的值都是相同数值的时候使用

示例 1:检查多个主机是否存活

#!/bin/bash

for ip in 192.168.1.{1..254}

do

if ping -c 1 $ip >/dev/null

then

echo "$ip OK."

else

echo "$ip NO!"

fi

done

 

示例2:99乘法表

#!/bin/bash

for((i=1;i<10;i=i+1)) ##可以写成i=i+1或者i++

do

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

do

echo -n -e " $i*$jt"

done

echo " "

done

#!/bin/bash

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

do

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

do

let "s=i*j"

echo -ne "$j*$i=$st"

done

echo ""

done

 

示例3:例计算1+2+3....+100的值。

#!/bin/bash

sum=0

for bl in {1..100}

do

let sum=sum+$bl

done

echo $sum

 

示例4:计算1+3+5+。。到100的值,间隔2

#!/bin/bash

sum=0

for bl in {1..100..2}

do

let sum=sum+$bl

done

echo $sum

 

示例5:从列表文件中读取多个用户名,然后为其逐一创建用户账户并设置密码。首先创建用户名称的列表文件users.txt,每个用户名称单独一行。

vim users.txt

harry

jack

marry

angle

bob

[root@zhong ~]# vim creteuser.sh

#!/bin/bash

read -p "Enter The Users Password : " PASSWD

for UNAME in `cat users.txt`

do

id $UNAME &> /dev/null

if [ $? -eq 0 ]

then

echo "Already exists"

else

useradd $UNAME &> /dev/null

echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null

if [ $? -eq 0 ]

then

echo "$UNAME , Create success"

else

echo "$UNAME , Create failure"

fi

fi

done

 

示例6:让脚本从文本中自动读取主机列表,然后自动逐个测试这些主机是否在线。

[root@zhong ~]# vim ipadds.txt

192.168.1.10

192.168.1.11

192.168.1.12

[root@zhong ~]# vim checkhosts.sh

#!/bin/bash

HLIST=$(cat ~/ipadds.txt)

for IP in $HLIST

do

ping -c 3 -i 0.2 -W 3 $IP &> /dev/null

if [ $? -eq 0 ]

then

echo "Host $IP is On-line."

else

echo "Host $IP is Off-line."

fi

done

 

示例7:面试题,计算1+2+3+...+100 的结果

[root@centos8 ~]#sum=0;for i in {1..100};do let sum+=i;done ;echo sum=$sum

sum=5050

[root@centos8 ~]#seq -s+ 100|bc5050

5050

[root@centos8 ~]#echo {1..100}|tr ' ' +|bc

5050

[root@centos8 ~]#seq 100|paste -sd +|bc

5050

 

示例8: 100以内的奇数之和

[root@centos8 ~]#sum=0;for i in {1..100..2};do let sum+=i;done;echo sum=$sum

sum=2500

[root@centos8 ~]#seq -s+ 1 2 100| bc

2500

[root@centos8 ~]#echo {1..100..2}|tr ' ' + | bc

2500

 

示例9: 批量创建用户

[root@centos8 ~]#cat createuser.sh

#!/bin/bash

[ $# -eq 0 ] && { echo "Usage: createuser.sh USERNAME ..." ;exit 1 ; }

for user ;do

id $user &> /dev/null && echo $user is exist || { useradd $user ; echo

$user

is created; }

done

 

示例10: 批量创建用户和并设置随机密码

[root@centos8 script]#cat user_for.sh

#!/bin/bash

for i in {1..10};do

useradd user$i

PASS=`cat /dev/urandom | tr -dc '[:alnum:]' |head -c12`

echo $PASS | passwd --stdin user$i &> /dev/null

echo user$i:$PASS >> /data/user.log

echo "user$i is created"

done

 

示例11: 九九乘法表

[root@centos8 script]#cat 9x9_for.sh

#!/bin/bash

for i in {1..9};do

for j in `seq $i`;do

echo -e "${j}x${i}=$[j*i]tc"

done

echo

done

 

示例12:99乘法表实现过程

#思路

步骤一:

99乘法表中开始为1x1=1,最后的值为 9x9=81,所以需要两个变量i,j。且i和j的值由1都变为i,并

且做了乘法运算。

#!/bin/bash

#99

for i in {1..9}

do

for j in {1..9}

do

echo "$i*$j=$[i*j]"

done

done

#执行结果,不是我们想要的。首先运算结果上有很多冗余数据,其次显示视图不符合要求

 

步骤二:删除冗余数据

分析可知,冗余数据出现在每次i都循环了9次。如果使得j<=i时,便不会出现冗余数据

#!/bin/bash

#99

for i in {1..9}

do

for j in {1..9}

do

if [ $j -le $i ];then

echo "$j*$i=$[i*j]"

fi

done

done

由执行结果可以看出,冗余数据已经被删除。但是结果并未分为9行。

#步骤三:分行处理,只需要在内层循环结束时,输出一个空行。

#!/bin/bash

#99

for i in {1..9}

do

for j in {1..9}

do

if [ $j -le $i ];then

echo "$j*$i=$[i*j]"

fi

done

echo

done

 

由图可知,目前分行已经基本ok,但是我们希望每一列数能单独在一行,而不是分为好几行。

#步骤四:取消每次循环换行 echo -n

#!/bin/bash

#99

for i in {1..9}

do

for j in {1..9}

do

if [ $j -le $i ];then

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

fi

done

echo

done

 

由图可知,基本上已经实现了我们的需求。但是看起来仍不太美观。

#步骤五:echo -e t。加入制表符,使结果更加美观。空格也可以,但是会出现不能对齐的效果

#!/bin/bash

#99

for i in {1..9}

do

for j in {1..9}

do

if [ $j -le $i ];then

echo -n -e "$j*$i=$[i*j]t"

fi

done

echo

done