Shell脚本编程30分钟入门(小结)(转)

原文连接https://www.jb51.net/article/161028.htmphp

什么是Shell脚本java

Shell脚本(英语:Shell script),又称Shell命令稿、程序化脚本,是一种电脑程序与文本文件,内容由一连串的shell命令组成,经由Unix Shell直译其内容后运做。被当成是一种脚本语言来设计,其运做方式与直译语言至关,由Unix shell扮演命令行解释器的角色,在读取shell脚本以后,依序运行其中的shell命令,以后输出结果。利用shell脚本能够进行系统管理,文件操做等。python

示例linux

看个例子吧:ios

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
 
cd ~
 
mkdir shell_tut
 
cd shell_tut
 
  
 
for ((i=0; i<10; i++)); do
 
     touch test_$i.txt
 
done

 

示例解释 •第1行:指定脚本解释器,这里是用/bin/sh作解释器的 •第2行:切换到当前用户的home目录 •第3行:建立一个目录shell_tut •第4行:切换到shell_tut目录 •第5行:循环条件,一共循环10次 •第6行:建立一个test_1…10.txt文件 •第7行:循环体结束git

cd, mkdir, touch都是系统自带的程序,通常在/bin或者/usr/bin目录下。for, do, done是sh脚本语言的关键字。github

shell和shell脚本的概念web

shell是指一种应用程序,这个应用程序提供了一个界面,用户经过这个界面访问操做系统内核的服务。Ken Thompson的sh是第一种Unix Shell,Windows Explorer是一个典型的图形界面Shell。shell

shell脚本(shell script),是一种为shell编写的脚本程序。业界所说的shell一般都是指shell脚本,但读者朋友要知道,shell和shell script是两个不一样的概念。因为习惯的缘由,简洁起见,本文出现的“shell编程”都是指shell脚本编程,不是指开发shell自身(如Windows Explorer扩展开发)。编程

环境

shell编程跟java、php编程同样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就能够了。

OS

当前主流的操做系统都支持shell编程,本文档所述的shell编程是指Linux下的shell,讲的基本都是POSIX标准下的功能,因此,也适用于Unix及BSD(如Mac OS)。

Linux

Linux默认安装就带了shell解释器。

Mac OS

Mac OS不只带了sh、bash这两个最基础的解释器,还内置了ksh、csh、zsh等不经常使用的解释器。

Windows上的模拟器

windows出厂时没有内置shell解释器,须要自行安装,为了同时能用grep, awk, curl等工具,最好装一个cygwin或者mingw来模拟linux环境。 •cygwinmingw

脚本解释器

sh

即Bourne shell,POSIX(Portable Operating System Interface)标准的shell解释器,它的二进制文件路径一般是/bin/sh,由Bell Labs开发。

本文讲的是sh,若是你使用其它语言用做shell编程,请自行参考相应语言的文档。

bash

Bash是Bourne shell的替代品,属GNU Project,二进制文件路径一般是/bin/bash。业界一般混用bash、sh、和shell,好比你会常常在招聘运维工程师的文案中见到:熟悉Linux Bash编程,精通Shell编程。

在CentOS里,/bin/sh是一个指向/bin/bash的符号连接:

?
1
2
3
4
5
6
7
[root@centosraw ~] # ls -l /bin/*sh
 
-rwxr-xr-x. 1 root root 903272 Feb 22 05:09 /bin/bash
 
-rwxr-xr-x. 1 root root 106216 Oct 17 2012 /bin/dash
 
lrwxrwxrwx. 1 root root   4 Mar 22 10:22 /bin/sh -> bash

但在Mac OS上不是,/bin/sh和/bin/bash是两个不一样的文件,尽管它们的大小只相差100字节左右:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
iMac:~ wuxiao$ ls -l /bin/ *sh
 
-r-xr-xr-x 1 root wheel 1371648 6 Nov 16:52 /bin/bash
 
-rwxr-xr-x 2 root wheel  772992 6 Nov 16:52 /bin/csh
 
-r-xr-xr-x 1 root wheel 2180736 6 Nov 16:52 /bin/ksh
 
-r-xr-xr-x 1 root wheel 1371712 6 Nov 16:52 /bin/sh
 
-rwxr-xr-x 2 root wheel  772992 6 Nov 16:52 /bin/tcsh
 
-rwxr-xr-x 1 root wheel 1103984 6 Nov 16:52 /bin/zsh

高级编程语言

理论上讲,只要一门语言提供了解释器(而不只是编译器),这门语言就能够胜任脚本编程,常见的解释型语言都是能够用做脚本编程的,如:Perl、Tcl、Python、PHP、Ruby。Perl是最老牌的脚本编程语言了,Python这些年也成了一些linux发行版的预置解释器。

编译型语言,只要有解释器,也能够用做脚本编程,如C shell是内置的(/bin/csh),Java有第三方解释器Jshell,Ada有收费的解释器AdaScript。

以下是一个PHP Shell Script示例(假设文件名叫test.php):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/php
 
<?php
 
for ( $i =0; $i < 10; $i ++)
 
     echo $i . "\n" ;
 
执行:
 
