前面散仙已经把Linux基础的shell命令系列的博客完工,如果没有任何linux基础的朋友,建议先从shell命令开始学习,如果有一定基础的就可以直接跳过。从本篇起,散仙要写的是关于shell编程系列的知识。
前面我们例子里面的命令,基本都是单个执行的,但是在linux下,只有把命令组合成一个脚本,发挥的作用,才是巨大的,这就类似于一个砖头没啥用处,但是用很多砖头,我们就可以盖一座大厦,这样它们的价值就体现出来了。
在linux中我们可以使用分号分开执行2个命令:
[code="java"]# who ;date
root pts/0 2014-08-08 02:55 (192.168.46.22)
2014年 08月 08日 星期五 03:39:43 CST
# [/code]
我们也可以放脚本里执行,编写一个shell脚本的头部生命通常是#!/bin/bash开头,除了这个开头的其他的#开头都是注释内容:
vi test.sh编辑一个脚本
[code="java"]# sh test.sh
2014年 08月 08日 星期五 03:46:15 CST
root pts/0 2014-08-08 02:55 (192.168.46.22)
# [/code]
两种调用方法,没有权限,可以赋值权限:
[code="java"]# sh test.sh
2014年 08月 08日 星期五 03:46:15 CST
root pts/0 2014-08-08 02:55 (192.168.46.22)
# ./test.s
-bash: ./test.s: 没有那个文件或目录
# ./test.sh
-bash: ./test.sh: 权限不够
# chmod u+x test.sh
# ll
总用量 328476
-rw-r--r-- 1 root root 143775368 7月 28 19:30 abc1.txt
-rw-------. 1 root root 1087 6月 13 19:06 anaconda-ks.cfg
-rw-r--r-- 1 root root 52 7月 31 21:29 count2.txt
-rw-r--r-- 1 root root 52 7月 31 19:46 count.txt
-rw-r--r--. 1 root root 96183833 6月 9 17:27 hadoop-2.2.0.tar.gz
-rw-r--r-- 1 root root 1 7月 31 21:25 hh.txt
drwxr-xr-x 3 root root 4096 7月 29 04:47 hivesrc
-rw-r--r--. 1 root root 2111 6月 16 13:10 initserver.sh
-rw-r--r--. 1 root root 7995 6月 13 19:06 install.log
-rw-r--r--. 1 root root 3384 6月 13 19:06 install.log.syslog
drwxr-xr-x 2 root root 4096 7月 31 21:19 intest
lrwxrwxrwx 1 root root 12 7月 31 21:45 jdk -> jdk1.7.0_25/
drwxr-xr-x. 8 search 143 4096 6月 6 2013 jdk1.7.0_25
-rwx------. 1 root root 96316511 11月 20 2013 jdk-7u25-linux-x64.gz
drwxr-xr-x 3 root root 4096 7月 31 21:33 li
drwxr-xr-x 3 root root 4096 7月 9 04:08 lo
drwxr-xr-x 3 root root 4096 7月 9 04:08 login
-rw-r--r-- 1 root root 1048 6月 19 03:31 setlimit.sh
drwxr-xr-x 2 root root 4096 8月 5 01:44 test
drwxr-sr-x 2 root abc 4096 8月 6 01:53 testidr
-rwxr--r-- 1 root root 46 8月 8 03:43 test.sh
drwxr-xr-x 3 root root 4096 6月 20 02:51 tsethadoop
# ./test.sh
2014年 08月 08日 星期五 03:47:10 CST
root pts/0 [/code]
如何输出一行文本,类似于JAVA里面的System.out.println()功能,linux里面的echo提供了这个功能,
如果字符串里面出现双引号,就使用单引号括起来,如果出现了单引号,就用双引号括起来,如果即出现了单引号,也出现了双引号,那么就要用\转义:
[code="java"]# echo "a's dog"
a's dog
# echo "a's"" dog"
a's dog
# echo "a's"abc" dog"
a'sabc dog
# echo "a's\"abc\" dog"
a's"abc" dog
# echo 'a 'dog' "abc"'
a dog "abc"[/code]
echo -n 参数可以避免末尾换行,类似System.out.print()
[code="java"]# sh a.sh
conent:2014年 08月 08日 星期五 04:00:14 CST[/code]
echo支持在字符串中,使用linux环境变量,可以正确输出:
[code="java"]# echo "my home is $HOME"
my home is /root
# [/code]
用户变量定义通过等号赋值,注意等号左右不能有空格,变量名区分大小写
[code="java"]# more a.sh
name="我是三劫散仙"
echo "info: $name"
# sh a.sh
info: 我是三劫散仙
# [/code]
变量之间的赋值:
[code="java"]# more a.sh
name="我是三劫散仙"
name2=$name
echo "info: $name2"
# sh a.sh
info: 我是三劫散仙
#
[/code]
把一个shell命令赋值给一个变量,使用反引号:
[code="java"]# more b.sh
test=`date;who`
echo -n "输出的内容是什么呢,大家来看下:"
echo $test
# sh b.sh
输出的内容是什么呢,大家来看下:2014年 08月 08日 星期五 04:14:37 CST root pts/0 2014-08-08 02:55 (192.168.46.22)
# [/code]
反引号的功能,类似于JavaScript里面的eval关键字的功能,可以解析字符串命令
通过这样,我们就可以生成文件时,以时间命名:
[code="java"]# more c.sh
#注意date后面有空格隔开,否则会出错
filename=`date +%y%m%d`
echo "我是文件里的内容" > log.$filename
# more log.140808
我是文件里的内容
# [/code]
输出重定向命令:
>覆盖模式重定向
>>追加模式重定向
输入重定向命令
<
内联输入重定向
<<
输出重定向相信大家用的很多,输入的重定向可能用的不多,下面散仙举几个例子:
[code="java"]# wc < a.sh
8 5 65
# [/code]
输出重定向,可以把一个文件的内容,发送给命令进行统计
这三个数字的含义,代表文本的行数,词数,和字节大小,说明,有8行,5个单词,65字节
内联重定向,允许交互式的读入,在你定义好的开头,与结束符之间,追加统计进行统计:
[code="java"]# wc << B
> a b 1
> d c 2
> B
2 6 12
# [/code]
结束符可以随便定义,散仙在这里是B
下面要说的是管道命令:|
[code="java"]# rpm -qa | sort
acl-2.2.49-6.el6.x86_64
attr-2.4.44-7.el6.x86_64
audit-2.2-2.el6.x86_64
audit-libs-2.2-2.el6.x86_64
authconfig-6.1.12-13.el6.x86_64
b43-openfwwf-5.2-4.el6.noarch
basesystem-10.0-4.el6.noarch
bash-4.1.2-15.el6_4.x86_64
binutils-2.20.51.0.2-5.36.el6.x86_64
bridge-utils-1.2-10.el6.x86_64
bzip2-1.0.5-7.el6_0.x86_64
bzip2-libs-1.0.5-7.el6_0.x86_64
ca-certificates-2013.1.94-65.0.el6.noarch
centos-release-6-5.el6.centos.11.1.x86_64
checkpolicy-2.0.22-1.el6.x86_64
chkconfig-1.3.49.3-2.el6_4.1.x86_64
coreutils-8.4-31.el6.x86_64
coreutils-libs-8.4-31.el6.x86_64
cpio-2.10-11.el6_3.x86_64
[/code]
rpm -qa可以查询已经安装的软件包,然后重定向到sort命令进行排序。
重定向命令可以使用多个:
[code="java"]# ll | more | sort
drwxr-sr-x 2 root abc 4096 8月 6 01:53 testidr
drwxr-xr-x 2 root root 4096 7月 31 21:19 intest
drwxr-xr-x 2 root root 4096 8月 5 01:44 test
drwxr-xr-x 3 root root 4096 6月 20 02:51 tsethadoop
drwxr-xr-x 3 root root 4096 7月 29 04:47 hivesrc
drwxr-xr-x 3 root root 4096 7月 31 21:33 li
drwxr-xr-x 3 root root 4096 7月 9 04:08 lo
drwxr-xr-x 3 root root 4096 7月 9 04:08 login
drwxr-xr-x. 8 search 143 4096 6月 6 2013 jdk1.7.0_25
lrwxrwxrwx 1 root root 12 7月 31 21:45 jdk -> jdk1.7.0_25/
-rw-------. 1 root root 1087 6月 13 19:06 anaconda-ks.cfg
-rw-r--r-- 1 root root 1048 6月 19 03:31 setlimit.sh
-rw-r--r-- 1 root root 127 8月 8 04:20 c.sh
-rw-r--r-- 1 root root 143775368 7月 28 19:30 abc1.txt
-rw-r--r-- 1 root root 1 7月 31 21:25 hh.txt
-rw-r--r--. 1 root root 2111 6月 16 13:10 initserver.sh
-rw-r--r-- 1 root root 25 8月 8 04:20 log.140808
-rw-r--r--. 1 root root 3384 6月 13 19:06 install.log.syslog
-rw-r--r-- 1 root root 52 7月 31 19:46 count.txt
-rw-r--r-- 1 root root 52 7月 31 21:29 count2.txt
-rw-r--r-- 1 root root 65 8月 8 04:11 a.sh
-rw-r--r--. 1 root root 7995 6月 13 19:06 install.log
-rw-r--r-- 1 root root 90 8月 8 04:14 b.sh
-rw-r--r--. 1 root root 96183833 6月 9 17:27 hadoop-2.2.0.tar.gz
-rwx------. 1 root root 96316511 11月 20 2013 jdk-7u25-linux-x64.gz
-rwxr--r-- 1 root root 46 8月 8 03:43 test.sh
总用量 328492
# [/code]
接下来,我们看下如何在shell中,执行数学运算:
[code="java"]# expr 1+5
1+5
# expr 1 + 5
6
# expr 1 * 8
expr: 语法错误
# expr 1 \* 8
8
# expr 9 / 3
3
# expr 9 / 5
1
# [/code]
expr 后面跟一个表达式,注意运算式左右必须有一个空格
这是比较传统的用法,linux里面可以有计算器bc模块,如果你的linux系统里面没有,就使用yum install bc命令安装一个
[code="java"]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
12 * 5.8
69.6
8 * 4 / 2
16
5 / 3
1
5 / 3.0
1
4.44 / 2
2
scale=4
3 / 8
.3750
10 / 11
.9090
scale=2
5 / 2
2.50
10 / 3
3.33
[/code]
默认的是不保留小数的,我们可以通过scale设置小数点位。
最后使用quit命令退出程序。
下面我们看看如何在脚本中,使用bc命令:
[code="java"]# more bc.sh
out=`echo "scale=4; 10 / 3" | bc`
echo "输出的内容如下:$out"
# sh bc.sh
输出的内容如下:3.3333
# [/code]
我们还可以结合,内联重定向使用bc计算器,在脚本里
[code="java"]# more cc.sh
var1=10.23
var2=9
var3=1
var4=`bc << EOF
scale=4
a1 = ($var1+$var2)
b1 = ($var2+$var3)
a1 + b1
EOF
`
echo "最终的结果是: $var4"
# sh cc.sh
最终的结果是: 29.23
# [/code]
下面我们看下退出脚本的状态码:
使用变量$?
[code="java"]# date
2014年 08月 08日 星期五 05:16:38 CST
# echo $?
0
# dates
-bash: dates: command not found
# echo $?
127
# [/code]
1,0代表成功
2,1代表通用的未知错误
3,126代表命令不可执行
4,127代表没找到命令
5,128无效的退出参数
6,128+xlinux信号x的严重错误
7,130代表命令通过Ctrl+C终止
8,255退出状态码越界
在JAVA编程中,我们都知道使用System.exit可以终止虚拟机运行,那么在linux中,我们也有一样的终止方法类似于JAVA中的return关键字exit;
[code="java"]# more t.sh
echo "上面的会打印"
sleep 5
exit
echo "我会被打印出来么?"
# sh t.sh
上面的会打印
# echo $?
0
# [/code]
当然我们也可以执行返回的状态码:
[code="java"]# cat t.sh
echo "上面的会打印"
sleep 5
exit 88
echo "我会被打印出来么?"
# sh t.sh
上面的会打印
# echo $?
88
# [/code]
状态码最大是255,超过255的,一律会被取模值,这一点需要注意、
前面我们例子里面的命令,基本都是单个执行的,但是在linux下,只有把命令组合成一个脚本,发挥的作用,才是巨大的,这就类似于一个砖头没啥用处,但是用很多砖头,我们就可以盖一座大厦,这样它们的价值就体现出来了。
在linux中我们可以使用分号分开执行2个命令:
[code="java"]# who ;date
root pts/0 2014-08-08 02:55 (192.168.46.22)
2014年 08月 08日 星期五 03:39:43 CST
# [/code]
我们也可以放脚本里执行,编写一个shell脚本的头部生命通常是#!/bin/bash开头,除了这个开头的其他的#开头都是注释内容:
vi test.sh编辑一个脚本
#!/bin/bash
#我是注释的内容
date
who[code="java"]# sh test.sh
2014年 08月 08日 星期五 03:46:15 CST
root pts/0 2014-08-08 02:55 (192.168.46.22)
# [/code]
两种调用方法,没有权限,可以赋值权限:
[code="java"]# sh test.sh
2014年 08月 08日 星期五 03:46:15 CST
root pts/0 2014-08-08 02:55 (192.168.46.22)
# ./test.s
-bash: ./test.s: 没有那个文件或目录
# ./test.sh
-bash: ./test.sh: 权限不够
# chmod u+x test.sh
# ll
总用量 328476
-rw-r--r-- 1 root root 143775368 7月 28 19:30 abc1.txt
-rw-------. 1 root root 1087 6月 13 19:06 anaconda-ks.cfg
-rw-r--r-- 1 root root 52 7月 31 21:29 count2.txt
-rw-r--r-- 1 root root 52 7月 31 19:46 count.txt
-rw-r--r--. 1 root root 96183833 6月 9 17:27 hadoop-2.2.0.tar.gz
-rw-r--r-- 1 root root 1 7月 31 21:25 hh.txt
drwxr-xr-x 3 root root 4096 7月 29 04:47 hivesrc
-rw-r--r--. 1 root root 2111 6月 16 13:10 initserver.sh
-rw-r--r--. 1 root root 7995 6月 13 19:06 install.log
-rw-r--r--. 1 root root 3384 6月 13 19:06 install.log.syslog
drwxr-xr-x 2 root root 4096 7月 31 21:19 intest
lrwxrwxrwx 1 root root 12 7月 31 21:45 jdk -> jdk1.7.0_25/
drwxr-xr-x. 8 search 143 4096 6月 6 2013 jdk1.7.0_25
-rwx------. 1 root root 96316511 11月 20 2013 jdk-7u25-linux-x64.gz
drwxr-xr-x 3 root root 4096 7月 31 21:33 li
drwxr-xr-x 3 root root 4096 7月 9 04:08 lo
drwxr-xr-x 3 root root 4096 7月 9 04:08 login
-rw-r--r-- 1 root root 1048 6月 19 03:31 setlimit.sh
drwxr-xr-x 2 root root 4096 8月 5 01:44 test
drwxr-sr-x 2 root abc 4096 8月 6 01:53 testidr
-rwxr--r-- 1 root root 46 8月 8 03:43 test.sh
drwxr-xr-x 3 root root 4096 6月 20 02:51 tsethadoop
# ./test.sh
2014年 08月 08日 星期五 03:47:10 CST
root pts/0 [/code]
如何输出一行文本,类似于JAVA里面的System.out.println()功能,linux里面的echo提供了这个功能,
如果字符串里面出现双引号,就使用单引号括起来,如果出现了单引号,就用双引号括起来,如果即出现了单引号,也出现了双引号,那么就要用\转义:
[code="java"]# echo "a's dog"
a's dog
# echo "a's"" dog"
a's dog
# echo "a's"abc" dog"
a'sabc dog
# echo "a's\"abc\" dog"
a's"abc" dog
# echo 'a 'dog' "abc"'
a dog "abc"[/code]
echo -n 参数可以避免末尾换行,类似System.out.print()
echo -n "conent:"
date[code="java"]# sh a.sh
conent:2014年 08月 08日 星期五 04:00:14 CST[/code]
echo支持在字符串中,使用linux环境变量,可以正确输出:
[code="java"]# echo "my home is $HOME"
my home is /root
# [/code]
用户变量定义通过等号赋值,注意等号左右不能有空格,变量名区分大小写
[code="java"]# more a.sh
name="我是三劫散仙"
echo "info: $name"
# sh a.sh
info: 我是三劫散仙
# [/code]
变量之间的赋值:
[code="java"]# more a.sh
name="我是三劫散仙"
name2=$name
echo "info: $name2"
# sh a.sh
info: 我是三劫散仙
#
[/code]
把一个shell命令赋值给一个变量,使用反引号:
[code="java"]# more b.sh
test=`date;who`
echo -n "输出的内容是什么呢,大家来看下:"
echo $test
# sh b.sh
输出的内容是什么呢,大家来看下:2014年 08月 08日 星期五 04:14:37 CST root pts/0 2014-08-08 02:55 (192.168.46.22)
# [/code]
反引号的功能,类似于JavaScript里面的eval关键字的功能,可以解析字符串命令
通过这样,我们就可以生成文件时,以时间命名:
[code="java"]# more c.sh
#注意date后面有空格隔开,否则会出错
filename=`date +%y%m%d`
echo "我是文件里的内容" > log.$filename
# more log.140808
我是文件里的内容
# [/code]
输出重定向命令:
>覆盖模式重定向
>>追加模式重定向
输入重定向命令
<
内联输入重定向
<<
输出重定向相信大家用的很多,输入的重定向可能用的不多,下面散仙举几个例子:
[code="java"]# wc < a.sh
8 5 65
# [/code]
输出重定向,可以把一个文件的内容,发送给命令进行统计
这三个数字的含义,代表文本的行数,词数,和字节大小,说明,有8行,5个单词,65字节
内联重定向,允许交互式的读入,在你定义好的开头,与结束符之间,追加统计进行统计:
[code="java"]# wc << B
> a b 1
> d c 2
> B
2 6 12
# [/code]
结束符可以随便定义,散仙在这里是B
下面要说的是管道命令:|
[code="java"]# rpm -qa | sort
acl-2.2.49-6.el6.x86_64
attr-2.4.44-7.el6.x86_64
audit-2.2-2.el6.x86_64
audit-libs-2.2-2.el6.x86_64
authconfig-6.1.12-13.el6.x86_64
b43-openfwwf-5.2-4.el6.noarch
basesystem-10.0-4.el6.noarch
bash-4.1.2-15.el6_4.x86_64
binutils-2.20.51.0.2-5.36.el6.x86_64
bridge-utils-1.2-10.el6.x86_64
bzip2-1.0.5-7.el6_0.x86_64
bzip2-libs-1.0.5-7.el6_0.x86_64
ca-certificates-2013.1.94-65.0.el6.noarch
centos-release-6-5.el6.centos.11.1.x86_64
checkpolicy-2.0.22-1.el6.x86_64
chkconfig-1.3.49.3-2.el6_4.1.x86_64
coreutils-8.4-31.el6.x86_64
coreutils-libs-8.4-31.el6.x86_64
cpio-2.10-11.el6_3.x86_64
[/code]
rpm -qa可以查询已经安装的软件包,然后重定向到sort命令进行排序。
重定向命令可以使用多个:
[code="java"]# ll | more | sort
drwxr-sr-x 2 root abc 4096 8月 6 01:53 testidr
drwxr-xr-x 2 root root 4096 7月 31 21:19 intest
drwxr-xr-x 2 root root 4096 8月 5 01:44 test
drwxr-xr-x 3 root root 4096 6月 20 02:51 tsethadoop
drwxr-xr-x 3 root root 4096 7月 29 04:47 hivesrc
drwxr-xr-x 3 root root 4096 7月 31 21:33 li
drwxr-xr-x 3 root root 4096 7月 9 04:08 lo
drwxr-xr-x 3 root root 4096 7月 9 04:08 login
drwxr-xr-x. 8 search 143 4096 6月 6 2013 jdk1.7.0_25
lrwxrwxrwx 1 root root 12 7月 31 21:45 jdk -> jdk1.7.0_25/
-rw-------. 1 root root 1087 6月 13 19:06 anaconda-ks.cfg
-rw-r--r-- 1 root root 1048 6月 19 03:31 setlimit.sh
-rw-r--r-- 1 root root 127 8月 8 04:20 c.sh
-rw-r--r-- 1 root root 143775368 7月 28 19:30 abc1.txt
-rw-r--r-- 1 root root 1 7月 31 21:25 hh.txt
-rw-r--r--. 1 root root 2111 6月 16 13:10 initserver.sh
-rw-r--r-- 1 root root 25 8月 8 04:20 log.140808
-rw-r--r--. 1 root root 3384 6月 13 19:06 install.log.syslog
-rw-r--r-- 1 root root 52 7月 31 19:46 count.txt
-rw-r--r-- 1 root root 52 7月 31 21:29 count2.txt
-rw-r--r-- 1 root root 65 8月 8 04:11 a.sh
-rw-r--r--. 1 root root 7995 6月 13 19:06 install.log
-rw-r--r-- 1 root root 90 8月 8 04:14 b.sh
-rw-r--r--. 1 root root 96183833 6月 9 17:27 hadoop-2.2.0.tar.gz
-rwx------. 1 root root 96316511 11月 20 2013 jdk-7u25-linux-x64.gz
-rwxr--r-- 1 root root 46 8月 8 03:43 test.sh
总用量 328492
# [/code]
接下来,我们看下如何在shell中,执行数学运算:
[code="java"]# expr 1+5
1+5
# expr 1 + 5
6
# expr 1 * 8
expr: 语法错误
# expr 1 \* 8
8
# expr 9 / 3
3
# expr 9 / 5
1
# [/code]
expr 后面跟一个表达式,注意运算式左右必须有一个空格
这是比较传统的用法,linux里面可以有计算器bc模块,如果你的linux系统里面没有,就使用yum install bc命令安装一个
[code="java"]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
12 * 5.8
69.6
8 * 4 / 2
16
5 / 3
1
5 / 3.0
1
4.44 / 2
2
scale=4
3 / 8
.3750
10 / 11
.9090
scale=2
5 / 2
2.50
10 / 3
3.33
[/code]
默认的是不保留小数的,我们可以通过scale设置小数点位。
最后使用quit命令退出程序。
下面我们看看如何在脚本中,使用bc命令:
[code="java"]# more bc.sh
out=`echo "scale=4; 10 / 3" | bc`
echo "输出的内容如下:$out"
# sh bc.sh
输出的内容如下:3.3333
# [/code]
我们还可以结合,内联重定向使用bc计算器,在脚本里
[code="java"]# more cc.sh
var1=10.23
var2=9
var3=1
var4=`bc << EOF
scale=4
a1 = ($var1+$var2)
b1 = ($var2+$var3)
a1 + b1
EOF
`
echo "最终的结果是: $var4"
# sh cc.sh
最终的结果是: 29.23
# [/code]
下面我们看下退出脚本的状态码:
使用变量$?
[code="java"]# date
2014年 08月 08日 星期五 05:16:38 CST
# echo $?
0
# dates
-bash: dates: command not found
# echo $?
127
# [/code]
1,0代表成功
2,1代表通用的未知错误
3,126代表命令不可执行
4,127代表没找到命令
5,128无效的退出参数
6,128+xlinux信号x的严重错误
7,130代表命令通过Ctrl+C终止
8,255退出状态码越界
在JAVA编程中,我们都知道使用System.exit可以终止虚拟机运行,那么在linux中,我们也有一样的终止方法类似于JAVA中的return关键字exit;
[code="java"]# more t.sh
echo "上面的会打印"
sleep 5
exit
echo "我会被打印出来么?"
# sh t.sh
上面的会打印
# echo $?
0
# [/code]
当然我们也可以执行返回的状态码:
[code="java"]# cat t.sh
echo "上面的会打印"
sleep 5
exit 88
echo "我会被打印出来么?"
# sh t.sh
上面的会打印
# echo $?
88
# [/code]
状态码最大是255,超过255的,一律会被取模值,这一点需要注意、