Shell学习笔记——入门

背景

以前在ubuntu运行软件的时候,因为不懂shell脚本,因此出了什么问题全是靠百度来解决,走前人走过的路,摸着前人的石头过河。这样短期还行,但显然不是长久之计,如今要逐步开始学习Fabric了,它的第一个例子的运行文件e2e_cli的network_setup.sh就难住了我,虽然依赖百度花费近十天终于将之运行了起来但是不能这样下去了。浑浑噩噩这么久,是时候学习一下shell脚本了。

什么是shell脚本

Shell是操作系统的最外层,管理用户与操作系统之间的交互;等待你的输入,向操作系统输入你的操作,并且处理各种操作系统的输出结果。

Shell 除了能解释用户输入的命令,将它传递给操作系统,还可以:

  1. 调用其他程序,给其他程序传递数据或参数,并获取程序的处理结果;
  2. 在多个程序之间传递数据,把一个程序的输出作为另一个程序的输入;
  3. Shell 本身也可以被其他程序调用。

由此可见,Shell 是将操作系统、程序和用户连接了起来。

Shell 也是一种编程语言,它的编译器(解释器)是 Shell 这个程序。我们平时所说的 Shell,有时候是指连接用户和内核的这个程序,有时候又是指 Shell 编程。

Shell 主要用来开发一些实用的、自动化的小工具,而不是用来开发具有复杂业务逻辑的中大型软件,例如检测计算机的硬件参数、一键搭建Web开发环境、日志分析等,Shell 都非常合适。

几种常见的shell

常见的 Shell 有 sh、bash、csh、tcsh、ash 等。

bash shell 是 Linux 的默认 shell

bash 由 GNU 组织开发,保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。

尽管如此,bash 和 sh 还是有一些不同之处:

一方面,bash 扩展了一些命令和参数;

另一方面,bash 并不完全和 sh 兼容,它们有些行为并不一致,但在大多数企业运维的情况下区别不大,特殊场景可以使用 bash 代替 sh。

查看当前Linux的shell可以用以下命令(SHELL要大写):

echo $SHELL
#我的输出结果是/bin/bash

Ubuntu16.03的shell终端就是Terminology。

Tips:

Shell提示符之中,$代表的是普通用户,#代表的是root用户。

 

Hello World

啥也别说了,编程第一步,Hello World!

新建一个脚本文件test.sh,里面输入如下内容:

#!/bin/bash

echo "Hello World !"

#!是一个约定,告诉系统这个脚本用什么解释器来执行。

Echo是在窗口输出后面的内容。

接着在该文件的同级目录里面打开终端,键入如下内容:

chmod +x ./test.sh

./test.sh

第一行是使之能够执行,第二行是执行该脚本。结果如下:

执行.sh脚本有6种方式,感兴趣的可以参考下面这两位的博客,https://blog.csdn.net/qq_37699336/article/details/80724700

https://blog.csdn.net/zhangxl_ly/article/details/79352644

注释

#开头,单行注释,shell只支持单行注释。

环境变量

由export关键字处理过的变量叫做环境变量。

变量

a=“helloworld”
echo $a
echo “This is ${a} !”
  1. 变量名和等号之间不能有空格,也就是说=的两边都不能有等号
  2. 命名规范和大部分编程语言一致

输出结果如下:

  • 单引号和双引号

一般来说,单引号引起来的内容都是直接输出,即使有变量和命令也不例外,换句话说,在单引号内,变量和命令无效;双引号会先解析里面的变量和命令,然后再输出。

  • 将命令的结果赋值给变量
Log=$(cat log.txt)

Echo $log
  • 只读变量
readonly zyx
  • 删除变量

只能删除普通变量,无法删除只读变量

unset zyx

  • 变量分为局部变量、环境变量、shell变量(特殊变量)

$* 和 $@ 的区别为: $* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

$? 可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。

  • 命令替换

命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。

DATE=`date`

echo "Date is $DATE"

#结果如下

Date is Fri Jan 18 09:15:58 CST 2019
  • 变量替换

可以根据变量的状态(是否为空、是否定义等)来改变它的值.

运算符

使用expr进行操作

  • 算术运算符
val=`expr 2 + 2`

echo "Total value : $val"

注意:

  1. 表达式和运算符之间要有空格。
  2. 完整的表达式要被`反引号包住。
  3. *前面必须加上\才行
  • 关系运算符

只支持数字,不支持字符串,除非这个字符串里面全是数字,当然别忘了空格

  • 布尔运算符

  • 字符串运算符

  • 文件运算符

字符串的一些操作

  • 拼接字符串
your_name="zyx"

greeting="hello, "$your_name" !"

greeting_1="hello, ${your_name} !"

echo $greeting $greeting_1

结果

hello, zyx ! hello, zyx !
  • 获取字符串长度
string="abcd"

echo ${#string} #输出 4
  • 提取字符串
string="zyx is a boy"

echo ${string:1:4} #输出yx i
  • 查找字符串
string="zyx is a boy who is very good!"

echo `expr index "$string" is` #输出5

数组

只支持一维数组,下标的范围没有限制

在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:

array_name=(value0 value1 value2 value3)

读取的格式一般是

${array_name[index]}

使用@ 或 * 可以获取数组中的所有元素,例如:

${array_name[*]}

${array_name[@]}

# 取得数组元素的个数

length=${#array_name[@]}

# 或者

length=${#array_name[*]}

# 取得数组单个元素的长度

lengthn=${#array_name[n]}

printf——加强版echo

prinft没有自带的换行,需要手动增加”\n”。

和C相比,bash的printf不需要加括号。

printf "Hello, Shell\n"

printf "%d %s\n" 1 "abc"

#输出1 abc

条件语句

直接上if..elif..fi吧

if [ expression 1 ]
then
   Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
fi

case…esac语句

同switch语句,break用;;代替,default用*代替。

取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;

case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

for循环

for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done

列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。

in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。

While循环

while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:

while command
do
   Statement(s) to be executed if command is true
Done

Util循环

until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般while循环优于until循环,但在某些时候,也只是极少数情况下,until 循环更加有用。

until command
do
   Statement(s) to be executed until command is true
done

当然,shell也有break和continue,作用于循环之中。另外,break 命令后面还可以跟一个整数,表示跳出第几层循环。

函数

先定义后使用,我推荐在函数前加上关键字 function

function MyFunction () {
    list of commands
    [ return value ]
}

调用函数只需要给出函数名,不需要加括号。

函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。

删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项

unset .f MyFunction
  • 函数参数

调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...

当n>=10时,需要加上{},因此我推荐统一使用${n}来获取参数的值。

输入输出重定向

Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。

重定向>会覆盖文件内容,可以使用 >> 追加到文件末尾

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。

标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。

标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

 

  • Here Document

Here Document 目前没有统一的翻译,这里暂译为”嵌入文档“。Here Document 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:

command << delimiter
    document
delimiter

它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。

注意:

结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。

开始的delimiter前后的空格会被忽略掉。

  • /dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到”禁止输出“的效果。

文件包含

Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。

Shell 中包含脚本可以使用:

. filename

source filename

两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。被包含脚本不需要有执行权限。

例子如图所示,使用main.sh调用test.sh的变量。

 

参考:

https://www.cnblogs.com/yinheyi/p/6648242.html

http://c.biancheng.net/cpp/view/6994.html

http://swiftlet.net/archives/category/swiftlet-shell/funny-shell(趣谈shell)

猜你喜欢

转载自blog.csdn.net/z695516174/article/details/86539738