/usr/bin/php test.php
 
或者:
 
chmod +x test.php
 
./test.php

如何选择shell编程语言

熟悉 vs 陌生

若是你已经掌握了一门编程语言(如PHP、Python、Java、JavaScript),建议你就直接使用这门语言编写脚本程序,虽然某些地方会有点啰嗦,但你能利用在这门语言领域里的经验(单元测试、单步调试、IDE、第三方类库)。

新增的学习成本很小,只要学会怎么使用shell解释器(Jshell、AdaScript)就能够了。

简单 vs 高级

若是你以为本身熟悉的语言(如Java、C)写shell脚本实在太啰嗦,你只是想作一些备份文件、安装软件、下载数据之类的事情,学着使用sh,bash会是一个好主意。

shell只定义了一个很是简单的编程语言,因此,若是你的脚本程序复杂度较高,或者要操做的数据结构比较复杂,那么仍是应该使用Python、Perl这样的脚本语言,或者是你原本就已经很擅长的高级语言。由于sh和bash在这方面很弱,好比说: •·它的函数只能返回字串,没法返回数组 •·它不支持面向对象,你没法实现一些优雅的设计模式 •·它是解释型的,一边解释一边执行,连PHP那种预编译都不是,若是你的脚本包含错误(例如调用了不存在的函数),只要没执行到这一行,就不会报错

环境兼容性

若是你的脚本是提供给别的用户使用,使用sh或者bash,你的脚本将具备最好的环境兼容性,perl很早就是linux标配了,python这些年也成了一些linux发行版的标配,至于mac os,它默认安装了perl、python、ruby、php、java等主流编程语言。

第一个shell脚本

编写

打开文本编辑器,新建一个文件,扩展名为sh(sh表明shell),扩展名并不影响脚本执行,见名知意就好,若是你用php写shell 脚本,扩展名就用php好了。

输入一些代码,第一行通常是这样:

?
1
2
3
4
5
#!/bin/bash
 
#!/usr/bin/php
 
#!”是一个约定的标记,它告诉系统这个脚本须要什么解释器来执行。

运行

运行Shell脚本有两种方法:

做为可执行程序

?
1
2
chmod +x test .sh
. /test .sh

注意,必定要写成./test.sh,而不是test.sh,运行其它二进制的程序也同样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录一般不在PATH里,因此写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找。

经过这种方式运行bash脚本,第一行必定要写对,好让系统查找到正确的解释器。

这里的"系统",其实就是shell这个应用程序(想象一下Windows Explorer),但我故意写成系统,是方便理解,既然这个系统就是指shell,那么一个使用/bin/sh做为解释器的脚本是否是能够省去第一行呢?是的。

做为解释器参数

这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,如:

?
1
2
3
/bin/sh test .sh
 
/bin/php test .php

这种方式运行的脚本,不须要在第一行指定解释器信息,写了也没用。

变量

定义变量

定义变量时,变量名不加美圆符号($),如:

?
1
your_name= "qinjx"

注意,变量名和等号之间不能有空格,这可能和你熟悉的全部编程语言都不同。

除了显式地直接赋值,还能够用语句给变量赋值,如:

?
1
for file in ` ls /etc `

使用变量

使用一个定义过的变量,只要在变量名前面加美圆符号便可,如:

?
1
2
3
4
5
your_name= "qinjx"
 
echo $your_name
 
echo ${your_name}

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,好比下面这种状况:

?
1
2
3
4
5
for skill in Ada Coffe Action Java; do
 
     echo "I am good at ${skill}Script"
 
done

若是不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是咱们指望的样子了。

推荐给全部变量加上花括号,这是个好的编程习惯。IntelliJ IDEA编写shell script时,IDE就会提示加花括号。

重定义变量

已定义的变量,能够被从新定义,如:

?
1
2
3
4
5
6
7
your_name= "qinjx"
 
echo $your_name
 
your_name= "alibaba"
 
echo $your_name

这样写是合法的,但注意,第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美圆符。

注释

以“#”开头的行就是注释,会被解释器忽略。

多行注释

sh里没有多行注释,只能每一行加一个#号。就像这样:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#--------------------------------------------
 
# 这是一个自动打ipa的脚本,基于webfrogs的ipa-build书写:https://github.com/webfrogs/xcode_shell/blob/master/ipa-build
 
  
 
# 功能:自动为etao ios app打包,产出物为14个渠道的ipa包
 
# 特点:全自动打包,不须要输入任何参数
 
#--------------------------------------------
 
  
 
##### 用户配置区 开始 #####
 
#
 
#
 
# 项目根目录,推荐将此脚本放在项目的根目录,这里就不用改了
 
# 应用名,确保和Xcode里Product下的target_name.app名字一致
 
#
 
##### 用户配置区 结束 #####

若是在开发过程当中,遇到大段的代码须要临时注释起来,过一下子又取消注释,怎么办呢?每一行加个#符号太费力了,能够把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释同样的效果。

字符串

字符串是shell编程中最经常使用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了,哈哈),字符串能够用单引号,也能够用双引号,也能够不用引号。单双引号的区别跟PHP相似。

单引号

