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. LCD显示方向

    一.ILI9341内存到显示地址的映射 本文只讨论“正常显示”,不讨论“垂直滚动显示”模式. 可以看到物理内存被两个指针访问,行指针和列指针,行指针范围从000h到013Fh,列指针范围为0000h到 ...

  2. 自动寻路NavMesh

    步骤 1.创建地形 2.添加角色 3.创建多个障碍物,尽量摆放的复杂些,用来检测NavMesh的可用性和效率 4.选中地形,在Navigation窗口中,设置Navigation Static 5.依 ...

  3. 如何使用Promise

    在说Promise之前,不得不说一下JavaScript的嵌套的回调函数 在JavaScript语言中,无论是写浏览器端的各种事件处理回调.ajax回调,还是写Node.js上的业务逻辑,不得不面对的 ...

  4. Hibernate与数据库分表

    数据库分片(shard)是一种在数据库的某些表变得特别大的时候采用的一种技术. 通过按照一定的维度将表切分,可以使该表在常用的检索中保持较高的效率,而那些不常用的记录则保存在低访问表中.比如:销售记录 ...

  5. jquery delegate

    代码如下:   $('#container').delegate('a','click',function(){alert('That tickles!')} JQuery扫描文档查找$('#cont ...

  6. this、call和apply

    this call apply this 和其他语言不同,JavaScript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境. this的 ...

  7. A Neural Network in 11 lines of Python

    A Neural Network in 11 lines of Python A bare bones neural network implementation to describe the in ...

  8. 【深度学习系列2】Mariana DNN多GPU数据并行框架

    [深度学习系列2]Mariana DNN多GPU数据并行框架  本文是腾讯深度学习系列文章的第二篇,聚焦于腾讯深度学习平台Mariana中深度神经网络DNN的多GPU数据并行框架.   深度神经网络( ...

  9. angular2地址栏路由配置

    一步一步route过去可以,地址栏直接写url怎么就找不到了呢? 这关乎于Nodejs的express路由规则(http://hm4123660.iteye.com/blog/2195035) exp ...

  10. django的url的name参数的意义(转发)

    http://bio.rusaer.com/archives/288   Django一个比较隐含的函数url 阅读量(5010)  |  发表 于 2010-03-09 14:26:18 Djang ...