一文教你入门shell脚本1.0——第一个shell脚本

shell脚本

1、shell是什么

在这里插入图片描述
Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

  • Shell 就是一个“中间商”,它在用户和内核之间“倒卖”数据,只是用户不知道罢了。
  • Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,它和 QQ、迅雷、Firefox等其它软件没有什么区别。然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用Linux,不启动 Shell 的话,用户就没办法使用 Linux。

1.1、Shell 是如何连接用户和内核的?

shell 能够接收用户输入的命令,并对命令进行处理,处理完毕后再将结果反馈给用户,比如输出到显示器、写入到文件等,这就是大部分读者对 Shell 的认知。

你看,我一直都在使用 Shell,哪有使用内核哦?我也没有看到 Shell 将我和内核连接起来呀?

其实,Shell 程序本身的功能是很弱的,比如文件操作、输入输出、进程管理等都得依赖内核。我们运行一个命令,大部分情况下 Shell 都会去调用内核暴露出来的接口,这就是在使用内核,只是这个过程被 Shell 隐藏了起来,它自己在背后默默进行,我们看不到而已。

接口其实就是一个一个的函数,使用内核就是调用这些函数。这就是使用内核的全部内容了吗?嗯,是的!除了函数,你没有别的途径使用内核。

1.2、Shell命令的本质到底是什么?

  • Shell 内置命令的本质是一个自带的函数,执行内置命令就是调用这个自带的函数。因为函数代码在 Shell启动时已经被加载到内存了,所以内置命令的执行速度很快。
    • 内置命令不宜过多,过多的内置命令会导致 Shell 程序本身体积膨胀,运行 Shell 程序后就会占用更多的内存。Shell 是一个常驻内存的程序,占用过多内存会影响其它的程序。
    • Shell内建命令(内置命令)
  • Shell外部命令的本质是一个应用程序,执行外部命令就是启动一个新的应用程序。因为要创建新的进程并加载应用程序的代码,所以外部命令的执行速度很慢。

一个外部的应用程序究竟是如何变成一个 Shell 命令的呢?

  • 应用程序就是一个文件,只不过这个文件是可以执行的。既然是文件,那么它就有一个名字,并且存放在文件系统中。用户在 Shell中输入一个外部命令后,只是将可执行文件的名字告诉了 Shell,但是并没有告诉 Shell 去哪里寻找这个文件。

  • 为了解决这个问题,Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量就保存了 Shell对外部命令的查找路径,如果在这些路径下找不到同名的文件,Shell 也不会再去其它路径下查找了,它就直接报错。

2、shell基本格式

command [选项] [参数]

[]表示可选的,也就是可有可无。有些命令不写选项和参数也能执行,有些命令在必要的时候可以附带选项和参数。

ls 是常用的一个命令,它属于目录操作命令,用来列出当前目录下的文件和文件夹。ls 可以附带选项,也可以不带,

1、不带选项的写法为:

[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ ls
abc          demo.sh    a.out         demo.txt
getsum       main.sh    readme.txt    a.sh
module.sh    log.txt    test.sh       main.c

2、使用选项

[mozhiyan@localhost demo]$ ls -l
总用量 140
-rwxrwxr-x. 1 mozhiyan mozhiyan 8675 42 15:01 a.out
-rwxr-xr-x. 1 mozhiyan mozhiyan  116 43 09:24 a.sh
-rw-rw-r--. 1 mozhiyan mozhiyan   44 42 16:41 check.sh
-rw-r--r--. 1 mozhiyan mozhiyan  399 311 17:12 demo.sh
-rw-rw-r--. 1 mozhiyan mozhiyan    4 48 17:56 demo.txt
-rw-rw-r--. 1 mozhiyan mozhiyan    0 415 17:26 log.txt
-rw-rw-r--. 1 mozhiyan mozhiyan  650 410 11:06 main.c
-rwxrwxr-x. 1 mozhiyan mozhiyan   69 326 10:13 main.sh

3、使用参数
数是命令的操作对象,一般情况下,文件、目录、用户和进程等都可以作为参数被命令操作。

[mozhiyan@localhost demo]$ ls -l main.c
-rw-rw-r--. 1 mozhiyan mozhiyan 650 410 11:06 main.c

3、第一个shell脚本

1、新建 helloworld.sh

[root@centos6-1 ~]# touch helloworld.sh

2、编辑helloworld.sh文件(vi helloworld.sh),添入一下内容

#!/bin/bash
echo "helloworld"
  • #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell,这里指定bash
  • echo 是Shell的一个内部指令,用于在屏幕上打印出指定的字符串

3、赋予当前用户helloworld.sh的执行权限(刚创建的文件没有执行权限)

[root@centos6-1 ~]# chmod u+x helloworld.sh

4、执行hellowo.sh脚本方式一

[root@centos6-1 ~]# ./helloworld.sh 
helloworld

一定要写成./helloworld.sh,而不是helloworld.sh,linux系统会去PATH里寻找有没有叫helloworld.sh的,而helloworld.sh不在PATH里,所以写成helloworld.sh是会找不到命令的,要用./helloworld.sh告诉系统说,就在当前目录找。

5、执行hellowo.sh脚本方式二

[root@centos6-1 ~]# /bin/sh helloworld.sh 
helloworld

这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,当使用这种方式时,脚本中的#!/bin/bash指定的解释器是不生效的,当前使用什么解释器就是什么解释器

下面给出了一段稍微复杂的 Shell 脚本:

#!/bin/bash
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"

在这里插入图片描述
read PERSON从终端读取用户输入的数据,并赋值给 PERSON 变量。read 命令用来从标准输入文件(Standard Input,stdin,一般就是指键盘)读取用户输入的数据。

4、shell编程

4.1、shell变量定义

变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。

  • 在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。
  • 这意味着,Bash shell在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。例如在C语言或者 C++中,变量分为整数、小数、字符串、布尔等多种类型。

4.2、shell变量的使用

1、定义变量
Shell 变量的命名规范和大部分编程语言都一样:

  • 变量名由数字、字母、下划线组成;
  • 必须以字母或者下划线开头;
  • 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。

Shell 支持以下三种定义变量的方式:

variable=value
variable='value'
variable="value"

variable 是变量名,value 是赋给变量的值。如果 value 不包含任何空白符(例如空格、Tab 缩进等),那么可以不使用引号;如果 value 包含了空白符,那么就必须使用引号包围起来。
注意,赋值号=的周围不能有空格

name='C++ program'
echo $name
author="hello "
echo $author

2、使用变量:推荐给所有变量加上花括号{ }
变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界

skill="Java"
echo "I am good at ${skill}Script"

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

url="hello、xixi"
echo ${url}
url="hi,haha"
echo ${url}

已定义的变量,可以被重新赋值

3.只读变量
使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变

name="zaomianbao"
readonly name
name="tiechui"

在这里插入图片描述
4.删除变量
使用unset命令可以删除变量,变量被删除后不能再次使用,同时unset命令不能删除只读变量

name="zaomianbao"
unset name
echo $name

4.2.1、单引号和双引号的区别

#!/bin/bash
name="tiechui"
website1='my name is: ${name}'
website2="my name is: ${name}"
echo $website1
echo $website2

在这里插入图片描述

  • 单引号''包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
  • 双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。
  • 如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。

4.2.2、将命令的结果赋值给变量

Shell 命令替换是指将命令的输出结果赋值给某个变量。比如,在某个目录中输入 ls 命令可查看当前目录中所有的文件,但如何将输出内容存入某个变量中呢?

Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:

variable=`command`
variable=$(command)

variable 是变量名,commands 是要执行的命令。commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号;分隔。

  • 第一种方式把命令用反引号(位于 Esc 键的下方)包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;
  • 第二种方式把命令用$()包围起来,区分更加明显,所以推荐使用这种方式。

实例:
创建了一个名为 log.txt 的文本文件,用来记录我的日常工作。下面的代码中,使用 cat 命令将 log.txt 的内容读取出来,并赋值给一个变量,然后使用 echo 命令输出。

log=$(cat log.txt)
echo $log

log=`cat log.txt`
echo $log

在这里插入图片描述

注意,如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个。请看下面的代码:

#!/bin/bash

LSL=`ls -l`
echo $LSL  #不使用双引号包围
echo "--------------------------"  #输出分隔符
echo "$LSL"  #使用引号包围

运行结果:

total 8 drwxr-xr-x. 2 root root 21 71 2016 abc -rw-rw-r--. 1 mozhiyan mozhiyan 147 1031 10:29 demo.sh -rw-rw-r--. 1 mozhiyan mozhiyan 35 1031 10:20 demo.sh~
--------------------------
total 8
drwxr-xr-x. 2 root     root      21 71 2016 abc
-rw-rw-r--. 1 mozhiyan mozhiyan 147 1031 10:29 demo.sh
-rw-rw-r--. 1 mozhiyan mozhiyan  35 1031 10:20 demo.sh~

4.3、位置参数

运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

这种通过$n的形式来接收的参数,在 Shell 中称为位置参数。

注意事项
如果参数个数太多,达到或者超过了 10 个,那么就得用${n}的形式来接收了,例如 10 {10}、 {23}。{ }的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }是一样的效果。

4.3.1、给脚本文件传递位置参数

请编写下面的代码,并命名为 test.sh

#!/bin/bash

echo "Language: $1"
echo "URL: $2"

运行 test.sh,并附带参数:

[mozhiyan@localhost demo]$ . ./test.sh Shell hello
Language: Shell
URL: hello

其中Shell是第一个位置参数,hello是第二个位置参数,两者之间以空格分隔。

4.3.2、给函数传递位置参数

#!/bin/bash

#定义函数
function func(){
    echo "Language: $1"
    echo "URL: $2"
}

#调用函数
func C++ hello

运行 test.sh:
[mozhiyan@localhost demo]$ . ./test.sh
Language: C++
URL: hello

参考

1、http://c.biancheng.net/view/706.html
2、http://c.biancheng.net/view/3146.html

猜你喜欢

转载自blog.csdn.net/JMW1407/article/details/107400477