?
1
str= 'this is a string'

单引号字符串的限制: •单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的 •单引号字串中不能出现单引号(对单引号使用转义符后也不行)

双引号

?
1
str= "Hello, I know your are \"$your_name\"! \n"

•双引号里能够有变量 •双引号里能够出现转义字符

字符串操做

拼接字符串

?
1
2
3
4
5
6
7
8
9
your_name= "qinjx"
 
greeting= "hello, " $your_name " !"
 
greeting_1= "hello, ${your_name} !"
 
  
 
echo $greeting $greeting_1

获取字符串长度:

?
1
2
string= "abcd"
echo ${ #string} #输出:4

提取子字符串

?
1
2
3
string= "alibaba is a great company"
 
echo ${string:1:4} #输出:liba

查找子字符串

?
1
2
3
string= "alibaba is a great company"
 
echo ` expr index "$string" is` #输出:8,这个语句的意思是:找出单词is在这名话中的位置

数组

管道

条件判断

流程控制

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
和Java、PHP等语言不同,sh的流程控制不可为空,如:
 
<?php
 
if (isset($_GET[ "q" ])) {
 
     search(q);
 
}
 
else {
 
     //do nothing
 
}
 
在sh /bash 里可不能这么写,若是 else 分支没有语句执行,就不要写这个 else
 
还要注意,sh里的 if [ $foo - eq 0 ],这个方括号跟Java /PHP if 后面的圆括号大不相同,它是一个可执行程序(和 cd , ls , grep 同样),想不到吧?在CentOS上,它在 /usr/bin 目录下:
 
ll /usr/bin/ [
 
-rwxr-xr-x. 1 root root 33408 6月 22 2012 /usr/bin/ [
 
正由于方括号在这里是一个可执行程序,方括号后面必须加空格,不能写成 if [$foo - eq 0]
 
if else
 
if
 
if condition
 
then
 
     command1
 
     command2
 
     ...
 
     commandN
 
fi
 
写成一行(适用于终端命令提示符):
 
if ` ps -ef | grep ssh `; then echo hello; fi
 
末尾的 fi 就是 if 倒过来拼写,后面还会遇到相似的
 
if else
 
if condition
 
then
 
     command1
 
     command2
 
     ...
 
     commandN
 
else
 
     command
 
fi
 
if else - if else
 
if condition1
 
then
 
     command1
 
elif condition2
 
     command2
 
else
 
     commandN
 
fi
 
for while
 
for
 
在开篇的示例里演示过了:
 
for var in item1 item2 ... itemN
 
do
 
     command1
 
     command2
 
     ...
 
     commandN
 
done
 
写成一行:
 
for var in item1 item2 ... itemN; do command1; command2… done ;

C风格的for

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
for (( EXP1; EXP2; EXP3 ))
 
do
 
     command1
 
     command2
 
     command3
 
done
 
while
 
while condition
 
do
 
     command
 
done
 
无限循环
 
while :
 
do
 
     command
 
done
 
或者
 
while true
 
do
 
     command
 
done
 
或者
 
for (( ; ; ))
 
until
 
until condition
 
do
 
     command
 
done
 
case
 
case "${opt}" in
 
     "Install-Puppet-Server" )
 
         install_master $1
 
         exit
 
     ;;
 
  
 
     "Install-Puppet-Client" )
 
         install_client $1
 
         exit
 
     ;;
 
  
 
     "Config-Puppet-Server" )
 
         config_puppet_master
 
         exit
 
     ;;
 
  
 
     "Config-Puppet-Client" )
 
         config_puppet_client
 
         exit
 
     ;;
 
  
 
     "Exit" )
 
         exit
 
     ;;
 
  
 
     * ) echo "Bad option, please choose again"
 
esac
 
case 的语法和C family语言差异很大,它须要一个esac(就是 case 反过来)做为结束标记,每一个 case 分支用右圆括号,用两个分号表示 break

函数

定义

调用

文件包含

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
可使用 source 和.关键字,如:
 
source . /function .sh
 
. . /function .sh
 
bash 里, source 和.是等效的,他们都是读入 function .sh的内容并执行其内容(相似PHP里的include),为了更好的可移植性,推荐使用第二种写法。
 
包含一个文件和执行一个文件同样,也要写这个文件的路径,不能光写文件名,好比上述例子中:
 
. . /function .sh
 
不能够写做:
 
. function .sh
 
若是 function .sh是用户传入的参数,如何得到它的绝对路径呢?方法是:
 
real_path=`readlink -f $1` #$1是用户输入的参数,如function.sh
 
. $real_path

用户输入

执行脚本时传入

脚本运行中输入

select菜单

stdin和stdout

经常使用的命令

sh脚本结合系统命令便有了强大的威力,在字符处理领域,有grep、awk、sed三剑客,grep负责找出特定的行,awk能将行拆分红多个字段,sed则能够实现更新插入删除等写操做。

ps

查看进程列表

grep

排除grep自身

查找与target相邻的结果

以上就是本文的所有内容,但愿对你们的学习有所帮助,也但愿你们多多支持脚本之家。

相关文章
相关标签/搜索