目录
一、Shell脚本入门
1、Shell简介
Shell 是一种脚本语言,也是一种命令行解释器,通常被用于在类 Unix 系统中的交互式终端或者脚本中编写自动化任务。Shell 脚本常用于处理文本文件、执行系统命令、管理程序等任务。他接收应用程序/用户命令,然后调用操作系统内核。
2、Shell解析器
Shell 解析器是一种命令行解释器,用于解释执行 Shell 脚本。就是平时我们在脚本第一行看到的#!bin/bash,就是指定解析器啦!可以执行以下命令查看系统的解析器。
[root@ ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
其中最常用的是 bash,它是大多数 Linux 系统中默认的 Shell 解析器。
Shell 解析器通常按照以下方式执行 Shell 脚本:
- 解析器读取脚本文件,并确定要使用的shell类型。
- 解析器读取脚本文件中的命令,并进行语法检查和解释。
- 解析器执行每个命令,并在必要时接受输入和输出数据。
- 解析器在脚本执行完成后退出,返回状态码以指示脚本执行结果。
脚本的开头是可以选择是否指定解析器的。指定解析器的目的是为了确保脚本在执行时使用正确的解析器进行解释。这样可以防止在不同的操作系统或环境中脚本被错误地解释执行。如果没有指定解析器,系统会默认使用当前用户的默认 Shell 来执行脚本。但是,在编写可供他人使用的脚本或在特定环境下执行脚本时,最好在脚本开头明确指定解析器!
3、第一个Shell脚本
创建一个shell脚本,输出"hello world"
[root@ ~]# touch helloworld.sh
[root@ ~]# vi helloworld.sh
#!/bin/bash
echo "hello world"
[root@ ~]# bash helloworld.sh
hello world
4、运行Shell脚本
方法一:采用bash+脚本路径(文件不需要具有可执行权限)
# bash+脚本的相对路径
[root@ ~]# bash helloworld.sh
# bash+脚本的绝对路径
[root@ /]# bash /root/helloworld.sh
方法二:直接输入脚本的路径(必须具有可执行权限+x)
1、首先要赋予helloworld.sh脚本的+x权限
[root@ ~]# chmod +x helloworld.sh
2、执行脚本
# 相对路径
[root@ ~]# ./helloworld.sh
# 绝对路径
[root@ /]# /root/helloworld.sh
两种方法的区别是:
第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。
第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。
二、Shell变量
1、系统变量
Linux 系统中有许多常用的系统变量,它们提供了有关系统配置和状态的信息。以下是一些常见的 Linux 系统变量:
PATH
: 指定系统搜索可执行程序的路径列表。HOME
: 当前用户的主目录路径。USER
或LOGNAME
: 当前登录用户的用户名。SHELL
: 当前用户所使用的默认 Shell 程序的路径。PWD
: 当前工作目录的路径。LANG
和LC_*
: 控制系统的本地化设置,用于定义字符编码、日期格式、语言等。LD_LIBRARY_PATH
: 动态链接器用于查找共享库文件的路径列表。TZ
: 定义当前时区的设置。PS1
: 定义命令行提示符的格式。
我们可以用命令来查看系统变量:
(1)显示当前Shell中的所有变量
[root@ ~]# set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
(2)查看系统变量的值
[root@ ~]# echo $HOME
/root
[root@ ~]# echo $PWD
/root
[root@ ~]# echo $SHELL
/bin/bash
[root@ ~]# echo $USER
root
2、特殊变量
(1)$?
功能描述:
是上一个命令或程序的退出状态码,用于判断命令执行是否成功。
如果这个变量的值为0,证明上一个命令正确执行;
如果这个变量的值为非0(具体哪个数,由命令自己来决定),则证明上一个命令执行不正确了。
案例:
# 脚本准备
[root@ ~]# vi test.sh
#!/bin/bash
echo "$1 $2"
# 执行脚本
[root@ ~]# bash test.sh 1 2
1 2
# 检查脚本是否执行成功
[root@ ~]# echo $?
0
(2)$n
功能描述:
n为数字,$0代表脚本名称,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}
案例:
# 脚本准备
[root@ ~]# touch test.sh
[root@ ~]# vi test.sh
#!/bin/bash
echo "$0 $1 $2"
# 执行脚本
[root@ ~]# chmod +x test.sh
[root@ ~]# ./test.sh a b
./test.sh a b
2
(3)$#
功能描述:
获取所有输入参数个数,常用于循环。
案例:
# 脚本准备
[root@ ~]# touch test.sh
[root@ ~]# vi test.sh
#!/bin/bash
echo "$0 $1 $2"
echo $#
# 执行脚本
[root@ ~]# chmod +x test.sh
[root@ ~]# ./test.sh a b
./test.sh a b
2
[root@ ~]# ./test.sh a b c
./test.sh a b
3
[root@ ~]# ./test.sh a c b
./test.sh a c
3
(4)$*、$@
功能描述:
$*变量将所有位置参数视为一个单词(字符串),使用空格作为分隔符。这意味着 $*
将所有参数合并为一个字符串,而不考虑参数中是否存在空格。
$@变量将每个位置参数视为一个独立的单词(字符串),并将每个参数作为独立的实体处理。这意味着 $@
保留了参数本身的空格和引号。
案例:
# 脚本准备
#!/bin/bash
echo "使用 \$* 打印参数列表:"
for arg in $*; do
echo "$arg"
done
echo "使用 \$@ 打印参数列表:"
for arg in $@; do
echo "$arg"
done
# 执行该脚本并传递以下参数:arg1 "arg2 with spaces" arg3,那么输出将如下所示:
# 使用 $* 打印参数列表:
arg1
arg2
with
spaces
arg3
# 使用 $@ 打印参数列表:
arg1
arg2 with spaces
arg3
3、自定义变量
定义变量:变量=值
撤销变量:unset 变量
声明静态变量:readonly 变量(静态变量无法unset)
变量定义规则:
(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
(2)等号两侧不能有空格。
(3)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
(4)变量的值如果有空格,需要使用双引号或单引号括起来。
案例:
# 定义变量
[root@ ~]# A=5
[root@ ~]# echo $A
5
# 撤销变量
[root@ ~]# unset A
[root@ ~]# echo $A
# 变量的值有空格需要用双引号或单引号括起来
[root@ ~]# C="a b c"
[root@ ~]# echo $C
a b c
三、运算符
运算符用法:
"$((运算式))"或"$[运算式]"
1、算术运算符
+
:加法-
:减法*
:乘法/
:除法%
:取模(取余数)**
:指数运算
假设a=5 b=2,可进行如下计算
c=$((a + b)) # 加法
d=$((a - b)) # 减法
e=$((a * b)) # 乘法
f=$((a / b)) # 除法
g=$((a % b)) # 取模
h=$((a ** b)) # 指数运算
# expr一步完成计算
expr `expr 2 + 3` \* 4
20
# 采用$[运算式]方式
echo $[(2+3)*4]
20
2、关系运算符
-eq
:等于-ne
:不等于-gt
:大于-lt
:小于-ge
:大于等于-le
:小于等于
# 假设a=5 b=2
if [ $a -eq $b ]; then
echo "a 等于 b"
fi
if [ $a -ne $b ]; then
echo "a 不等于 b"
fi
3、逻辑运算符
&&
:逻辑与||
:逻辑或!
:逻辑非
# 可以使用逻辑运算符来组合条件判断:
if [ $a -gt 0 ] && [ $b -lt 10 ]; then
echo "a 大于 0,且 b 小于 10"
fi
if [ $a -eq 0 ] || [ $b -eq 0 ]; then
echo "a 或者 b 等于 0"
fi
if ! [ $a -eq 0 ]; then
echo "a 不等于 0"
fi
4、字符串运算符
=
:判断两个字符串是否相等!=
:判断两个字符串是否不相等-z
:判断字符串是否为空(长度为 0)-n
:判断字符串是否非空(长度大于 0)
# 可以对字符串进行比较和判断:
str1="hello"
str2="world"
if [ $str1 = $str2 ]; then
echo "str1 等于 str2"
fi
if [ $str1 != $str2 ]; then
echo "str1 不等于 str2"
fi
if [ -z $str1 ]; then
echo "str1 是空字符串"
fi
if [ -n $str2 ]; then
echo "str2 是非空字符串"
fi
5、文件测试运算符
-e
:判断文件是否存在-f
:判断文件是否是普通文件-d
:判断文件是否是目录-r
:判断文件是否可读-w
:判断文件是否可写-x
:判断文件是否可执行-s
:判断文件是否为空(大小是否为 0)
if [ -e /path/to/file ]; then
echo "文件存在"
else
echo "文件不存在"
fi
if [ -f /path/to/file ]; then
echo "这是一个文件"
else
echo "这不是一个文件"
fi
if [ -d /path/to/dir ]; then
echo "这是一个目录"
else
echo "这不是一个目录"
fi
if [ -r /path/to/file ]; then
echo "这个文件可读"
else
echo "这个文件不可读"
fi
if [ -w /path/to/file ]; then
echo "这个文件可写"
else
echo "这个文件不可写"
fi
if [ -x /path/to/file ]; then
echo "这个文件可执行"
else
echo "这个文件不可执行"
fi
if [ -s /path/to/file ]; then
echo "这个文件非空"
else
echo "这个文件是空的"
fi
四、流程控制
1、if判断
if
是用于条件判断的关键字,可以根据条件的真假执行不同的代码块。
基本语法:
if [ condition ]; then
# 当条件为真时执行的代码块
else
# 当条件为假时执行的代码块(可选)
fi
注意事项:
(1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
(2)if后要有空格
案例:
a=5
b=10
if [ $a -gt $b ]; then
echo "a 大于 b"
elif [ $a -lt $b ]; then
echo "a 小于 b"
else
echo "a 等于 b"
fi
2、case语句
case
是一种用于多条件判断的语句结构。它可以根据给定的值,执行与各个条件匹配的代码块。
基本语法:
case value in
pattern1)
# 当 value 匹配 pattern1 时执行的代码块
;;
pattern2)
# 当 value 匹配 pattern2 时执行的代码块
;;
pattern3|pattern4)
# 当 value 匹配 pattern3 或 pattern4 时执行的代码块
;;
*)
# 当 value 不匹配任何 pattern 时执行的代码块(可选)
;;
esac
注意事项:
(1)case行尾必须为单词"in",每一个模式匹配必须以右括号")"结束。
(2)双分号";;"表示命令序列结束,相当于java中的break。
(3)最后的"*)"表示默认模式,相当于java中的default。
案例:
fruit="apple"
case $fruit in
"apple")
echo "这是一个苹果"
;;
"orange")
echo "这是一个橙子"
;;
"banana"|"pineapple")
echo "这是一个香蕉或菠萝"
;;
*)
echo "未知水果"
;;
esac
case 语句还支持正则表达式匹配和使用通配符进行模式匹配。可以在 pattern 中使用 * 匹配任意字符,? 匹配单个字符,[abc] 匹配 a、b 或 c 等。
filename="file.txt"
case $filename in
*.txt)
echo "这是一个文本文件"
;;
*.jpg|*.png)
echo "这是一个图片文件"
;;
*)
echo "未知文件类型"
;;
esac
3、for循环
for
循环用于迭代一个列表或一组元素,并对每个元素执行特定的操作。
基本语法:
# 写法1
for(( 初始值;循环控制条件;变量变化 ))
do
程序
done
# 写法2
for 变量 in list集合
do
# 执行代码块
done
案例:
# 从1加到100
s=0
for(( i=1;i<=100;i++ ))
do
s=$[$s+$i]
done
echo $s
# 迭代列表
fruits=("apple" "banana" "orange")
for fruit in "${fruits[@]}"
do
echo "水果: $fruit"
done
# 迭代数字范围
for num in {1..5}
do
echo "数字: $num"
done
# 迭代文件列表
for file in /path/to/directory/*
do
echo "文件: $file"
done
#使用通配符进行迭代
for file in *.txt
do
echo "文本文件: $file"
done
4、while循环
while
循环用于在满足特定条件的情况下执行一段代码块。只要条件为真,循环将继续执行,直到条件不再为真为止。
基本语法:
while condition
do
# 执行代码块
done
案例:
# 使用计数器进行循环
counter=1
while ((counter <= 5))
do
echo "计数器值: $counter"
((counter++))
done
# 读取文件内容进行循环
while IFS= read -r line
do
echo "行内容: $line"
done < "file.txt"
五、函数
1、系统函数
介绍一下常见的系统函数
-
文件和文件夹操作:
open()
:打开文件。read()
:从文件中读取数据。write()
:向文件中写入数据。close()
:关闭文件。mkdir()
:创建文件夹。rmdir()
:删除空文件夹。
-
进程管理:
fork()
:创建一个子进程。exec()
:执行新的程序。wait()
:等待子进程结束。kill()
:发送信号给进程。
-
网络通信:
socket()
:创建套接字。bind()
:将套接字绑定到特定的地址和端口。listen()
:监听连接请求。accept()
:接受连接请求。connect()
:建立与远程主机的连接。send()
:发送数据。recv()
:接收数据。
-
内存管理:
malloc()
:分配内存。free()
:释放内存。
-
时间和日期:
time()
:获取当前时间戳。ctime()
:将时间戳转换为可读的时间字符串。
2、自定义函数
基本语法:
function name() {
# 函数代码块
}
# 调用函数
name
案例:
# 基础用法
say_hello() {
echo "Hello, World!"
}
say_hello # 输出 Hello, World!
# 使用参数用法
greet() {
echo "Hello, $1!"
}
greet "John" # 输出 Hello,John!
# 在函数中使用 return 返回值
add() {
local result=$(( $1 + $2 ))
return $result
}
add 5 3
echo "结果: $?" # 输出 "结果: 8"
六、Shell工具
1、cut
cut
是一个常用的命令行工具,用于从文本文件或标准输入中提取字段(列),具体的说就是在文件中负责剪切数据用的。cut命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
基本语法:
cut[选项参数] filename
注:如果不指定文件,则
cut
会从标准输入中读取数据。
选项参数说明:
-c
:根据字符位置提取字段,即列号。
-f
:根据字段(以分隔符分隔的列)提取字段。
-d
:设置字段分隔符。
-s
:仅显示包含分隔符的行。
--complement
:显示除指定字段外的其他字段。
案例:
# -c:提取第 1 到 5 个字符
cut -c 1-5 file.txt
# -f:使用逗号作为分隔符,并提取第 2 和第 3 个字段
cut -d ',' -f 2,3 file.csv
# -d:使用制表符作为分隔符,并提取第 1 个字段
cut -d $'\t' -f 1 file.txt
# -s:仅提取包含制表符的行的第 2 个字段
cut -d $'\t' -f 2 --only-delimited file.txt
# --complement:提取除了第 3 到最后一个字段之外的其他字段
cut -f 1-2 --complement file.txt
2、sed
sed
是一个强大的流式文本编辑器,用于对输入流进行编辑、替换和转换操作。它支持使用正则表达式来匹配和修改文本。文件内容并没有改变,除非你使用重定向存储输出。
基本语法:
sed[选项参数] 'command' filename
注:如果不指定文件,则
sed
将从标准输入中读取数据。
选项参数:
-e 脚本
:指定要执行的脚本命令。
-i[扩展名]
:直接修改源文件。
-n
:禁止自动打印模式空间。
-r
:启用扩展的正则表达式语法(在某些版本中使用-E
)。
-f 脚本文件
:从指定的脚本文件中读取命令。
案例:
# 将文件中的 "apple" 替换为 "orange":
sed -e 's/apple/orange/g' file.txt
# 将文件中的 "apple" 替换为 "orange" 并直接修改源文件:
sed -i 's/apple/orange/g' file.txt
# 只打印被修改的行:
sed -n 's/apple/orange/p' file.txt
# 使用扩展的正则表达式替换:
sed -r 's/(^|\s)apple(\s|$)/\1orange\2/g' file.txt
# 将多个替换规则保存在一个脚本文件 script.sed 中,并应用到文件中:
sed -f script.sed file.txt
command命令功能:
命令 | 功能描述 |
---|---|
a | 新增,a的后面可以接字符串,在下一行出现 |
d | 删除 |
s | 查找并替换 |
3、awk
awk
是一种强大的文本处理工具,用于从输入流中提取和处理数据。它按行读取输入,并根据指定的规则进行处理和输出。
基本语法:
awk 'pattern {action}' file
pattern
定义了要执行action
的条件或模式。action
定义了要执行的操作。
案例:
# 搜索data.txt文件以root关键字开头的所有行,并输出该行的第3列。
awk -F : '/^root/ {print $3}' data.txt
44
44
# 搜索data.txt文件以root关键字开头的所有行,并输出该行的第2列和第4列,中间以“,”号分割。
awk -F : '/^root/ {print $3","$4}' data.txt
44,2
44,2
4、sort
sort
命令用于对文本文件的行进行排序操作。它可以按照字典顺序、数值顺序和自定义规则对文本行进行排序。
基本语法:
sort [选项] 文件名
选项参数:
-b, --ignore-leading-blanks
:忽略行首的空格字符。-n, --numeric-sort
:按照数值大小进行排序。-r, --reverse
:以相反的顺序进行排序。-f, --ignore-case
:不区分大小写进行排序。-k, --key=字段
:按照指定的字段进行排序。-t, --field-separator=分隔符
:使用指定的分隔符作为字段的分隔符。-u, --unique
:去除重复的行。
案例:
# 对文件按数字大小进行排序:
sort -n file.txt
# 忽略空格并按逆序排序:
sort -b -r file.txt
#按照第 2 列进行排序:
sort -k 2 file.txt
#使用逗号作为字段分隔符进行排序:
sort -t ',' -k 3 file.txt
#去除重复行并按照字典顺序排序:
sort -u file.txt
收藏关注不迷路!