Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算符/if语句/循环控制/… 但在开始之前, 我想先理清Shell语言与Shell之间的关系.

Shell与Shell语言

上面说了Shell是一种编程语言但你可能也听说过: sh/bash/csh/zsh/…它们也叫Shell, 实际上这里所说的Shell是一种应用程序, 它负责解释执行你编写的Shell脚本, Mac默认就自带了sh/bash/csh/zsh/tcsh/ksh, 你可以这样查看cat /etc/shells
不同的shell的用法基本相同, 但有些shell提供了一些新特性, 比如我现在在用的就是zsh, 更多zsh的内容可以去看这篇文章

第一个Shell脚本

#! /bin/sh
echo "hello shell!"

依国际惯例这里以在终端里打印一句hello shell!开始, 第一行的#!是一个约定标记, 它告诉脚本这段脚本需要什么解释器来执行. 第二行的echo命令则负责向屏幕上输出一句话.

如何运行

运行shell程序有3种方法:

  1. chmod +x使文件具有可执行权限, 直接运行
  2. 直接调用解释器, 将脚本文件作为参数传入 (比如bash hi.sh)
  3. 使用source(也可用 . 代替)执行文件

通常情况下, 最方便的方式就是方式1, 通过方式1执行你需要在脚本第一行写好这段脚本由哪个解释器来解释, 而通过方式2来执行则没有这个限制, 写了也没用.
除此之外方式1与方式2执行命令就没有区别了, 但方式3执行的方式与前两种都不同:

使用source执行shell脚本时, 不会创建子进程, 而是在父进程中直接执行!

这里不作更多解释, 感兴趣的同学可以去参考Linux Shell编程从入门到精通这本书的第一章的相关部分.

变量

和其它语言一样Shell中也有变量, 而且更简单, 但有一些比较特殊的地方.

  1. Shell中的变量只有字符串这一种类型
  2. Shell中变量名与变量值没有长度限制
  3. Shell的变量也允许比较操作和整数操作, 只要变量中的字符串为数字

定义变量

variable_name=ghui

需要注意: = 两边不能加空格, 当赋值语句包含空格时请加引号(单引号/双引号均可)比如:

variable_name="ghui's blog"

Shell中的变量可以分为两种类型:

  1. 局部变量 (定义变量时在前面加local修饰符)
  2. 全局变量 (定义变量时不加任何修饰符)

与其它语言一样局部变量的可见范围是代码块或函数内, 全局变量在全局范围内可见.看个简单的例子:

#! /bin/sh
num=111 #全局变量

func1()
{
  local num=222 #局部变量
  echo $num
}

echo "before---$num"
func1
echo "after---$num"

输出:

before---111
222
after---111

使用变量

使用一个定义过的变量, 只要在变量名前面加$即可, 如:

name=ghui
echo $name
echo ${name} #{} 为了帮助解释器识别变量边界, 非必须

在使用变量时还有一个地方需要注意, 请看下面的例子:

#! /bin/sh
str='abc'
echo "1 print $str"
echo '2 print $str'

输出:

1 print abc
2 print $str

即:
被双引号括起来的变量会发生变量替换, 单引号不会

注释

Shell中注释使用#, 而且它不支持多行注释.

常用的字符串操作

字符串拼接

name="shell"
sayHi="hello, "$name" !"
sayHi2="hello, ${name} !"
echo $sayHi $sayHi2

注意: 上面说的单双引号引起的变量替换问题

获得字符串长度

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

截取字符串

str="hello shell"
echo ${str:2}  #输出: llo shell
echo ${string:1:3} #输出:ell

更多关于字符串的操作可以看这个

if/else流程控制

基本语法结构:

if condition
then
	 do something
elif condition
then
	do something
elif condition
then
	do something
else
	do something
fi

其中, elif语句和else语句非必须的.看个例子:

#! /bin/sh
a=1
if [ $1=$a ]
then
	echo "you input 1"
elif [ $1=2 ]
then
	echo "you input 2"
else
	#do nothing
	echo " you input $1"
fi

很简单, 不过这里有两个地方需要注意, 如果某个条件下的执行体为空, 则你就不能写这个条件 即下面这样会报错:

if condition
then
	#do nothing
elif condition
then
	# do nothing
#or
else
	#do nothing

另外, [ ] 两边一定要加空格, 下面这样都会报错:

if [$a=$b]
#or
if [ $a=$b]
#or
if [$a=$b ]

只有这样if [ $a=$b ]才是对的.
注意: 实际上这里的[]test命令的一种形式, [是系统的一个内置命令,存在路径是/bin/[,它是调用test命令的标识, 右中括号是关闭条件判断的标识, 因此下面的两个测试语句是等效的:

if test "2>3"
then
	...
fi

if [ "2>3" ]
then
	…
fi

[]之外, shell语言中还有几种其它括号, 比如: 单小括号/双小括号/双中括号/… , 不同的括号有不同的用法, 更多关于shell中, 括号的用法可以看看这个

switch流程控制

当条件较多时, 可以选择使用switch语句, shell中的switch语句的写法和其它语言还是有些不同的, 基本结构如下:

case expression in
	pattern1)
		do something... ;;
	pattern2)
		do something... ;;
	pattern2)
		do something... ;;
	...
esac

看个例子:

#! /bin/sh
input=$1
case $input in
        1 | 0)
        str="一or零";;
        2)
        str="二";;
        3)
        str="三";;
        *)
        str=$input;;
esac
echo "---$str"

这个例子会根据你执行此脚本时传入的参数不同在屏幕上输出不同的值, 其中第一个case 1 | 0代表逻辑或.
NOTE:

  1. ;;相当于其它语言中的break
  2. 每个pattern之后记得加)
  3. 最后记得加esac (即反的case)

for循环

基本结构:

for name [in list]
do
	...
done

其中,[]括起来的 in list, 为可选部分, 如果省略in list则默认为in "$@", 即你执行此命令时传入的参数列表.
看个例子:

for file in *.txt
do
	open $file
done

遍历当前目录下的所有txt文件, 并依次打开.

while循环

基本结构:

while condition
do
	do something...
done

看个例子:

#! /bin/sh
i=0
while ((i<5));
do
	((i++))
	echo "i=$i"
done

输出:

i=1
i=2
i=3
i=4
i=5

NOTE: 你可能需要去了解一下(())的用法

until循环

基本结构

until condition
do
	do something...
done

看个例子:

#! /bin/sh
i=5
until ((i==0))
do
	((i--))
	echo "i=$i"
done

输出:

i=4
i=3
i=2
i=1
i=0

跳出循环

shell中也支持break跳出循环, continue跳出本次循环.用法与C, Java中相同

函数

要定义一个函数, 可以使用下面两种形式:

function funcname()
{
	do something
}

或者

funcname ()
{
	do something
}

看个例子

#! /bin/sh
# ad.sh 计算sum
add()
{
	let "sum=$1+$2"
	return $sum
}

add $1 $2
echo "sum=$?"

输入

ad 1 2

输出

sum=3

其中, $?在shell中保存的是上一条命令的返回值

NOTE:

  1. 函数必须先定义后使用
  2. 如果在函数中使用exit会退出脚本, 如果想退回到原本函数调用的地方, 则可使用return

向脚本传递参数

先shell脚本传递参数, 非常简单, 只需要在你执行命令的后面跟上即可, 看个例子:

#! /bin/sh
# test.sh
echo "$# parameters";
echo "$@";
echo "$0"
echo "$1"

输入:

test.sh 11 22

输出:

2 parameters
11 22
test.sh
11

后记

之所以要写这篇博客, 有以下几个原因:

  1. 想总结一下shell编程中的关键知识点, 方便日后查看.
  2. 想通过shell优化一下我的hexo写作及博客管理流程, 目前相关脚本已完成, 待我下一篇博客分享给大家, 如果你也是在用Hexo写博客, 相信对你会很有用, 尽请期待! 已经发布
  3. 可以看的出这里总结的都是最关键的知识点, 还有很多这里并没有说. 是因为我觉得刚开始学习一个东西没必要太计较一些细节/琐碎的东西, 掌握好大致知识框架, 然后在大家编写具体的脚本时, 遇到具体问题, 再去google寻找即可.

参考

