Skip to content

Latest commit

 

History

History
618 lines (354 loc) · 23.1 KB

File metadata and controls

618 lines (354 loc) · 23.1 KB

Linux Shell编程

Shell是一种具备特殊功能的程序,它提供用户与内核进行交互操作的接口。它接受用户输入的命令,并把它送入内核去执行。

Shell可以提供直接在Linux进行打开操作,而可以提供SSH方式远程登录操作。

Shell编程就是编写Shell脚本文件。

Shell脚本文件使用的是Shell脚本语言。它运行于底层内核,所以相较于普通编译型语言来说,它不需要编译、链接、运行等繁琐操作,直接即可在Linux系统中运行。Shell脚本通常以.sh后缀存在,可使用文本工具如vi进行编辑。

#!/bin/bash

cd	#切换到用户根目录
..bash_profile	#配置用户的命令行环境
date	#显示日期命令
who		#显示当前登录的用户

上面是一个简单的Shell脚本。

Shell脚本通常以#!/bin/bash开头,也可以是#!/bin/sh#!符号称为"Sha-bang"符号,是Shell脚本的起始符号,它告诉Linux系统这个文件的执行需要一个解释器。对于一般的Shell脚本而言,解释器是bash,也可以是sh。当然Linux系统中还存在其它的一些解释器,如sed、awk等等。当然大多数Shell脚本都是使用bash解释器。

Shell脚本语言中使用单的#符号当作单行注释符号。

Shell脚本语言中的大多数命令,可以在Shell命令行中直接执行。

Linux系统中存在上万条命令,基本上很难全部掌握它们,对于某些命令,当忘记如何使用、命令的选项时,可以使用Linux系统提供的命令手册指令:

man [命令名称]

man是Linux程序员和管理员用于查询命令用法的常用手段。

输出打印 -echo

在Shell平台中,使用echo 命令可以在终端或脚本中显示消息或输出。是大多数 Unix-like 系统(包括 Linux 和 macOS)的标准部分。

以下是 echo 命令的一些基本用法:

  1. 显示文本消息:

    echo "Hello, World!"
  2. 显示变量的值:

    bashCopy codename="ChatGPT"
    echo "My name is $name."
  3. 输出带有转义字符的文本: 使用 -e 选项可以解释转义字符,如 \n(新行)和 \t(制表符)。

    echo -e "This is the first line.\nThis is the second line."
  4. 不输出末尾的新行: 默认情况下,echo 会在输出的末尾添加一个新行。使用 -n 选项可以阻止这种行为。

    echo -n "This text will not end with a newline."
  5. 显示多个字符串:

    echo Hello World!
  6. 输出到文件: 你可以使用重定向操作符 >>>echo 的输出重定向到文件。 这个方法常用于shell脚本输出一个文本文件。

    echo "This is a line of text." > output.txt
  7. 显示环境变量:

    echo $PATH

文件目录操作

目录切换 - cd

在Linux操作Shell控台下,没有GUI图型显示,无法使用鼠标进行操作。通常使用cd 目录进行目录切换操作。

cd [文件夹]

下面常用操作如下:

  • cd .. :返回上级目录
  • cd / :返回系统根目录
  • cd /root :返回root目录,需要超级用户权限才能访问
  • cd /home :返回home目录,home目录通常为用户登录目录的上级命令,存放着Linux目前的每个用户文件夹
  • cd - :返回上次访问的目录下

列出文件清单 - ls

ls命令是list的简写。功能就是列出目录下的文件和目录的相关信息。是Shell目录中最常用的命令之一。类似Windows中DOS命令 - dir。ls是获取目录中文件内容的最直接的命令。

其中ls列出的 . 和 .. 并不是表示文件,它是表示当前为文件夹、存在外部文件夹。

ls [option] [文件 or 目录名]

其中有如下常用option选项:

  • -a :显示隐藏文件
  • -A :显示隐藏文件,并且不额外列出“.”和“..”
  • -c :列出内容按文件的修改时间顺序
  • -d :表示只显示目录,而不是其文件内容。
  • -l :以长格式来显示文件的详细信息,它们的信息依次是:文件类型和权限、链接数、文件属主、文件属组、文件大小、最近修改时间、文件名称
  • -m :以字符流格式输出,文件跨页显示,以逗号分开
  • -o :于l选项相同,只是不显示拥有者信息

其中最为常用的是 ls -l,它可以直接用ll代替使用。 ls也可以充当find查询命令作用,只需要将其输入通配内容即可。

文件复制 - cp

