鸟哥的 Linux 私房菜Shell Scripts篇(二)

 

参考:

http://linux.vbird.org/linux_basic/0340bashshell-scripts.php#script_be

http://www.runoob.com/linux/linux-tutorial.html

12.2 简单的 shell script 练习

在第一支 shell script 撰写完毕之后,相信你应该具有基本的撰写功力了。接下来,在开始更
深入的程序概念之前,我们先来玩一些简单的小范例好了。 下面的范例中,达成结果的方式
相当的多,建议你先自行撰写看看,写完之后再与鸟哥写的内容比对, 这样才能更加深概念
喔!好!不?唆,我们就一个一个来玩吧!

12.2.1 简单范例

下面的范例在很多的脚本程序中都会用到,而下面的范例又都很简单!值得参考看看喔!
对谈式脚本:变量内容由使用者决定
很多时候我们需要使用者输入一些内容,好让程序可以顺利运行。 简单的来说,大家应该都
有安装过软件的经验,安装的时候,他不是会问你“要安装到那个目录去”吗? 那个让使用者
输入数据的动作,就是让使用者输入变量内容啦。
你应该还记得在十章 bash 的时候,我们有学到一个 read 指令吧?现在,请你以 read 指令的
用途,撰写一个 script ,他可以让使用者输入:1. first name 与 2. last name, 最后并且在屏
幕上显示:“Your full name is: ”的内容:
[dmtsai@study bin]$ vim showname.sh
#!/bin/bash
# Program:
# User inputs his first name and last name. Program shows his full name.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input your first name: " firstname # 提示使用者输入
read -p "Please input your last name: " lastname # 提示使用者输入
echo -e "\nYour full name is: ${firstname} ${lastname}" # 结果由屏幕输出

将上面这个 showname.sh 执行一下,你就能够发现使用者自己输入的变量可以让程序所取
用,并且将他显示到屏幕上! 接下来,如果想要制作一个每次执行都会依据不同的日期而变
化结果的脚本呢?

随日期变化:

利用 date 进行文件的创建想像一个状况,假设我的服务器内有数据库,数据库每天的数据都不太一样,因此当我备份
时,希望将每天的数据都备份成不同的文件名, 这样才能够让旧的数据也能够保存下来不被
覆盖。哇!不同文件名呢!这真困扰啊?难道要我每天去修改 script ?
不需要啊!考虑每天的“日期”并不相同,所以我可以将文件名取成类似: backup.2015-07-
16.data , 不就可以每天一个不同文件名了吗?呵呵!确实如此。那个 2015-07-16 怎么来
的?那就是重点啦!接下来出个相关的例子: 假设我想要创建三个空的文件 (通过 touch)
文件名最开头由使用者输入决定,假设使用者输入 filename 好了,那今天的日期是
2015/07/16 , 我想要以前天、昨天、今天的日期来创建这些文件,亦即 filename_20150714,
filename_20150715, filename_20150716 ,该如何是好?
[dmtsai@study bin]$ vim create_3_filename.sh
#!/bin/bash
# Program:
# Program creates three files, which named by user's input and date command.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 1\. 让使用者输入文件名称,并取得 fileuser 这个变量;
echo -e "I will use 'touch' command to create 3 files." # 纯粹显示信息
read -p "Please input your filename: " fileuser # 提示使用者输入
# 2\. 为了避免使用者随意按 Enter ,利用[变量功能](../Text/index.html#variable_other_re)分析文件名是否有设置?
filename=${fileuser:-"filename"} # 开始判断有否配置文件名
# 3\. 开始利用 date 指令来取得所需要的文件名了;
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}
# 4\. 将文件名创建吧!
touch "${file1}" # 下面三行在创建文件
touch "${file2}"
touch "${file3}"

 

上面的范例鸟哥使用了很多在第十章介绍过的概念: 包括小指令“ $(command) ”的取得讯
息、变量的设置功能、变量的累加以及利用 touch 指令辅助! 如果你开始执行这个
create_3_filename.sh 之后,你可以进行两次执行:一次直接按 [Enter] 来查阅文件名是啥?
一次可以输入一些字符,

数值运算:简单的加减乘除


各位看官应该还记得,我们可以使用 declare 来定义变量的类型吧? 当变量定义成为整数后
才能够进行加减运算啊!此外,我们也可以利用“ $((计算式)) ”来进行数值运算的。 可
惜的是, bash shell 里头默认仅支持到整数的数据而已。OK!那我们来玩玩看,如果我们要
使用者输入两个变量, 然后将两个变量的内容相乘,最后输出相乘的结果,那可以怎么做?
[dmtsai@study bin]$ vim multiplying.sh
#!/bin/bash
# Program:
# User inputs 2 integer numbers; program will cross these two numbers.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "You SHOULD input 2 numbers, I will multiplying 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}"

在数值的运算上,我们可以使用“ declare -i total=${firstnu}*${secnu} ” 也可以使用上面的方式
来进行!基本上,鸟哥比较建议使用这样的方式来进行运算:
var=$((运算内容))
不但容易记忆,而且也比较方便的多,因为两个小括号内可以加上空白字符喔! 未来你可以
使用这种方式来计算的呀!至于数值运算上的处理,则有:“ +, -, , /, % ”等等。 那个 % 是取
余数啦~举例来说, 13 对 3 取余数,结果是 13=43+1,所以余数是 1 啊!就是:
[dmtsai@study bin]$ echo $(( 13 % 3 ))
1
这样了解了吧?另外,如果你想要计算含有小数点的数据时,其实可以通过 bc 这个指令的协
助喔! 例如可以这样做:
[dmtsai@study bin]$ echo "123.123*55.9" |  bc
6882.575
了解了 bc 的妙用之后,来让我们测试一下如何计算 pi 这个东西呢?
数值运算:通过 bc 计算 pi
其实计算 pi 时,小数点以下位数可以无限制的延伸下去!而 bc 有提供一个运算 pi 的函数,
只是想要使用该函数必须要使用 bc -l 来调用才行。 也因为这个小数点以下位数可以无线延伸
运算的特性存在,所以我们可以通过下面这只小脚本来让使用者输入一个“小数点为数值”,
以让 pi 能够更准确!
[dmtsai@study bin]$ vim cal_pi.sh
#!/bin/bash
# Program:
# User input a scale number to calculate pi number.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "This program will calculate pi value. \n"
echo -e "You should input a float number to calculate pi value.\n"
read -p "The scale number (10~10000) ? " checking
num=${checking:-"10"} # 开始判断有否有输入数值
echo -e "Starting calcuate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq

 

上述数据中,那个 4*a(1) 是 bc 主动提供的一个计算 pi 的函数,至于 scale 就是要 bc 计
算几个小数点下位数的意思。当 scale 的数值越大, 代表 pi 要被计算的越精确,当然用掉的
时间就会越多!因此,你可以尝试输入不同的数值看看!不过,最好是不要超过 5000 啦!因
为会算很久! 如果你要让你的 CPU 随时保持在高负载,这个程序算下去你就会知道有多操
CPU ?! ^_^
Tips 鸟哥的实验室中,为了要确认虚拟机的效率问题,所以很多时候需要保持虚拟机在忙碌
的状态~鸟哥的学生就是丢这只程序进去系统跑! 但是将 scale 调高一些,那计算就得要花
比较多时间~用以达到我们需要 CPU 忙碌的状态喔!

这样可以判断你的脚本是否设计正确喔!

12.2.2 script 的執行方式差異 (source, sh script, ./script)

不同的 script 執行方式會造成不一樣的結果喔!尤其影響 bash 的環境很大呢!腳本的執行方式除了前面小節談到的方式之外,還可以利用 source 或小數點 (.) 來執行喔!那麼這種執行方式有何不同呢?當然是不同的啦!讓我們來說說!

  • 利用直接執行的方式來執行 script

當使用前一小節提到的直接指令下達 (不論是絕對路徑/相對路徑還是 ${PATH} 內),或者是利用 bash (或 sh) 來下達腳本時, 該 script 都會使用一個新的 bash 環境來執行腳本內的指令!也就是說,使用這種執行方式時, 其實 script 是在子程序的 bash 內執行的!我們在第十章 BASH 內談到 export 的功能時,曾經就父程序/子程序談過一些概念性的問題, 重點在於:『當子程序完成後,在子程序內的各項變數或動作將會結束而不會傳回到父程序中』! 這是什麼意思呢?

我們舉剛剛提到過的 showname.sh 這個腳本來說明好了,這個腳本可以讓使用者自行設定兩個變數,分別是 firstname 與 lastname,想一想,如果你直接執行該指令時,該指令幫你設定的 firstname 會不會生效?看一下底下的執行結果:

[dmtsai@study bin]$ echo ${firstname} ${lastname}
    <==確認了,這兩個變數並不存在喔!
[dmtsai@study bin]$ sh showname.sh
Please input your first name: VBird <==這個名字是鳥哥自己輸入的
Please input your last name:  Tsai 

Your full name is: VBird Tsai      <==看吧!在 script 運作中,這兩個變數有生效
[dmtsai@study bin]$ echo ${firstname} ${lastname}
    <==事實上,這兩個變數在父程序的 bash 中還是不存在的!

上面的結果你應該會覺得很奇怪,怎麼我已經利用 showname.sh 設定好的變數竟然在 bash 環境底下無效!怎麼回事呢? 如果將程序相關性繪製成圖的話,我們以下圖來說明。當你使用直接執行的方法來處理時,系統會給予一支新的 bash 讓我們來執行 showname.sh 裡面的指令,因此你的 firstname, lastname 等變數其實是在下圖中的子程序 bash 內執行的。 當 showname.sh 執行完畢後,子程序 bash 內的所有資料便被移除,因此上表的練習中,在父程序底下 echo ${firstname} 時, 就看不到任何東西了!這樣可以理解嗎?

showname.sh 在子程序當中運作的示意圖
圖12.2.1、showname.sh 在子程序當中運作的示意圖
  • 利用 source 來執行腳本:在父程序中執行

如果你使用 source 來執行指令那就不一樣了!同樣的腳本我們來執行看看:

[dmtsai@study bin]$ source showname.sh
Please input your first name: VBird
Please input your last name:  Tsai

Your full name is: VBird Tsai
[dmtsai@study bin]$ echo ${firstname} ${lastname}
VBird Tsai  <==嘿嘿!有資料產生喔!

竟然生效了!沒錯啊!因為 source 對 script 的執行方式可以使用底下的圖示來說明! showname.sh 會在父程序中執行的,因此各項動作都會在原本的 bash 內生效!這也是為啥你不登出系統而要讓某些寫入 ~/.bashrc 的設定生效時,需要使用『 source ~/.bashrc 』而不能使用『 bash ~/.bashrc 』是一樣的啊!

showname.sh 在父程序當中運作的示意圖
圖12.2.2、showname.sh 在父程序當中運作的示意圖

 

posted @ 2018-12-04 11:37  rockpile  阅读(453)  评论(0编辑  收藏  举报