Shell脚本编程总结及速查手册的更多相关文章

  1. LINUX SHELL脚本攻略笔记[速查]

    Linux Shell脚本攻略笔记[速查] 资源 shell script run shell script echo printf 环境变量和变量 pgrep shell数学运算 命令状态 文件描述 ...

  2. 【链接】LINUX SHELL脚本攻略笔记[速查]

    LINUX SHELL脚本攻略笔记[速查]

  3. Shell脚本编程(一)

    shell 脚本编程(一) 1 . shell 的作用 Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一 ...

  4. SHELL脚本编程的常识和VI常用技巧

    来源:http://mprc.pku.edu.cn/mentors/training/TrainingCourses/material/ShellProgramming.HTM#_Toc3751808 ...

  5. 程序员 & 设计师都能用上的 75 份速查手册

    分享75份开发人员和设计师会用到的速查手册,由 vikas 收集整理,包括:jQuery.HTML.HTML5.CSS.CSS3.JavaScript.Photoshop .git.Linux.Jav ...

  6. CUDA 7.0 速查手册

    Create by Jane/Santaizi 03:57:00 3/14/2016 All right reserved. 速查手册基于 CUDA 7.0 toolkit documentation ...

  7. 《Linux命令行与shell脚本编程大全 第3版》

    第一部分 Linux 命令行 第1章  初识Linux she1.1   什么是Linux 21.1.1 深入探究Linux 内核 31.1.2 GNU 工具 61.1.3 Linux 桌面环境 81 ...

  8. Docker常用命令速查手册(华贵铂金版)

    原创声明:作者:Arnold.zhao  博客园地址:https://www.cnblogs.com/zh94 Docker常用命令速查手册 搜索仓库镜像 docker search nginx 获取 ...

  9. Linux命令行与Shell脚本编程大全

    快来参加<Linux命令行与Shell脚本编程大全>学习吧,提升技能,展示自我. 点击链接即可进入学习:https://s.imooc.com/WTmCO6H 课程亮点适合零基础读者,从零 ...

随机推荐

  1. ubuntu 12.04 安装 nginx+php+mysql web服务器

    Nginx 是一个轻量级,以占用系统资源少,运行效率而成为web服务器的后起之秀,国内现在很多大型网站都以使用nginx,包括腾讯.新浪等大型信息网站,还有淘宝网站使用的是nginx二次开发的web服 ...

  2. 一步步学习NHibernate(6)——ISession的管理

    请注明转载地址:http://www.cnblogs.com/arhat 今天老魏那个汗啊,我的ThinkPad的电源线不通电了,擦啊.明天还得掏银子买一个!心疼啊,原装的啊.不过话说回来,已经用了将 ...

  3. 深入浅出JMS(二)——JMS的组成

    JMS Provider 实现了JMS规范的消息系统,该系统还提供必须的用于管理和控制全方位的功能,如这里的ActiveMQ. Administered Objects Administered Ob ...

  4. javascript随手记

    编码规范 避免使用全局变量 写在所有函数外面的变量就是全局变量. 之所以要避免使用全局变量是因为:如果有多个类库的话,它们都定义了一个名字的变量.这时候后引入的类库中该变量的值就会覆盖前面引入的类库中 ...

  5. Delphi XE10让android的界面设计摆脱繁杂

    设计一个选项卡. 大体图样: 1.创建一个multi_Device_Application;2.在form上放一个Rectangle1,设置align为top.设置fill属性的kind为Gradie ...

  6. 解决iphone safari上的圆角问题

    -webkit-appearance : none ; /*解决iphone safari上的圆角问题*/

  7. r个有标志的球放进n个不同的盒子里,要求无一空盒,问有多少种不同的分配方案?

           由题意可知道r>=n,我原来想的是先取n个全排列,剩下的r-n个每个有n中选择,所以结果是n!*n^(r-n).经满神猜测,这样是会重复的.比如说,1到5个球,ABC三个盒子,ms ...

  8. WebKit Web Inspector增加覆盖率分析和类型推断功能

    WebKit中的Web Inspector(Web检查器)主要用于查看页面源代码.实时DOM层次结构.脚本调试.数据收集等,日前增加了两个十分有用的新功能:覆盖率分析和类型推断.覆盖率分析工具能够可视 ...

  9. android 服务service开启和关闭

    startService()方法开启一个服务. 服务只会开启一次,如果服务已经创建,并且没有销毁,多次调用startService方法只会执行onStartCommand方法和onStart方法. 服 ...

  10. UVA 1160 X-Plosives

    题意是一次装入物品,物品由两种元素组成,当遇到即将装入的物品与已经装入的物品形成k个物品,k种元素,跳过该物品的装入.可以将每种元素看成顶点,物品看成一条边.这样问题就转化为利用并查集求环的情况. 算 ...