文件或目录复制到另外一个目录下,通常使用cp命令。它等同于Windows下的DOS命令 copy

cp [option] [源文件] [目标位置]

其中有如下常用option选项:

  • -a : 复制文件保留文件属性。
  • -r :复制目录,以及递归复制目录下的所有文件和目录。
  • -i :对于需要覆盖操作时进行提示确定,为交互式复制。
  • -f :直接对也存在的文件进行覆盖操作,不进行提示。
  • -l :不进行复制操作,只是链接文件。

复制目录必须使用-r选项,否则会产生错误。

对于复制目录操作,通常使用cp -r -a目录,它不但确保了目录及其下的所有文件,还保留了文件的属性和权限设置。

文件移动 - mv

移动文件到另外一个位置使用mv命令。

mv [option] [源文件] [目标位置]

其中有如下常用option选项:

  • -i : 交互式操作。如果存在覆盖存在,会询问用户是否需要覆盖操作
  • p :移动时保持权限

mv命令可以作用于目录,将移动目录及下属所有的文件。

查询文件 - find

find目录用于查询目录下的相关文件。

find [查询路径] [option] [操作]

其中option和操作常见如下:

  • -name :根据文件名查询
  • -user :根据文件属主查询
  • -type :查询指定类型文件 【d:目录、f:普通文件】
  • -mtime : 根据文件的更改时间查询文件,-n 表示文件更改距今在n天内,+n表示文件更改时间距今在n天前。
  • -exec :对查询出的匹配文件进行再次Shell命令操作,后续命令中使用占位符 {}表示 单个匹配文件,将进行循环操作。
  • -ok :和-exec操作作用类似,但是它是交互式操作,对于每个命令执行前,将提示用户。

find命令在Linux Shell中编程不单单只是单纯的查询文件作用,更多用于对匹配的文件进行批量执行操作。

find . -mtime +3 -exec rm {} \;  #匹配当前目录下修改时间距今3天前的所有文件 将其删除。

其中\表示exec中的Shell命令结束。并且和其它语言一样,也是需要在句末添加;的。

对于复杂的Shell命令,可以在其额外创建一个bash :

find . -type f -name "*.txt" -exec bash -c 'dir_name=$(basename "${0}" .txt); mkdir -p "${dir_name}"; mv "${0}" "${dir_name}/"' {} \;  # 将其匹配当前目录下的所有txt文件全部放置到 对应文件名称的目录中

其中bash -c 表示对每个找到的文件执行 bash 子进程。

文件删除 - rm

文件删除使用rm操作,它支持删除单个、多个文件、目录。rm是remove的缩写。

rm [option] [文件名 or 目录]

其中有如下常用option选项:

  • -f :忽略不存在的文件,并不会提示
  • -r :文件目录删除,会递归删除其目录下所有内容
  • -i :交互式操作

对于文件夹删除操作必须 携带 -r 选项。rm命令一旦将文件删除后,是不能被回复的。

