11.1 script 的编写与执行
shell script 其实就是纯文本档,我们可以编辑这个文件,然后让这个文件来帮我们一次执行多个指令,或者是利用一些运算与逻辑判断来帮我们达成某些功能。所以,要编辑这个文件的内容时,当然就需要具备有 bash 指令下达的相关认识。
- 注意事项:
- 指令的执行是从上而下、从左而右的分析与执行;
- 指令的下达就如同第四章内提到的: 指令、选项与参数间的多个空白都会被忽略掉;
- 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空格键;
- 如果读取到一个 Enter 符号 (CR) ,就尝试开始执行该行 (或该串) 命令;
- 至于如果一行的内容太多,则可以使用『 [Enter] 』来延伸至下一行;
- 『 # 』可做为批注!任何加在 # 后面的资料将全部被视为批注文字而被忽略!
如此一来,我们在 script 内所撰写的程序,就会被一行一行的执行。现在我们假设你写的这个程序 文件名是 /home/xiaoqi/shell.sh 那如何执行这个文件?有底下几个方法:
- 直接指令下达: shell.sh 文件必须要具备可读与可执行 (rx) 的权限,然后:
- 绝对路径:使用 /home/dmtsai/shell.sh 来下达指令;
- 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来执行
- 变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/
- 以 bash 程序来执行:透过『 bash shell.sh 』或『 sh shell.sh 』来执行
由于 CentOS 默认用户家目录下的 ~/bin 目录会被设定到 ${PATH} 内,所以你也可以将 shell.sh 建立在 /home/xiaoqi/bin/ 底下 ( ~/bin 目录需要自行设定) 。此时,若 shell.sh 在 ~/bin 内且具有 rx 的权限, 那就直接输入 shell.sh 即可执行该脚本程序!
- 那为何sh shell.sh也可以执行呢?
这是因为 /bin/sh 其实就是 /bin/bash (连结档),使用 sh shell.sh 亦即告诉系统,我想要直接以 bash 的功能来执行 shell.sh 这个文件内的相关指令的意思,所以此时 你的 shell.sh 只要有 r 的权限即可被执行喔!而我们也可以利用 sh 的参数,如 -n 及 -x 来检查与 追踪 shell.sh 的语法是否正确!
11.2 shell写hello world
[xiaoqi@study bin]$ mkdir bin;cd bin
[xiaoqi@study bin]$ vim hello.sh
#!/bin/bash
#Program:
#! This progeam shows "Hello World" in your screen.
#History
#2019/08/25 xiaoqi First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World \a \n"
exit 0
请将所有编写的 script 放置到你家目录的 ~/bin 这个目录内,以后比较好管理!
- 整个程序的撰写分成数段,大致是这样:
- 第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称:
因为我们使用的是 bash ,所以,必须要以『 #!/bin/bash 』来宣告这个文件内的语法使用 bash 的语法! 那么当这个程序被执行时,他就能够加载 bash 的相关环境配置文件 (一般来说就是 non-login shell 的 ~/.bashrc), 并且执行 bash 来使我们底下的指令能够执行!这很重要的!(在很多状况中,如果没有设定好 这一行, 那么该程序很可能会无法执行,因为系统可能无法判断该程序需要使用什么 shell 来执行!
- 程序内容的说明:
整个 script 当中,除了第一行的『 #! 』是用来宣告 shell 的之外,其他的 # 都是『批注』用途! 所以 上面的程序当中,第二行以下就是用来说明整个程序的基本数据。一般来说, 建议你一定要养成说明该 script 的:1. 内容与功能; 2. 版本信息; 3. 作者与联络方式; 4. 建立日期;5. 历史纪录 等等。这将有助于未来程序的改写与 debug !
- 主要环境变量的宣告:
建议务必要将一些重要的环境变量设定好,个人认为,PATH 与 LANG (如果有使用到输出相关的信息时) 是当中最重要的!如此一来,则可让我们这支程序在进行时,可以直接下达一些外部指令,而不必 写绝对路径!
- 主要程序部分
就将主要的程序写好即可!在这个例子当中,就是 echo 那一行!
- 执行成果告知 (定义回传值)
是否还记得之前讨论一个指令的执行成功与否,可以使用 $? 这个变量来观察~ 那么我们也可以利用 exit 这个指令来让程序中断,并且回传一个数值给系统。在我们这个例子当中,使用 exit 0 ,这代表离开 script 并且回传一个 0 给系统,所以我执行完这个 script 后,若接着下达 echo $? 则可得到 0 的值!利用这个 exit n (n 是数字) 的功能,我们还可以自定义错误讯息!
练习简单的shell
利用 date 进行文件的建立
假设我的服务器内有数据库,数据库每天的数据都不太一样,因此当我备份时,希望将每天的资料都备份成不同的档名, 这样才能够让旧的数据也能够保存下来不被覆盖。
所以我可以将档名取成类似: backup.2019-08-16.data ,不就可以每天一个不同档名了吗?那个 2019-08-28 怎么来的?那就是重点啦!接下来出个相关的例子:
假设我想要建立三个空的文件 (透过 touch) ,档名最开头由使用者输入决定, 假设使用者输入 filename 好了,那今天的日期是 2019-08-28 , 我想要以前天、昨天、今天的日期 来建立这些文件,亦即 filename_20190528, filename_20190527, filename_20190526 ,该如何建立呢?
[root@study xiaoqi]# vim create_3_filename.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#1. 让使用者输入文件名,并取得filename这个变量
echo -e "I will use 'touch' command to create 3 files."
read -p "Please input your filename: " fileuser
#2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有设定
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里头预设仅支持到整数的数据而已。
[root@study xiaoqi]# vim multiplying.sh
#!/bin/bash
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} = ${total}"
在数值的运算上,我们可以使用『 declare -i total=${firstnu}*${secnu} 』 也可以使用上面的方式来进行!
比较建议使用这样的方式来进行运算:var=$((运算内容))
不但容易记忆,而且也比较方便的多,因为两个小括号内可以加上空格符.
至于数值运算上的处理,则有:『 +, -, *, /, % 』等等。 那个 % 是取余数!
另外,如果你想要计算含有小数点的数据时,其实可以透过 bc 这个指令的协助喔!例如可以这样做:
[root@study xiaoqi]# echo "12.2*4.33" | bc
52.82
透过 bc 计算 pi
其实计算 pi 时,小数点以下位数可以无限制的延伸下去!而 bc 有提供一个运算 pi 的函式,只是 想要使用该函式必须要使用 bc -l 来使用.也因为这个小数点以下位数可以无线延伸运算的特性存在,所以我们可以透过底下这只小脚本来让使用者输入一个『小数点为数值』, 以让 pi 能够更准确!
[root@study xiaoqi]# vim cal_pi.sh
#!/bim/bash
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 要被计算的越精确,当然用掉的时间就会越多!
11.3 script 的执行方式差异 (source, sh script, ./script)
不同的 script 执行方式会造成不一样的结果喔!尤其影响 bash 的环境很大呢!脚本的执行方式除了 前面小节谈到的方式之外,还可以利用 source 或小数点 (.) 来执行.那么这种执行方式有何不同呢?
利用直接执行的方式来执行 script
当使用前一小节提到的直接指令下达 (不论是绝对路径/相对路径还是 ${PATH} 内),或者是利用 bash (或 sh) 来下达脚本时,该 script 都会使用一个新的 bash 环境来执行脚本内的指令!也就是 说,使用这种执行方式时, 其实 script 是在子程序的 bash 内执行的!我们在第十章 BASH 内谈 到 export 的功能时,曾经就父程序/子程序谈过一些概念性的问题, 重点在于:『当子程序完成后, 在子程序内的各项变量或动作将会结束而不会传回到父程序中』!这是什么意思呢?
我们举刚刚提到过的 showname.sh 这个脚本来说明好了,这个脚本可以让用户自行设定两个变量, 分别是 firstname 与 lastname,想一想,如果你直接执行该指令时,该指令帮你设定的 firstname 会 不会生效?看一下底下的执行结果:
[root@study xiaoqi]# echo ${firstname} ${lastname}
<--变量不存在
[root@study xiaoqi]# sh showname.sh
Please input your first name: xiao
Please input your second name: qi
You Full name is : xiaoqi <--在 script 运作中,这两个变量有生效
[root@study xiaoqi]# echo ${firstname} ${secname}
<--事实上,这两个变量在父程序的 bash 中还是不存在的!
上面的结果你应该会觉得很奇怪,怎么我已经利用 showname.sh 设定好的变量竟然在 bash 环境底下无效!怎么回事呢?
如果将程序相关性绘制成图的话,我们以下图来说明。当你使用直接执行的 方法来处理时,系统会给予一支新的 bash 让我们来执行 showname.sh 里面的指令,因此你的 firstname, lastname 等变量其实是在下图中的子程序 bash 内执行的。当 showname.sh 执行完毕后, 子程序 bash 内的所有数据便被移除,因此上表的练习中,在父程序底下 echo ${firstname} 时,就利用 source 来执行脚本:在父程序中执行如果你使用 source 来执行指令那就不一样了!同样的脚本我们来执行看看:看不到任何东西了!
利用 source 来执行脚本:在父程序中执行
如果你使用 source 来执行指令那就不一样了!同样的脚本我们来执行看看:
[root@study xiaoqi]#
[root@study xiaoqi]# source showname.sh
Please input your first name: xiao
Please input your second name: qi
You Full name is : xiaoqi
[root@study xiaoqi]# echo ${firstname} ${secname}
xiao qi <--变量有内容
竟然生效了!没错!因为 source 对 script 的执行方式可以使用底下的图示来说明! showname.sh 会在父程序中执行的,因此各项动作都会在原本的 bash 内生效!这也是为啥你不注销系统而要让某 些写入 ~/.bashrc 的设定生效时,需要使用source ~/.bashrc
而不能使用bash ~/.bashrc
是一样的!
11.4 善用判断式
在上一章中,我们提到过 $? 这个变量所代表的意义, 此外,也透过 && 及 || 来作为前一个指令执 行回传值对于后一个指令是否要进行的依据。如果想要判断一个目录是否存在, 当 时我们使用的是 ls 这个指令搭配数据流重导向,最后配合 $? 来决定后续的指令进行与否。 但是 否有更简单的方式可以来进行『条件判断』呢?有的~那就是『 test 』这个指令。
11.4.1 利用 test 指令的测试功能
当我要检测系统上面某些文件或者是相关的属性时,利用 test 这个指令来工作真是好用得不得了, 举例来说,我要检查 /dmtsai 是否存在时,使用:
[root@study xiaoqi]# test -e /root/
执行结果并不会显示任何讯息,但最后我们可以透过 $? 或 && 及 || 来展现整个结果呢! 例如我 们在将上面的例子改写成这样:
[root@study xiaoqi]# test -e /xiaoqi && echo "exist" || echo "Not exist"
Not exist <--结果输出不存在
最终的结果可以告知我们是『exist』还是『Not exist』呢!那我知道 -e 是测试一个『东西』在不在, 如果还想要测试一下该档名是啥玩意儿时,还有哪些标志可以来判断?有底下这些参数!
- 关于某个档名的『文件类型』判断,如 test -e filename 表示存在否
测试的标志 | 代表意义 |
---|---|
-e | 该『档名』是否存在?(常用) |
-f | 该『档名』是否存在且为文件(file)?(常用) |
-d | 该『文件名』是否存在且为目录(directory)?(常用) |
-b | 该『档名』是否存在且为一个 block device 装置? |
-c | 该『档名』是否存在且为一个 character device 装置? |
-S | 该『档名』是否存在且为一个 Socket 文件? |
-p | 该『档名』是否存在且为一个 FIFO (pipe) 文件? -L 该『档名』是否存在且为一个连结档? |
- 关于文件的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外)
测试的标志 | 代表意义 |
---|---|
-r | 侦测该档名是否存在且具有『可读』的权限? |
-w | 侦测该档名是否存在且具有『可写』的权限? |
-x | 侦测该档名是否存在且具有『可执行』的权限? |
-u | 侦测该文件名是否存在且具有『SUID』的属性? |
-g | 侦测该文件名是否存在且具有『SGID』的属性? |
-k | 侦测该文件名是否存在且具有『Sticky bit』的属性? |
-s | 侦测该档名是否存在且为『非空白文件』? |
- 两个文件之间的比较,如: test file1 -nt file2
测试的标志 | 代表意义 |
---|---|
-nt | (newer than)判断 file1 是否比 file2 新 |
-ot | (older than)判断 file1 是否比 file2 旧 |
-ef | 判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判定,两个文件是否均指向同一个 inode ! |
- 关于两个整数之间的判定,例如 test n1 -eq n2
测试的标志 | 代表意义 |
---|---|
-eq | 两数值相等 (equal) |
-ne | 两数值不等 (not equal) |
-gt | n1 大于 n2 (greater than) |
-lt | n1 小于 n2 (less than) |
-ge | n1 大于等于 n2 (greater than or equal) |
-le | n1 小于等于 n2 (less than or equal) |
- 判定字符串的数据
测试的标志 | 代表意义 |
---|---|
test -z string | 判定字符串是否为 0 ?若 string 为空字符串,则为 true |
test -n string | 判定字符串是否非为 0 ?若 string 为空字符串,则为 false。 注: -n 亦可省略 |
test str1 == str2 | 判定 str1 是否等于 str2 ,若相等,则回传 true |
test str1 != str2 | 判定 str1 是否不等于 str2 ,若相等,则回传 false |
- 多重条件判定,例如: test -r filename -a -x filename
测试的标志 | 代表意义 |
---|---|
-a | (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限 时,才回传 true。 |
-o | (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时, 就可回传 true。 |
! | 反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true |
- 现在我们就利用 test 来帮我们写几个简单的例子。首先,判断一下,让使用者输入一个档名, 我们判断:
- 这个文件是否存在,若不存在则给予一个『Filename does not exist』的讯息,并中断程序;
- 若这个文件存在,则判断他是个文件或目录,结果输出『Filename is regular file』或 『Filename is directory』
- 判断一下,执行者的身份对这个文件或目录所拥有的权限,并输出权限数据!
[root@study xiaoqi]# cat file_perm.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#1. 让使用者输入文件名,并且判断使用者是否真的有输入字符串?
echo -e "Please input a filename, I will check the filename's type and permission. \n\n"
read -p "Input a filename : " filename
test -z ${filename} && echo "You MUST input a filename." && exit 0
#2. 判断文件是否存在?若不存在则显示讯息并结束脚本
test ! -e ${filename} && echo "The filename '${filename}' DO NOT exist" && exit 0
#3. 开始判断文件类型与属性
test -f ${filename} && filetype="regulare file"
test -d ${filename} && filetype="directory"
test -r ${filename} && perm="readable"
test -w ${filename} && perm="${perm} writable"
test -x ${filename} && perm="${perm} executable"
#4. 开始输出信息!
echo "The filename: ${filename} is a ${filetype}"
echo "And the permissions for you are : ${perm}"
如果你执行这个脚本后,他会依据你输入的档名来进行检查喔!先看是否存在,再看为文件或目录类 型,最后判断权限。 但是你必须要注意的是,由于 root 在很多权限的限制上面都是无效的,所以 使用 root 执行这个脚本时, 常常会发现与 ls -l 观察到的结果并不相同!所以,建议使用一般使用 者来执行这个脚本试看看。
11.4.2 利用判断符号 [ ]
除了我们很喜欢使用的 test 之外,其实,我们还可以利用判断符号『 [ ] 』(就是中括号啦) 来进行 数据的判断呢! 举例来说,如果我想要知道 ${HOME} 这个变量是否为空的,可以这样做:
[xiaoqi@study ~]$ [ -z "${HOME}" ] ; echo $?
1
使用中括号必须要特别注意,因为中括号用在很多地方,包括通配符与正规表示法等等,所以如果要 在 bash 的语法当中使用中括号作为 shell 的判断式时,必须要注意中括号的两端需要有空格符来分 隔喔! 假设我空格键使用『□』符号来表示,那么,在这些地方你都需要有空格键:
[ "$HOME" == "$MAIL" ]
[□"$HOME"□==□"$MAIL"□]
↑ ↑ ↑ ↑
你会发现在上面的判断式当中使用了两个等号『 == 』。其实在 bash 当中使用一个等号与两个等号的结果是一样的! 不过在一般惯用程序的写法中,一个等号代表『变量的设定』,两个等号则是 代表『逻辑判断 (是与否之意)』。 由于我们在中括号内重点在于『判断』而非『设定变量』,因此建议还是 使用两个等号较佳!
上面的例子在说明,两个字符串 ${HOME} 与 ${MAIL} 是否相同的意思,相当于 test ${HOME} == ${MAIL} 的意思啦! 而如果没有空白分隔,例如 [${HOME}==${MAIL}] 时,我们的 bash 就会显 示错误讯息了!这可要很注意啊! 所以说,你最好要注意:
- 在中括号 [] 内的每个组件都需要有空格键来分隔;
- 在中括号内的变数,最好都以双引号括号起来;
- 在中括号内的常数,最好都以单或双引号括号起来。
为什么要这么麻烦啊?直接举例来说,假如我设定了 name="VBird Tsai" ,然后这样判定:
[root@study xiaoqi]# [ ${name} == "Vbird" ]
bash: [: 参数太多
怎么会发生错误?bash 还跟我说错误是由于『太多参数 (arguments)』所致! 为什么呢? 因为 ${name} 如果没有使用双引号刮起来,那么上面的判定式会变成:
[ VBird Tsai == "VBird" ]
上面这个是错的.因为一个判断式仅能有两个数据的比对,上面 VBird 与 Tsai 还有 "VBird" 就有 三个资料! 这不是我们要的!我们要的应该是底下这个样子:
[ "VBird Tsai" == "VBird" ]
这可是差很多的喔!另外,中括号的使用方法与 test 几乎一模一样啊~ 只是中括号比较常用在条件 判断式 if ..... then ..... fi 的情况中就是了。
那我们也使用中括号的判断来做一个小案例好了,案 例设定如下:
- 当执行一个程序的时候,这个程序会让用户选择 Y 或 N ,
- 如果用户输入 Y 或 y 时,就显示『 OK, continue 』
- 如果用户输入 n 或 N 时,就显示『 Oh, interrupt !』
- 如果不是 Y/y/N/n 之内的其他字符,就显示『 I don't know what your choice is 』
利用中括号、 && 与 || 来完成!
[root@study xiaoqi]# vim ans_yn.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input (Y/N): " yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK, continue" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "Oh, interrupt!" && exit 0
echo "I don't know what your choice is" && exit 0
由于输入正确 (Yes) 的方法有大小写之分,不论输入大写 Y 或小写 y 都是可以的,此时判断式内 就得要有两个判断才行! 由于是任何一个成立即可 (大写或小写的 y) ,所以这里使用 -o (或) 连结 两个判断!利用这个字符串判别的方法,我们就可以很轻松的将使用者想要进行的工作分门别类!
11.4.3Shell script的默认变量($0, $1...)
我们知道指令可以带有选项与参数,例如 ls -la 可以察看包含隐藏文件的所有属性与权限。那么 shell script 能不能在脚本档名后面带有参数呢?
举例来说,如果你想要重新启动系统的网络,可以这样做:
[root@study xiaoqi]# file /etc/init.d/network
/etc/init.d/network: Bourne-Again shell script, ASCII text executable
#使用 file 来查询后,系统告知这个文件是个 bash 的可执行 script !
[root@study xiaoqi]# /etc/init.d/network restart
Restarting network (via systemctl): [ 确定 ]
restart 是重新启动的意思,上面的指令可以『重新启动 /etc/init.d/network 这个程序』
那么如果你在 /etc/init.d/network 后面加上 stop 呢?就可以直接关闭该服务了!
如果你要依据程序的执行给予一些变量去进行不同的任务时,本章一开始是使用 read 的功 能!但 read 功能的问题是你得要手动由键盘输入一些判断式。如果透过指令后面接参数, 那么一个指令就能够处理完毕而不需要手动再次输入一些变量行为!这样下达指令会比较简单方便啦!
script 是怎么达成这个功能的呢?其实 script 针对参数已经有设定好一些变量名称了!对应如下:
/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4
执行的脚本档名为 $0 这个变量,第一个接的参数就是 $1 所以,只要我们 在 script 里面善用 $1 的话,就可以很简单的立即下达某些指令功能了!
了这些数字的变量之外, 我们还有一些较为特殊的变量可以在 script 内使用来呼叫这些参数!
- $# :代表后接的参数『个数』,以上表为例这里显示为『 4 』;
- $@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
- $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字符,默认为空格键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
那个 $@ 与 $* 基本上还是有所不同啦!不过,一般使用情况下可以直接记忆 $@ 即可!
来做个例子吧~假设我要执行一个可以携带参数的 script ,执行该脚本后屏幕会显示如下的数据:
- 程序的文件名为何?
- 共有几个参数?
- 若参数的个数小于 2 则告知使用者参数数量太少
- 全部的参数内容为何?
- 第一个参数为何?
- 第二个参数为何
[root@study xiaoqi]# vim how_paras.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "The script name is ==> ${0}"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0
echo "Your whole parameter is ==> '$@'"
echo "The 1st parameter ==> ${1}"
echo "The 2nd parameter ==> ${2}"
执行结果:
[root@study xiaoqi]# sh how_paras.sh theone haha quit
The script name is ==> how_paras.sh <--文件名
Total parameter number is ==> 3 <--传入的3个参数
Your whole parameter is ==> 'theone haha quit' <--传入的全部参数
The 1st parameter ==> theone <--第一个参数
The 2nd parameter ==> haha <--第二个参数
- shift:造成参数变量号码的便宜
除此之外,脚本后面所接的变量是否能够进行偏移 (shift) 呢?我们直接以底下的范 例来说明好了, 用范例说明比较好解释!我们将 how_paras.sh 的内容稍作变化一下,用来显示每次 偏移后参数的变化情况:
[root@study xiaoqi]# cat shift_paras.sh
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
shift # 进行第一次『一个变量的 shift 』
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
shift 3 # 进行第二次『三个变量的 shift 』
echo "Total parameter number is ==> $#"
echo "Your whole parameter is ==> '$@'"
执行结果:
[root@study xiaoqi]# sh shift_paras.sh one two three four five six <--给予的六个参数
Total parameter number is ==> 6 <--最原始的参数变量情况
Your whole parameter is ==> 'one two three four five six'
Total parameter number is ==> 5 <--第一次偏移,看地下发现第一个one不见了
Your whole parameter is ==> 'two three four five six'
Total parameter number is ==> 2 <--第二次便宜掉三个 two three four 不见了
Your whole parameter is ==> 'five six'
光看结果你就可以知道啦,那个 shift 会移动变量,而且 shift 后面可以接数字,代表拿掉最前面的 几个参数的意思。 上面的执行结果中,第一次进行 shift 后他的显示情况是『 one two three four five six』,所以就剩下五个啦!第二次直接拿掉三个,就变成『 two three four five six 』
版权属于:龙之介大人
本文链接:https://i7dom.cn/167/2019/28/linux-bash-shell-04.html
本站所有原创文章采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 您可以自由的转载和修改,但请务必注明文章来源和作者署名并说明文章非原创且不可用于商业目的。