【1.1】shell script入门
为了将减少每天重复的代码量,将每日例行的代码可以写入bash中。
一、Bash简介
shell script 是利用 shell 的功能所写的一个『程序 (program)』,这个程序是使用纯文本文件,将一些shell 的语法与指令(含外部指令)写在里面, 搭配正规表示法、管线命令与数据流重导向等功能,以达到我们所想要的处理目的
shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为Shell scripts 的速度较慢,且使用的 CPU 资源较多,造成主机资源的分配不良。
在 shell script 的撰写中还需要用到底下的注意事项:
- 指令的执行是从上而下、从左而右的分析与执行;
- 指令、选项与参数间的多个空白都会被忽略掉;
- 空白行也将被忽略掉,并且 [tab] ****按键所推开的空白同样视为空格键;
- 如果读取到一个 Enter 符号
(CR)
,就尝试开始执行该行 (或该串) 命令; - 至于如果一行的内容太多,则可以使用
\[Enter]
来延伸至下一行; #
可做为批注!任何加在 # 后面的资料将全部被视为批注文字而被忽略!
命令的执行:
方法一:
直接指令下达: shell.sh 档案必须要具备可读与可执行 (rx) 的权限,然后:
绝对路径:使用 /home/dmtsai/shell.sh 来下达指令;
相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来执行
方法二:
变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/
以 bash 程序来执行:透过『 bash shell.sh 』或『 sh shell.sh 』来执行
注意:
**script **的执行方式差异 (source, sh script, ./script)
利用直接执行的方式来执行 script
利用 source 来执行脚本:在父程序中执行source ./script
意思就是说source后,脚本中的变量会写入终端,这个变量以后还保存,而其他的方式执行脚本后,脚本中的变量仅仅停留在这个脚本中。这也就是为什么修改环境变量后要source.
二、一个简单的例子
Hello.sh
#!/bin/bash
# This is a very simple example
echo Hello World
问题:
- 第一行的 #! 是什么意思
- 第一行的 /bin/bash 又是什么意思
- 第二行是注释吗
- echo 语句
- 如何执行该程序
在 BASH 中 第一行的 “#!” 及后面的 “/bin/bash” 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。
第二行的 “# This is a …” 就是 BASH 程序的注释,在 BASH 程序中从“#”号(注意:后面紧接着是“!”号的除外)开始到行尾的多有部分均被看作是程序的注释。
第三行的 echo 语句的功能是把 echo 后面的字符串输出到标准输出中去。由于 echo 后跟的是 “Hello World” 这个字符串,因此 “Hello World"这个字串就被显示在控制台终端的屏幕上了。
运行:
一种是显式制定 BASH 去执行:
$ bash hello.sh
方法二:
用/bin/bash 程序去解释执行 hello 文件的:
$ chmod u+x hello
$ ./hello.sh
三、详解
3.1输入和输出
在 Linux 系统中:标准输入(stdin)默认为键盘输入;标准输出(stdout)默认为屏幕输出;标准错误输出(stderr)默认也是输出到屏幕(上面的std 表示 standard)。在 BASH 中使用这些概念时一般将标准输出表示为 1,将标准错误输出表示为 2。
输入、输出及标准错误输出主要用于 I/O 的重定向,就是说需要改变他们的默认设置。先看这个例子:
$ ls > ls_result
$ ls -l >> ls_result
上面这两个命令分别将 ls 命令的结果输出重定向到 ls_result 文件中和追加到 ls_result 文件中,而不是输出到屏幕上。">“就是输出(标准输出和标准错误输出)重定向的代表符号,连续两个 “>” 符号,即 “»” 则表示不清除原来的而追加输出。下面再来看一个稍微复杂的例子:
$ find /home -name lost* 2> err_result
这个命令在 “>” 符号之前多了一个 “2”,“2>” 表示将标准错误输出重定向。由于 /home 目录下有些目录由于权限限制不能访问,因此会产生一些标准错误输出被存放在 err_result 文件中。大家可以设想一下
find /home -name lost* 2>>err_result
命令会产生什么结果?
如果直接执行
find /home -name lost* > all_result
其结果是只有标准输出被存入 all_result 文件中,要想让标准错误输出和标准输入一样都被存入到文件中,那该怎么办呢?看下面这个例子:
$ find /home -name lost* > all_result 2>& 1
上面这个例子中将首先将标准错误输出也重定向到标准输出中,再将标准输出重定向到 all_result 这个文件中。这样我们就可以将所有的输出都存储到文件中了。为实现上述功能,还有一种简便的写法如下:
$ find /home -name lost* >& all_result
如果那些出错信息并不重要,下面这个命令可以让你避开众多无用出错信息的干扰:
$ find /home -name lost* 2> /dev/null
3.2变量
BASH 中的变量都是不能含有保留字,不能含有 “-” 等保留字符,也不能含有空格。
hello2.py例如:
#!/bin/bash
# give the initialize value to STR
STR="Hello World"
echo $STR
在上面这个程序中我们需要注意下面几点:
- 变量赋值时,'=‘左右两边都不能有空格;
2.BASH 中的语句结尾不需要分号(";");
3.除了在变量赋值和在FOR循环语句头中,BASH 中的变量使用必须在变量前加”$“符号,同学们可以将上面程序中第三行改为 “echo STR” 再试试,看看会出什么结果。==>output: STR
4.由于 BASH 程序是在一个新的进程中运行的,所以该程序中的变量定义和赋值不会改变其他进程或原始 Shell 中同名变量的值,也不会影响他们的运行。
四、案例
[sam] vi sh01.sh
#! /bin/bash
#Program:
# This progaram shows "Hello World !" in your screen.
# History:
#2014/07/21 Sam First release
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World! \a \n"
exit 0
#变量由用户定义
[sam] vi sh02.sh
#! /bin/bash
#Program:
# User inputs his first name and last name . Progaram shows his full name.
#History :
#2014/07/21 Sam 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 :" fisrtname # 提示使用者输入
read -p "Please input your last name :" lastname #提示使用者输入
echo -e "\nYour full name is :$fisrtname $lastname" #结果由屏幕输出
#利用日期进行文件建立
[sam] vi sh03.sh
#!/bin/bash
#Program:
# Program creats three files, which named by user's input
# and date command.
#History:
# 2014/07/22 Sam 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 ,利用变量功能分析文件名是否有设定?
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"
#数值的运算
[sam] vi sh04.sh
#!/bin/bash
# Program:
# User inputs 2 integer numbers; program will cross these two numbers.
#History:
# 2014/07/22 Sam First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/licl/bin:/usr/local/sbin:~/bin
export PATH
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"
五、报错与讨论
5.1参数-e显示出来
在下面运行例子sh sh01.sh运行后出来的结果为 -e Hello Word!
这个-e 是echo 的一个参数,为什么运行脚本会显示出来
而直接 echo -e “Hello Word !” 这个-e是不显示出来的
解决办法:
你运行下echo $SHELL看看当前用的是不是bash作shell
/bin/zsh #原来不是bash作为默认的shell, 说明zsh和bash的echo不一样
用bash sh01.sh运行脚本试试
或者把该脚本加上可执行属性再直接运行
没必要改把默认的shell改为bash
给脚本加上可执行属性
脚本在运行时会自动调用bash
参考资料
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn