1. Shell编程第一讲
(1)shell 历史:
Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive)。
Shell还有一种执行命令的方式称为批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。
Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。
由于历史原因,UNIX系统上有很多种Shell:
<1.> sh(Bourne Shell):由Steve Bourne开发,各种UNIX系统都配有sh。
<2.> csh(C Shell):由Bill Joy开发,随BSD UNIX发布,它的流程控制语句很像C语言,支持很多Bourne Shell所不支持的功能:作业控制,命令历史,命令行编辑。
<3.> ksh(Korn Shell):由David Korn开发,向后兼容sh的功能,并且添加了csh引入的新功能,是目前很多UNIX系统标准配置的Shell,在这些系统上/bin/sh往往是指向/bin/ksh的符号链接。
<4.> tcsh(TENEX C Shell):是csh的增强版本,引入了命令补全等功能,在FreeBSD、Mac OS X等系统上替代了csh。
<5.> bash(Bourne Again Shell):由GNU开发的Shell,主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,bash从csh和ksh借鉴了很多功能,是各种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。虽然如此,bash和sh还是有很多不同的,一方面,bash扩展了一些命令和参数,另一方面,bash并不完全和sh兼容,有些行为并不一致,所以bash需要模拟sh的行为:当我们通过sh这个程序名启动bash时,bash可以假装自己是sh,不认扩展的命令,并且行为与sh保持一致。
<6.> zsh 的命令补全功能非常强大,可以补齐路径,补齐命令,补齐参数等。
用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。
以前学过的cd、alias、umask、exit等命令即是内建命令,凡是用which命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册,要在man手册中查看内建命令,应该
$ man bash-builtins
如export、shift、if、eval、[、for、while等等。内建命令虽然不创建新的进程,但也会有Exit Status,通常也用0表示成功非零表示失败,虽然内建命令不创建新的进程,但执行结束后也会有一个状态码,也可以用特殊变量$?读出。
(2)执行简单脚本:
编写一个简单的脚本test.sh:
#! /bin/sh
cd ..
ls
Shell脚本中用#表示注释,相当于C语言的//注释。但如果#位于第一行开头,并且是#!(称为Shebang)则例外,它表示该脚本使用后面指定的解释器/bin/sh解释执行。
如果把这个脚本文件加上可执行权限然后执行:
chmod a+x test.sh
./test.sh
Shell会fork一个子进程并调用exec执行./test.sh这个程序,exec系统调用应该把子进程的代码段替换成./test.sh程序的代码段,并从它的_start开始执行。然而test.sh是个文本文件,根本没有代码段和_start函数,怎么办呢?
其实exec还有另外一种机制,如果要执行的是一个文本文件,并且第一行用Shebang指定了解释器,则用解释器程序的代码段替换当前进程,并且从解释器的_start开始执行,而这个文本文件被当作命令行参数传给解释器。因此,执行上述脚本相当于执行程序
$ /bin/sh ./test.sh
以这种方式执行不需要test.sh文件具有可执行权限。
如果将命令行下输入的命令用()括号括起来,那么也会fork出一个子Shell执行小括号中的命令,一行中可以输入由分号;隔开的多个命令,比如:
$ (cd ..;ls -l)
和上面两种方法执行Shell脚本的效果是相同的,cd ..命令改变的是子Shell的PWD,而不会影响到交互式Shell。然而命令
$ cd ..;ls -l
则有不同的效果,cd ..命令是直接在交互式Shell下执行的,改变交互式Shell的PWD,然而这种方式相当于这样执行Shell脚本:
$ source ./test.sh
或者:
$ . ./test.sh
source或者.命令是Shell的内建命令,这种方式也不会创建子Shell,而是直接在交互式Shell下逐行执行脚本中的命令。
(3)基本语法:
(3.1) 变量:
<1.> 环境变量
环境变量可以从父进程传给子进程,因此Shell进程的环境变量可以从当前Shell进程传给fork出来的子进程。用printenv命令可以显示当前Shell进程的环境变量。
<2.> 本地变量
只存在于当前Shell进程,用set命令可以显示当前Shell进程中定义的所有变量(包括本地变量和环境变量)和函数。
环境变量是任何进程都有的概念,而本地变量是Shell特有的概念。在Shell中,环境变量和本地变量的定义和用法相似。在Shell中定义或赋值一个变量:
$ VARNAME=value
注意等号两边都不能有空格,否则会被Shell解释成命令和命令行参数。
一个变量定义后仅存在于当前Shell进程,它是本地变量,用export命令可以把本地变量导出为环境变量,定义和导出环境变量通常可以一步完成:
$ export VARNAME=value
也可以分两步完成:
$ VARNAME=value
$ export VARNAME
用unset命令可以删除已定义的环境变量或本地变量:
$ unset VARNAME
如果一个变量叫做VARNAME,用${VARNAME}可以表示它的值,在不引起歧义的情况下也可以用$VARNAME表示它的值。通过以下例子比较这两种表示法的不同:
$ echo $SHELL
注意,在定义变量时不用$,取变量值时要用$。和C语言不同的是,Shell变量不需要明确定义类型,事实上Shell变量的值都是字符串,比如我们定义VAR=45,其实VAR的值是字符串45而非整数。Shell变量不需要先定义后使用,如果对一个没有定义的变量取值,则值为空字符串。
(3.2) 文件名代换(Globbing): * ? []
这些用于匹配的字符称为通配符(Wildcard),具体如下:
* 匹配0个或多个任意字符
? 匹配一个任意字符
[若干字符] 匹配方括号中任意一个字符的一次出现
$ ls /dev/ttyS*
$ ls ch0?.doc
$ ls ch0[-].doc
$ ls ch[] [-].doc
注意,Globbing所匹配的文件名是由Shell展开的,也就是说在参数还没传给程序之前已经展开了,比如上述ls ch0[012].doc命令,如果当前目录下有ch00.doc和ch02.doc,则传给ls命令的参数实际上是这两个文件名,而不是一个匹配字符串。
(3.3) 命令代换: `或 $()
由'`'反引号括起来的也是一条命令,Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。例如定义一个变量存放date命令的输出:
$ DATE=`date`
$ echo $DATE
命令代换也可以用$()表示:
$ DATE=$(date)
(3.4) 算术代换:$(())
用于算术计算,$(())中的Shell变量取值将转换成整数,同样含义的$[]等价例如:
$ VAR=
$ echo $(($VAR+)) # $(())中只能用+-*/和()运算符,并且只能做整数运算。
# $[base#n],其中base表示进制,n按照base进制解释,后面再有运算数,按十进制解释。 echo $[#+] # 13
echo $[#+] # 19
echo $[#+] # 21
(3.5) 转义字符 \
和C语言类似,\在Shell中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值。例如:
$ echo $SHELL
/bin/bash
$ echo \$SHELL
$SHELL
$ echo \\
\
比如创建一个文件名为“$ $”的文件可以这样:
$ touch \$\ \$
还有一个字符虽然不具有特殊含义,但是要用它做文件名也很麻烦,就是-号。如果要创建一个文件名以-号开头的文件,这样是不行的
$ touch -hello
touch: invalid option -- h
Try `touch --help' for more information. # 即使加上\转义也还是报错: $ touch \-hello
touch: invalid option -- h
Try `touch --help' for more information.
因为各种UNIX命令都把-号开头的命令行参数当作命令的选项,而不会当作文件名。如果非要处理以-号开头的文件名,可以有两种办法:
$ touch ./-hello
或者:
$ touch -- -hello
\还有一种用法,在\后敲回车表示续行,Shell并不会立刻执行命令,而是把光标移到下一行,给出一个续行提示符>,等待用户继续输入,最后把所有的续行接到一起当作一个命令执行。例如:
$ ls \
> -l
(ls -l命令的输出)
(3.6) 单引号:
和C语言不一样,Shell脚本中的单引号和双引号一样都是字符串的界定符(双引号下一节介绍),而不是字符的界定符。单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。如果引号没有配对就输入回车,Shell会给出续行提示符,要求用户把引号配上对。例如:
$ echo '$SHELL'
$SHELL
$ echo 'ABC\(回车)
> DE'(再按一次回车结束命令)
ABC\
DE
(3.7) 双引号:
被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引号的处理方式不同
$ DATE=$(date)
$ echo "$DATE"
2018年 07月 16日 星期一 :: CST
$ echo '$DATE'
$DATE
$ echo "$DATE+3"
2018年 07月 16日 星期一 :: CST+3 $ echo '$DATE+3'
$DATE+
1. Shell编程第一讲的更多相关文章
- 2. Shell编程第二讲
(1) 条件测试: test [ 命令 test 或 [ 可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测试结果为假,则命令的Exit Status为1(注 ...
- shell编程第一天
shell编程基础 脚本:简单来说就是一条条的文字命令(一些指令的堆积)Shell属于内置的脚本 1.程序开发效率非常高,依赖于功能强大的命令可以迅速地完成开发任务(批处理) 2.语法简单,代码写起来 ...
- C#面对抽象编程第一讲
闲话不多说,面向对象编程是高级语言的一个特点,但是把它概括成面向抽象更容易直击灵魂,经过了菜鸟大家都要面对的是不要写这么菜的代码了. 上例子,这应该是大家都很熟悉耳熟能详的代码, so easy. 1 ...
- windows编程之Windows Shell 编程
参考书<VC++ Windows Shell Programming> 这里仅仅是记录下该资源,推荐到下文列出的连接进行查看 用VC++ 进行Windows Shell 扩展编成 ...
- shell编程企业级实战
如何才能学好Shell编程 为什么要学习shell编程 Shell是Linux底层核心 Linux运维工作常用工具 自动化运维必备基础课程 学好shell编程所需Linux基础 熟练使用vim编辑器 ...
- MFC控件第一讲.DC编程
MFC控件第一讲.DC编程 一丶简介 什么是DC,DC有什么用. DC成为设备描述符表. DC的作用就是可以进行绘制. 比如我们的窗口都是绘制出来的. DC可以简单理解为.没一个窗口程序都有一块内存 ...
- shell编程学习笔记(一):编写我的第一段代码
目前在学习Shell编程,我会把我的学习笔记记录在这里.大神可以直接略过~ 嗯,第一段代码,肯定是要输出Hello World了~ 以下蓝色字体的内容为linux命令,红色字体的内容为输出的内容: # ...
- 【Shell 编程基础第一部分】第一个Shell脚本HelloShell及一些简单的Shell基础书写与概念;
http://blog.csdn.net/xiaominghimi/article/details/7603000 本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区 ...
- 少儿编程Scratch第一讲:Scratch完美的初体验
素材及视频下载 链接:https://pan.baidu.com/s/1qX0T2B_zczcLaCCpiRrsnA提取码:xfp8 都说未来是人工智能.计算机程式控制的时代,如何让青少年接触计算机编 ...
随机推荐
- requirejs——define——普通模块
一.普通模块可能包含的内容: 一个模块对应着一个js文件,由于模块可能包含着以下三种内容:模块名.依赖模块.返回给其他模块使用的参数:因此js文件根据包含内容的不同而写法不同. 一.传统的js脚本文件 ...
- pandas读写excel
import pandas as pd import numpy as np df = pd.read_csv("result.csv") # csv # df = pd.read ...
- 1 任务管理 --转载于电子工程世界
uC/OS-II 中最多可以支持64 个任务,分别对应优先级0-63,其中0 为最高优先级.63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务,所有用户可以使用的任务数有56个. uC ...
- 可变、不可变数据类型和hash
一.可变和不可变数据类型 在python中,我们对数据类型除了分为数字类型.字符串类型.列表类型.元组类型.字典类型和集合类型外, 还有另外一种分类方式,我们给数据类型分为可变数据类型和不可变数据类型 ...
- 02.socket实现远程调用
不使用webservice使用以前的知识也可以实现远程系统之间的调用.用Socket可以.实现Socket通信. 开设一个端口.ip.
- 仿函数(二、stl中常用仿函数)
提到C++ STL,首先被人想到的是它的三大组件:Containers, Iterators, Algorithms,即容器,迭代器和算法.容器为用户提供了常用的数据结构,算法大多是独立于容器的常用的 ...
- 【bzoj1018】[SHOI2008]堵塞的交通traffic
1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 2887 Solved: 954[Submit ...
- 一个jquery在不同浏览器下的兼容性问题。
<div id ='pdiv' style='visibility:hidden;'> <div id='cdiv'>子元素</div> </div> ...
- c++ 桥接模式(bridge)
桥接模式的目的是分离抽象实现部分,把数据和实现分开,降低耦合.桥接模式和适配器模式不同之处是,桥接模式一般会在软件设计初考虑使用,适配器模式在软件设计之后为了实现接口兼容时使用. 下面是系统和电脑之间 ...
- LoadRunner使用问题
最近给客户做POC,为了测试大数据的框架的一个并发能力,使用loadrunner进行相关的测试,目前发现几个要注意的地方 1: loadrunner的Java脚本必须使用jdk1.6的32位版本 2: ...