shell编程

shell

运行脚本

Linux 程序有三种方式运行:

  1. 使文件具有可执行权限,直接运行文件
  2. 直接调用命令解释器执行文件
  3. 使用 source. 执行文件

区别

​ 一: 第一种和第二种类似,区别只是 谁来寻找 命令解释器。第一种是通过文件顶部的 #! 来指定,第二种是直接指定。这两种方式,都会新fork一个子进程来运行程序。第三种 则是在本进程中执行程序。

​ 二: 因为第一种是通过顶部的 #!内容来运行指定的命令解释器。因此程序顶部的语句必然会运行。而第二种和第三种因为只直接指定了运行该程序的命令解释器,因此不会运行程序顶部的语句。

#!/bin/rm
echo "hello world"

当使用第一种方式运行该程序时,会发现,该程序会被自己删除,且永远不会用打印语句出现。然而,第二种和第三种方式运行该程序时,该文件会一直存在,且成功打印语句。

变量

shell 变量有几个特点:

  1. 变量赋值时, = 两边不能有空格,否则变量名会被认为为命令
  2. 双引号引起的变量是可以替换的。单引号引起的变量不能 替换。
  3. 局部变量必须用 关键字 local 声明,否则,即使该变量在函数内部被声明,依旧是全局变量。声明全局变量不需要加修饰符。默认就是全局变量。
  4. $haha${haha} 的简写
    5.如果变量值多余一个单词,那么需要用引号将其引起来。
#!/bin/bash
  
name="ann"

function test(){
    fav="dota"
    local hate="get up"  # 定义局部变量

    echo "in of function test ----> $name"
    echo "in of function test ----> $fav"
    echo "in of function test ----> $hate"

    name="yang"
    echo "change name in test $name"
}

test

echo "out of function test ----> $name"
echo "out of function test ----> $fav"
echo "out of function etst ----> $hate"
# ----------------------------------------------
in of function test ----> ann  
in of function test ----> dota  # 函数内部创建全局变量
in of function test ----> get up
change name in test yang  # 函数内部修改  变量值
out of function test ----> yang  #  波及到了函数外部的变量值
out of function test ----> dota  #  函数外部该全局变量依旧存在
out of function etst ---->       #  局部变量在函数外部不存在

echo 用于打印输出

export 用于配置环境变量

unset 用于删除变量

函数

shell 有两种方式来创建函数:

  1. function name(){}
  2. name(){}

shell 调用函数直接使用函数名即可。

nction first(){
    echo "I'm first fun"
}

second(){
    echo "I'm sechod fun"
}

function third(){
    echo "x == $1"
    echo "y == $2"
}


first
second
third 1 2

参数

通过传参,可以将外部的值,传递到 shell 脚本函数中。

shell 参数分 位置参数 全局参数 局部参数

位置参数

参数名称 参数意义
0, 1,2,3,4 … 位置参数,0表示脚本名(不一定是函数名);其余为位置参数。最大为9,如果超过9个了, 那么 $1 这类写法已经行了,得用 ${10}
* 一个字符串 显示多有向脚本传递的参数
@ 从 参数 1 开始显示所有向脚本传递的参数。如果被双引号引起来了“$@”,那么等同于逐次调用$1 $2….
# 参数数量,不含 参数0 (即脚本名)
$ 脚本运行的当前进程ID
! 后台运行的最后一个进程 ID
显示最后命令的 退出状态 0 表示正常

管道与重定向

标准输入

文件描述符 0

cat 0</tmp/b.txt

标准输出

文件描述符 1

cat /tmp/.b.txt  > /dev/null    2>/dev/null
cat /tmp/b.txt  1>/dev/null    2>/dev/null
cat /tmp/b.txt  &>/dev/null

&表示标准输出和标准错误

标准错误

文件描述符 2
使用样例

grep 'a' /tmp/zz.log  2>/dev/null

重定向

> (目标不存在就创建)

重定向追加

>> (目标不存在就创建)

管道

|

管道的作用是以 前一个命令的输出作为下一个命令的输入。

ls | grep  *.log

该命令并不是说,将 ls 的结果, 放到 grep 的前面,即 grep| 之间,而是说,将 ls 的结果 作为 grep 的 输入, grep 命令 这样的 grep 字符串 文件名 , 所以, 管道连接 ls 的结果之后,它的意思是,ls 的结果就是 文件名

文件描述符

内核(kernal)通过文件描述符(file descriptor)访问文件。 文件描述符是非负整数,打开已有文件,或创建新文件时,内核都会返回一个文件描述符。读写文件也需要使用文件描述符还指定特定的读写文件。

文件描述符表

位于用户空间,进程中的每个打开的文件,文件描述符表都有一个对应的条目(感觉类似于,一个文件,一个代号),每个进程都有自己的文件描述符表,自己对其维护。当进程调用文件描述符相关函数或命令时,会对其进行修改。

系统文件表

为系统中所有进程所共享。每个系统文件表的条目都包含文件的偏移量,访问模式(读、写、读写),以及指向它的文件描述符表的条目的数量。

每个进程的文件表在系统文件表中的区域都是不重合的。这种安排是为了使每个进程都有它自己对该文件的当前偏移量

内存索引节点表

对于系统中每个活动的文件(即被某个进程打开了),内存中都有索引节点表包含一个条目,几个系统文件表条目可能对应同一个内存索引节点表(即 不同进程打开同一个文件)

关系

每个进程维护自己的文件描述符表,文件描述符表中的每一项指向系统文件表,系统文件表指向内存索引节点表。

这样进程通过对文件描述符表的操作,,访问内存中索引节点表控制的文件。

文件描述符

文件描述符是由无符号整数表示的句柄,进程 用它来表示文件。文件描述符与包括相关信息(如文件打开模式,文件位置,文件初始类型)等文件对象关联,这些信息被称为上下文。
进程获取文件描述符的常用方法是本机子例程 opencreate 文件。或通过 fork 从父进程中继承。

特殊文件

/dev/null

可以把 /dev/null 想想成一个黑洞,所有写入它里面的内容都会丢失。

/dev/zero

类似于 /dev/null ,其作用主要用来创建一个指定长度,并且初始化为空的文件,这种文件一般作为临时交换文件。

/dev/tty

表示当前终端,既可以从该文件获取内容(在终端写入),也可以将内容写入到该文件,从而在终端显示。

原文地址:https://www.cnblogs.com/jijizhazha/p/9943171.html