Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。
shell 能够接收用户输入的命令,并对命令进行处理,处理完毕后再将结果反馈给用户,比如输出到显示器、写入到文件等,这就是大部分读者对 Shell 的认知。
你看,我一直都在使用 Shell,哪有使用内核哦?我也没有看到 Shell 将我和内核连接起来呀?
其实,Shell 程序本身的功能是很弱的,比如文件操作、输入输出、进程管理等都得依赖内核。我们运行一个命令,大部分情况下 Shell 都会去调用内核暴露出来的接口,这就是在使用内核,只是这个过程被 Shell 隐藏了起来,它自己在背后默默进行,我们看不到而已。
接口其实就是一个一个的函数,使用内核就是调用这些函数。这就是使用内核的全部内容了吗?嗯,是的!除了函数,你没有别的途径使用内核。
一个外部的应用程序究竟是如何变成一个 Shell 命令的呢?
应用程序就是一个文件,只不过这个文件是可以执行的。既然是文件,那么它就有一个名字,并且存放在文件系统中。用户在 Shell中输入一个外部命令后,只是将可执行文件的名字告诉了 Shell,但是并没有告诉 Shell 去哪里寻找这个文件。
为了解决这个问题,Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量就保存了 Shell对外部命令的查找路径,如果在这些路径下找不到同名的文件,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 4月 2 15:01 a.out
-rwxr-xr-x. 1 mozhiyan mozhiyan 116 4月 3 09:24 a.sh
-rw-rw-r--. 1 mozhiyan mozhiyan 44 4月 2 16:41 check.sh
-rw-r--r--. 1 mozhiyan mozhiyan 399 3月 11 17:12 demo.sh
-rw-rw-r--. 1 mozhiyan mozhiyan 4 4月 8 17:56 demo.txt
-rw-rw-r--. 1 mozhiyan mozhiyan 0 4月 15 17:26 log.txt
-rw-rw-r--. 1 mozhiyan mozhiyan 650 4月 10 11:06 main.c
-rwxrwxr-x. 1 mozhiyan mozhiyan 69 3月 26 10:13 main.sh
3、使用参数
数是命令的操作对象,一般情况下,文件、目录、用户和进程等都可以作为参数被命令操作。
[mozhiyan@localhost demo]$ ls -l main.c
-rw-rw-r--. 1 mozhiyan mozhiyan 650 4月 10 11:06 main.c
1、新建 helloworld.sh
[root@centos6-1 ~]# touch helloworld.sh
2、编辑helloworld.sh文件(vi helloworld.sh
),添入一下内容
#!/bin/bash
echo "helloworld"
#!
是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell,这里指定bash
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,一般就是指键盘)读取用户输入的数据。
变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。
1、定义变量
Shell 变量的命名规范和大部分编程语言都一样:
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
#!/bin/bash
name="tiechui"
website1='my name is: ${name}'
website2="my name is: ${name}"
echo $website1
echo $website2
单引号''
包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。双引号" "
包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。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 7月 1 2016 abc -rw-rw-r--. 1 mozhiyan mozhiyan 147 10月 31 10:29 demo.sh -rw-rw-r--. 1 mozhiyan mozhiyan 35 10月 31 10:20 demo.sh~
--------------------------
total 8
drwxr-xr-x. 2 root root 21 7月 1 2016 abc
-rw-rw-r--. 1 mozhiyan mozhiyan 147 10月 31 10:29 demo.sh
-rw-rw-r--. 1 mozhiyan mozhiyan 35 10月 31 10:20 demo.sh~
运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1
表示第一个参数,$2
表示第二个参数,依次类推。
在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
这种通过$n
的形式来接收的参数,在 Shell 中称为位置参数。
注意事项
如果参数个数太多,达到或者超过了 10 个,那么就得用${n}
的形式来接收了,例如 10 、 {10}、 10、{23}。{ }
的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }是一样的效果。
请编写下面的代码,并命名为 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
是第二个位置参数,两者之间以空格
分隔。
#!/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