通常文件夹删除使用rm -rf命令,但是由于f的存在,它不会进行任何提示,所以是及其危险的。坊间流传的删库操作rm -rf /*,但其实在现代的Linux系统下并不能直接执行了,Linux对其根目录的rm操作进行限制了,执行会提示操作失败。

很多公司将其提供的用户并不给予rm权限,对于需要删除的文件,使用mv移动到一个回收站文件夹,由管理员或者bot统一做rm操作。

创建目录 - mkdir

mkdir [option] [目录名]

其中有如下常用option选项:

  • -m :对新建目录设置权限,使用 数字赋值
  • -p :对于多重目录,自动创建多个目录

mkdir -p可以创建多重目录,mkdir -p mk/233:表示创建mk目录,并且在mk目录下再创建233目录。

删除目录 - rmdir

rmdir命令可以删除一个或多个目录。但是 最大的缺陷就是 只支持删除空目录。所以通常使用rm -r命令删除目录,这个命令使用频率并不多。

文件目录权限操作

Linux系统中每个文件和目录都有访问许可权限,用它来确定用户能以何种方式对文件和目录进行访问和操作。

Linux系统将其每个文件和目录 都拥有3个权限作用域: 文件所有者(User) 、同组用户(group)、其它用户(others)

每个作用域都拥有对其文件权限,文件或目录访问权限分为 读、写、可执行 三种。

更改文件、目录权限 - chmod

使用chmod操作可以对其文件或目录 修改访问权限。只有具有 管理员权限并使用su命令才能进行使用。

它有两种修改方法 :

1、包含字母和操作符表达式 :

chmod [用户类型] [数学符号] [访问类型] [文件或目录]

其中用户类型 有: u( 文件所有者) 、g(同组用户) 、o(其它用户)、a(所有用户,默认值)

数学符号 有 :+(添加权限)、-(取消权限)、 =(直接赋值等同权限,取消其它权限)

访问类型 有:r(读) 、 w(写)、x(可执行)

chmod u+x,g+w text.txt  # 修改text.txt权限,文件所有者增加可执行权限,同组用户增加读写权限

注意:创建chmod命令不同用户组的权限修改参数需要 使用逗号隔开。

2、权限数字设定:

chmod [权限数字] [文件或目录]

所谓的权限数字,就是3位数的数字。每一位数字都表示其对应的拥有的访问权限。

第一位表示文件所有者的访问权限,第二位表示同组用户的访问权限,第三位表示其他用户的访问权限。

其中数字 : 0表示 没有任何权限,1表示可执行权限,2表示拥有写权限,4表示读权限。

不同的权限的数值可以叠加。比如 3 表示 拥有 可执行、写权限。 5 表示拥有可执行、读权限。6表示拥有读写权限。7表示拥有全部权限(读写执行)。

chmod 764 text.txt  # 修改text.txt权限,文件所有者全部权限,同组用户读写权限,其他用户读权限

更改文件、目录宿主 - chown

chown能够更改文件、目录的属主。该指令只有超级管理员才能使用。一般使用者没有权限修改文件或目录属主。

chown [option] [owner] [文件名\目录名]

常用的option选项如下:

  • -R :对其目录下的所有文件和子文件目录进行同样拥有者变更
chown zssaer file.txt  #将file.txt文件修改为zssaer所属

文本编辑器

不同于具有GUI的文本编辑器,在Liunx Shell下的文本编辑器需要使用相关指令才能够进行操作。

Linux Shell平台下的常见文本有 vi 、 vim等等。

vim

vi是UNIX世界中最通用的全屏编辑器,Linux中使用的是vi加强版vim。

vim与vi完全兼容,不同的是vim支持对代码的高亮等额外的功能。

vim [文件]

如果这个文件是不存在的,vim将自动打开一个空白的文本文件。

vim具有两种模式:

  1. 一般模式:

    vim打开文本文件将默认使用该模式,或在插入模式下按esc。该模式允许用户移动游标,并允许搜索文本功能。

    输入: 可输入文本操作命令下:

    • w :存储当前文本
    • q :关闭文件。(当修改过文本未保存的话,无法执行)
    • q! :强制关闭文件,而不保存。
    • wq :存储当前文件并关闭文件。

    输入/ + 文本 可查询文本:

    • 输入相当于文本后,按下“Enter”键搜索,vim将文本游标移动到游标下 文本第一个满足搜索条件下的位置。
    • n,这会将光标移动到下一个匹配的文本。
    • N 键。这会将光标移动到上一个匹配的文本。

    输入:s + /原文本/替换文本/ 可进行文本替换操作。输入:%s + /原文本/替换文本/g 将替换整个文件中的每个匹配项。

正则表达式

Shell使用正则表达式进行对内容的匹配。Shell工具中sed、awk和grep等都会用到正则表达式。

基本的正则表达式元字符

符号 意义
* 匹配前面一个字符 0个或多个字符
. 匹配匹配前面一个字符 1个任何字符
^ 匹配行首,或后面字符的非
$ 匹配行尾
[ ] 匹配字符集合
\ 转义符,屏蔽一个元字符的特殊意义

除了常规的匹配表达式之外,还有一个常用的表达式:

^$   # 既匹配行首 又匹配行尾,中间没有元素,所以 最终匹配空行

这个特殊的表达式,最终匹配空行,需要牢记,在很多命令中都会用到这个表达式表达空行。

[ ]符号,匹配字符集合,通常内部包含 -字符,表示从A到B全部匹配。

[0123456789]  # 匹配任意一个数字
[0-9]  # 匹配任意一个数字
[a-z] # 匹配任意一个小写字母
[A-Z] # 匹配任意一个大写字母
[b-p] #匹配小写字母b~p 中的任意一个字母

^ 匹配行首字符放置到[ ]中的话,它将不再表示匹配行首字符了,而是取反符号,表示相反的匹配:

[^b-d]  # 匹配小写字符不在b-d中任意一个字母

一个[]可包含多个-字符组合:

[A-Za-z][A-Za-z]*  #匹配所有英语字母 0-N次,所有 最终匹配任意英语单词

在正则表达式中常常内容包含符号,而这样又会被误认为正则表达式中的元字符。所以使用\+符号 将会进行转义,符号将会被变成普通的字符。

\的特殊用法

\{n\}匹配前面一个字符出现n次的字符串。\{n,\}匹配前面一个字符至少出现n次的字符串。\{n,m\}匹配前面一个字符出现n~m次的字符串。

JO\{3\}B    #匹配出现3次的O的字符,所以最终匹配 JOOOB
JO\{3,\}B    #匹配至少出现3次的O的字符,所以最终匹配 JOOOB、JOOOOB、JOOOOOB...
JO\{3,5\}B    #匹配出现3次~5次的O的字符,所以最终匹配 JOOOB、JOOOOB、JOOOOOB

[a-z]\{5\}    #匹配任意一个小写字母 5次的字符串, 如hello,house...

扩充的正则表达式元字符

除了基本的正则表达式元字符以外,awk和Perl等Linux工具还支持扩充的正则表达式元字符:

符号 意义
匹配0-1个前一个普通字符
+ 匹配1-N个前一个普通字符
( ) 匹配其中集合中一个字符

总体上扩充的正则表达式元字符 和基本的差不多,但是注意,?包括 0个,所以和.不一样。+至少包含一个,所以和*不一样。

通配

传统的bash Shell本身不支持正则表达式,使用正则表达式的是Shell命令和工具,如grep、sed、awk等。

但是在bash Shell中可以使用正则表达式中的元字符实现通配(Globbing)功能。当使用统配功能时,其元字符表达意义将不再一样。

如: *不再表示前面那个字符的重复,而是表示任意位的任意字符。表示一个任意字符,^不再表示行首,而是只能用于取反。

Shell命令中有很多是支持统配查询的,如常用的 ls命令

ls -l *.txt  #列出以.txt结尾的文件
ls -l 0?.pem  #列出以0开头、后跟一个任意字符且以.pem为后缀的文件
ls -l [a-z]*.awk  #列出以a-z范围一个字符开头且以.awk为后缀的文件

通配的结果由计算机搜索大量文件或目录进行匹配而输出的,通配对处理能力和内存资源有很大的需求。黑客可以输入大量通配符的文件查询来故意引起拒绝服务攻击。所以大型服务器通常通过限制服务器执行通配功能的次数,来保障服务器的安全。

grep

grep命令,它的全程是 Global search Regular Expression and Print out the line,即全面搜索正则表达式并打印。

GREP是一个强大文本搜索工具,它使用正则表达式搜索文本,并把匹配的行打印出来,grep是Linux中最为广泛的命令之一,也是正则表达式在Linux中最多使用的地方。

grep [option] [模式] [文件...]

模式后的所有字符串被看作是文件名,它接受多个文件名。搜索的结果将会被打印出来,不影响原文件的内容。

grep命令的主要选项有:

  • -c :只输出匹配行的数量,不输出匹配行的内容
  • -i :搜索时忽略大小写
  • -n :列出所有的匹配行,并显示行号
  • -v :显示不包含匹配文本的所有行
  • -w :正则表达式匹配整词,非整词将会被过滤
  • -x :正则表达式匹配整行,非整行将会被过滤、
  • -q :不输出匹配的内容,只输出搜索退出状态, 0 (匹配失败)、1(匹配成功)。需要配合echo $? 后显查看。
  • -r :递归搜索,不仅搜索当前目录,而且搜索子目录
  • -b :打印匹配行距文件头部的偏移量,以字节为单位
  • -E :支持扩展的正则表达式

grep命令的模式十分灵活,可以是字符串,也可以是变量,还可以是字符串。对于含有空格的字符串匹配的话,需要将其使用引号包住。

# 搜索 00.pem文件中包含certificate字符串的行,不需要引号引起模式
grep certificate 00.pem
# 搜索 00.pem文件中包含user certificate字符串的行,需要引号引起模式,不然certificate会被当做文件名
grep "user certificate" 00.pem

# 对当前文件夹下所有文件 以及 目录下的文件进行查询字符串“user certificate”
grep -r "user certificate" *
#  查询空白行,只打印行数
grep -c  ^$ 00.pem
#  查询非空白行,只打印行数
grep -c  ^(^$) 00.pem

sed命令

sed命令是Linux的一个难点,它是一个非交互式的文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以是来自键盘输入、文件重定向、字符串、变量甚至来之管道的文本。

sed从文本的一个文本行或标准输入中读取数据,将其复制到缓存区,然后读取命令行或脚本的第一个命令,对此命令要求的行号进行编辑,重复过程,直到所有命令完成。

sed相比于vim等文本编辑器,它可以一次性完成所有的编辑任务,效率十分高效,但是要流程使用它也是非常复杂的。

sed的操作通常如下:

sed 'sed命令' 文本文件 > 输出文件

sed处理文件默认只是打印出来,并不会编辑原始文件。所以如果需要保存的话,需要 使用>重定向符号 输出成新文件。

执行sed 操作 有三种方法:

  • 直接通过sed命令执行 :

    sed [选项] 'sed命令' 文本文件

  • 使用sed执行sed脚本文件:

    sed [选项] -f 'sed命令' 文本文件

  • 直接执行sed脚本文件:

    ./'sed脚本文件' 文本文件

sed选项通常有如下:

  • -n :不打印所有行 (不带这个的话就会继续将所有行内容打印出来)
  • -e :表示将下个字符串解析为sed命令,用于一次性输入多个sed命令使用。
  • -f :调用sed脚本文件
  • -i : 直接作用到原文件上

sed命令

sed命令通常由两部分组成:定位文本行 和 sed编辑命令。

对于定位文本行 , sed提供了两种方式来定位需要处理得文本行:

  1. 使用行号,指定一行,或者指定行号范围

    x :x表示行号。 eg: 5 表示指定第5行内容。

    x , y :指定从x行到y行范围。 eg: 2,12 表示指定第2行到12行内容

    /文本/ :查询包含该文本的行。 eg:/demo/ 表示查询文件中demo的行

    /文本/ 文本/ :查询包含这2个文本的行。 eg:/demo/first/ 表示查询文件中有demo并也有first的行

    /文本/,x :查询 包含该文本的行到 x行范围。 eg:/demo/,15 表示查询文件中demo的行到15行为止的范围行

    x,y!:查询除开x和y行所有行

  2. 使用正则表达式

对于sed编辑命令,则是用来对指定的文本行内容进行各种处理的操作,如打印、删除、追加、插入、替换等。

sed编辑命令常用如下:

  • p :打印匹配行的内容
  • = :打印匹配行的行号
  • a\ :在匹配行号之后追加文本
  • i\ :在匹配行号之前插入文本
  • d :删除匹配行
  • c\ : 用新文本替代定位文本
  • r :从另外一个文件中读文本
  • w :将文本写入到另外一个文本
  • h:将模式缓冲区的文本复制到保持缓冲区
  • H:将模式缓冲区的文本追加到保持缓冲区
  • g:将保持缓冲区的文本复制到模式缓冲区
  • G:将保持缓冲区的文本追加到模式缓冲区
  • x:保持缓冲区 和 模式缓冲区 的内容互换

替换文本:

s/原字符串/新字符串/ [g:替换全部文件中匹配内容]

sed脚本

sed脚本文件 其实就是 多个sed命令 组成得文件。直接通过sed命令执行,也可以一次性输入多个sed命令。

sed脚本文件一般以.sed为后缀名。

sed脚本内容大概如下:

#!/bin/sed -f
/demo:/a\			#在文件中搜索到的包含demo后添加文本
#添加的文本如下:
We append a new line.\ 		#"\"符号表示换行,此时最佳还没有结束
We append another line.

上面是一个简单的sed脚本。

其中#!/bin/sed -f 和bash Shell脚本语言,以sha-bang(#!)符号开头,sha-bang后面为解释器的路径。这里sed需要sed解释器,并且必须加上 -f才能表明该文件是sed脚本文件。

当然这个sed解释器的位置一般都是在/bin文件下,如果不知道的话可以使用which函数获取路径:

which sed

如果像使用第三种方法直接执行sed脚本作用于文本文件的话,需要该脚本文件拥有当前用户可执行权限:

chmod u+x append.sed	#为append.sed脚本文件给予可执行权限

使用案例

sed -n '1p' input.txt  #打印input文件下的第一行内容
sed '1p' input.txt  #打印input文件下的第一行内容,此外还会打印出所有行内容

sed -n '3,6p' input.txt  #打印input文件下的第三行到第6行的内容
sed -n '/certificate/p' input.txt  #搜索input文件下的包含certificate的行,打印出来
sed -n '/certificate/=' input.txt  #搜索input文件下的包含certificate的行,只将行号打印出来

sed -n 's/certificate/CERTIFICATE/pg' input.txt  #替换input.txt中所有certificate为CERTIFICATE并把行内容打印出来

如果需要一次执行多条sed命令行,那么对于每条之间要加上选项-e才能被识别 为sed命令:

sed -n -e '/certificate/p' -e '/certificate/=' input.txt