Shell学习笔记(一)

一、相关概述

1、图形界面和命令行要达到的目的是一样的,都是让用户控制计算机。然而,真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核(Kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁。

2、用户不能直接接触内核,这时候需要开发一个程序作为中间代理,将用户的操作需求转化为内核能接受的信息进行传入,而用户界面和命令行就是充当这个中间代理角色的程序。在Linux下,这个命令行就叫做Shell。

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

4、任何代码最终都要被“翻译”成二进制的形式才能在计算机中执行。有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码,这个过程叫做编译,这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器。而有的编程语言,如 Shell、JavaScript、Python、PHP等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完,这个过程叫做解释,完成解释过程的软件叫做解释器。

补充:编译型语言的优点是执行速度快、对硬件要求低、保密性好,适合开发操作系统、大型应用程序、数据库等。脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合Web开发以及小工具的制作。

二、常见的Shell

1、sh

sh 的全称是 Bourne shell,由 AT&T 公司的 Steve Bourne开发,为了纪念他,就用他的名字命名了。sh 是 UNIX 上的标准 shell,很多 UNIX 版本都配有 sh。sh 是第一个流行的 Shell。

2、csh

sh 之后另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计的,这个 shell 的语法有点类似C语言,所以才得名为 C shell ,简称为 csh。Bill Joy 是一个风云人物,他创立了 BSD 操作系统,开发了 vi 编辑器,还是 Sun 公司的创始人之一。BSD 是 UNIX 的一个重要分支,后人在此基础上发展出了很多现代的操作系统,最著名的有 FreeBSD、OpenBSD 和 NetBSD,就连 Mac OS X 在很大程度上也基于BSD。

3、tcsh

tcsh 是 csh 的增强版,加入了命令补全功能,提供了更加强大的语法支持。

4、ash

一个简单的轻量级的 Shell,占用资源少,适合运行于低内存环境,但是与下面讲到的 bash shell 完全兼容。

5、bash

bash shell 是 Linux 的默认 shell,本教程也基于 bash 编写。bash 由 GNU 组织开发,保持了对 sh shell 的兼容性,是各种 Linux 发行版默认配置的 shell。

6、查看当前系统支持的sh
$ cat /etc/shells

7、查看当前系统默认使用的sh
$ echo $SHELL

三、Hello示例

1、新建脚本文件,后缀随意,见名知意即可,eg : test.sh;

2、编辑内容如下:

#!/bin/bash
#声明本脚本使用的解释器

# Copyright (c) http://c.biancheng.net/shell/

#输出文字
echo "What is your name?"

#读取用户输入,并将用户输入内容赋值给PERSON变量
read PERSON

#输入变量内容
echo "Hello, $PERSON"

3、Shell脚本执行:

$ cd demo  #切换到 test.sh 所在的目录
$ chmod +x ./test.sh  #使脚本具有执行权限
$ ./test.sh  #执行脚本

补充:使用点号“.”即使没有可执行权限依然能够运行。

四、基本语法

1、变量

a. 变量不需要指明类型,直接赋值即可,也可以使用declare关键字显示定义变量的类型;

b. 变量定义方式:单引号、双引号、都不带;

c. 赋值号=的周围不能有空格;

d. 命名规则和大部分编程语言一致;

e. 变量输出时,需要在变量名前加$,而花括号{}可加可不加,加为了区分边界;

f. 只读变量声明:readonly;

g. 删除变量:unset variable_name

单引号和双引号的区别:前者原样输出内容,而后者存在变量是支持解释。

2、变量的作用域(Scope)

  • 有的变量可以在当前 Shell 会话中使用,这叫做全局变量(global variable);
  • 有的变量只能在函数内部使用,这叫做局部变量(local variable);
  • 有的变量还可以在其它 Shell 中使用,这叫做环境变量(environment variable)。

全局变量:当前会话有效,声明方式可以使用命令行直接声明,或者在脚本中声明。声明的变量在同一会话下都有效。

局部变量:脚本文件内的函数定义的变量,默认也是全局变量,只有在变量前显示使用local进行声明才是局部变量。

环境变量: 使用export关键字将变量导出,定义的变量在字Shell中也有效,但是关闭Shell会话后它就自动销毁。永久保留的方式是把环境变量写入启动文件。

3、给脚本传递位置参数

脚本test.sh代码如下:

#!/bin/bash

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

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

$ . ./a.sh Shell http://c.biancheng.net/shell/

4、给函数传递位置参数
脚本test.sh代码如下:

#!/bin/bash
#定义函数
function func(){
    echo "Language: $1"
    echo "URL: $2"
}
#调用函数
func C++ http://c.biancheng.net/cplus/

执行test.sh:

$. ./test.sh

5、特殊变量

变量 含义
$0 当前脚本的文件名。
$n(n≥1) 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同,我们将在《Shell *和@的区别》一节中详细讲解。
$? 上个命令的退出状态,或函数的返回值,我们将在《Shell $?》一节中详细讲解。
$$ 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。

*与@区别:当被“”包围时,前者将所有的参数从整体上看做是一份数据,而不是把每一个参数都看做一份数据,for循环时,只循环一遍,而后者则将每一个参数作为一份数据,彼此之间独立。

6、Shell命令替换: 理解为将指令的执行结果赋值给变量

示例:

#方式一:使用反应号将指令包围
var_name1 = `date`

#方式二:使用$()将指令包围
var_name2 = $(date)

echo $var_name1
echo $var_name2

注意:变量输出时,不使用“”包围的话,换行符、连续空白等格式都将会被压缩成一个空格,而使用“”包围则会按照原样格式进行输出。

7、字符串

  • 由单引号’ '包围的字符串:任何字符都会原样输出,在其中使用变量是无效的,而且字符串中不能出现单引号,转义也不行;
  • 由双引号包围的字符串:如若其中包含变量,变量会自动解析,字符串中可以包含双引号,但需要转义;
  • 不被引号包围:出现变量依然能被解析,但是字符串中不能出现空格,否则空格之后的将会作为新的变量进行处理。

获取字符串的长度:

#!/bin/bash

str="http://c.biancheng.net/shell/"

echo ${$str}

**字符串连接:**直接将变量并在一起即可

#!/bin/bash

#全是变量
name="Shell"
url="http://c.bian.com"
str1=$name$url #没被任何一种引号包围时,不能有空格,否则被误认为字符串结束
str2="$name $url" #中间允许有空格
#非全变量
str3=$name":"$url #中间允许其他符号
str4="${name}Script:${url}index.html"

echo $str1
echo $str2
echo $str3
echo $str4

字符串截取:

(1)从指定位置开始截取

#!/bin/bash

url="c.biancheng.net"

#从左边开始计数
echo ${url:2:9} #从第2个字符开始,截取九个长度的字符串
echo ${url:2} #从第2个字符开始,截取到末尾

#从右边开始计数
echo ${url:0-13:9}
echo ${url:0-13} #截取到末尾

(2)从指定字符串开始截取

特点:这种截取方式无法指定字符串的长度,只能从指定字符开始截到末尾,但可以选择右边所有字符或者左边所有字符

使用#截取右边所有字符:从左往右

#!/bin/bash

url="http://test.com"
#使用#指定获取字符右边的所有字符,其中*是表示忽略左边的字符
echo ${url#*:} #结果输出://test.com
echo ${url#:} #结果输出:http://test.com

#使用#默认匹配从左往右首个匹配到的字符,若要匹配最后一个匹配的字符,则使用两个#
url="http://test.com/index.html"
echo ${url#*/} #结果输出:/test.com/index.html
echo ${url##*/} #结果输出:index.html

使用%截取左边所有字符:从右往左

#!/bin/bash
url="http://c.biancheng.net/index.html"
echo ${url%/*}  #结果为 http://c.biancheng.net
echo ${url%%/*}  #结果为 http:
str="---aa+++aa@@@"
echo ${str%aa*}  #结果为 ---aa+++
echo ${str%%aa*}  #结果为 ---

两者用法一致,方向相反而已。

8、Shell数组:

Shell并没有限制数组的大小,理论上可以存放无限量的数据。数组元素的下标也是从0开始计数,获取数组中的元素要使用下标[]。常用的Bash Shell只支持以为数组,不支持多为数组。

数组定义

#数组元素之间使用空格分隔,数组元素不要求类型相同
num=(20 39 49 55 "http://test.com")

#追加元素
num[5]=88

#给指定元素赋值
ages=([3]=23 [5]=19 [10]=12)

获取数组元素

#获取单个元素值
n=${nums[2]}

#获取所有元素值
${nums[*]}
${nums[@]}

nums=(29 100 13 8 91 44)
echo ${nums[@]}  #输出所有数组元素
nums[10]=66  #给第10个元素赋值(此时会增加数组长度)
echo ${nums[*]}  #输出所有数组元素
echo ${nums[4]}  #输出第4个元素

运行结果:
29 100 13 8 91 44
29 100 13 8 91 44 66
91

获取数组长度

使用@或者*,可以将数组扩展成为列表,然后使用#来获取数组的个数:

#!/bin/bash

nums=(29 100 13)
echo ${#nums[*]}

#向数组中添加元素
nums[10]="http://c.biancheng.net/shell/"
echo ${#nums[@]}
echo ${#nums[10]}

#删除数组元素
unset nums[1]
echo ${#nums[*]

运行结果:
3
4
29
3

数组拼接

拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。示例如下:

#!/bin/bash

array1=(23 56)
array2=(99 "http://c.biancheng.net/shell/")

array_new=(${array1[@]} ${array2[*]})
echo ${array_new[@]}  #也可以写作 ${array_new[*]}

#运行结果:
#23 56 99 http://c.biancheng.net/shell/

删除数组

在 Shell 中,使用 unset 关键字来删除数组元素,具体示例如下:

#!/bin/bash

arr=(23 56 99 "http://c.biancheng.net/shell/")

unset arr[1]
echo ${arr[@]}

unset arr
echo ${arr[*]}

#运行结果:
#23 99 http://c.biancheng.net/shell/
#

9、Shell内建指令(内置指令)

所谓 Shell 内建命令,就是由 Bash 自身提供的命令,而不是文件系统中的某个可执行文件。

10、Shell alias:给命令创建别名

查看那些指令被默认创建了别名;

[root@localhost ~]# alias
alias cp='cp -i'
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

自定义别名:使用 alias 定义的别名命令也是支持 Tab 键补全的

alias myShutdown='shutdown -h now'

注意,这样定义别名只能在当前 Shell 环境中有效,换句话说,重新登录后这个别名就消失了。为了确保永远生效,可以将该别名手动写入到用户主目录中的.bashrc文件。

.bashrc其实也是一个 Shell 脚本文件,该文件专门用来存放用户自定义的别名和函数。

将别名写入.bashrc文件后的效果如下所示:

# .bashrc
# User specific aliases and functions

alias myShutdown='shutdown -h now'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

unalias:删除别名

使用 unalias 内建命令可以删除当前 Shell 环境中的别名。unalias 有两种使用方法:

  • 第一种用法是在命令后跟上某个命令的别名,用于删除指定的别名。
  • 第二种用法是在命令后接-a参数,删除当前 Shell 环境中所有的别名。

同样,这两种方法都是在当前 Shell 环境中生效的。要想永久删除在.bashrc文件中定义的别名,只能进入该文件手动删除。

11、echo命令

(1)添加-n参数不换行;

(2)添加-e参数显示转义字符;

(3)添加-e参数,配合\c转义字符强制不换行;

12、exit命令

(1)脚本内执行exit,结束代码运行,退出Shell脚本;

(2)终端执行exit,退出当前登录的Shell,并结束终端;

13、Shell ulimit命令:显示并设置进程资源限度

系统的可用资源是有限的,如果不限制用户和进程对系统资源的使用,则很容易陷入资源耗尽的地步,而使用 ulimit 命令可以控制进程对可用资源的访问(ulimit 是一个 Shell 内置命令)。

默认情况下 Linux 系统的各个资源都做了软硬限制,其中硬限制的作用是控制软限制(换言之,软限制不能高于硬限制)。使用ulimit -a可以查看当前系统的软限制,使用命令ulimit -a –H可查看系统的硬限制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章