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"
  1. 这个档案是否存在,若不存在则给予一个『Filename does not exist』的讯息,并中断程序;
  2. 若这个档案存在,则判断他是个档案或目录,结果输出『Filename is regular file』或
    『Filename is directory』
  3. 判断一下,执行者的身份对这个档案或目录所拥有的权限,并输出权限数据!
#!/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" ]

  1. 当执行一个程序的时候,这个程序会让用户选择 Y 或 N ,
  2. 如果用户输入 Y 或 y 时,就显示『 OK, continue 』
  3. 如果用户输入 n 或 N 时,就显示『 Oh, interrupt !』
  4. 如果不是 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. 判断 $1 是否为 hello,如果是的话,就显示 "Hello, how are you ?";
  2. 如果没有加任何参数,就提示使用者必须要使用的参数下达法;
  3. 而如果加入的参数不是 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
posted @ 2020-12-31 11:14  告一段落  阅读(190)  评论(0编辑  收藏  举报