声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关,切勿触碰法律底线,否则后果自负!!!!有兴趣的小伙伴可以点击下面连接进入b站主页[B站泷羽sec](泷羽sec的个人空间-泷羽sec个人主页-哔哩哔哩视频)
本章课程链接:
shell脚本(1)脚本创建执行与变量使用 | shell脚本(1)脚本创建执行与变量使用_哔哩哔哩_bilibili |
shell编程(2)永久环境变量和字符串显位 | shell编程(2)永久环境变量和字符串显位_哔哩哔哩_bilibili |
shell (3)脚本参数传递与数学运算 | shell (3)脚本参数传递与数学运算_哔哩哔哩_bilibili |
shell编程(4)脚本与用户交互以及if条件判断 | shell编程(4)脚本与用户交互以及if条件判断_哔哩哔哩_bilibili |
shell(5)字符串运算符和逻辑运算符 | shell(5)字符串运算符和逻辑运算符_哔哩哔哩_bilibili |
shell(6)if条件判断与for循环结构 | shell(6)if条件判断与for循环结构_哔哩哔哩_bilibili |
shell(7)for循环与while循环 | shell(7)for循环与while循环_哔哩哔哩_bilibili |
shell编程(8) until循环以及函数基本创建调用 | shell编程(8) until循环以及函数基本创建调用_哔哩哔哩_bilibili |
shell编程(完结) | shell编程(完结)_哔哩哔哩_bilibili |
Shell脚本(1)脚本创建执行与变量使用
Shell
Shell 脚本是一种为 Linux/Unix 操作系统的 shell(命令行解释器)编写的脚本程序。它是一系列命令的集合,通过 shell 来执行。就像是一个批处理文件,将多个需要在命令行中手动输入的命令组合在一起,实现自动化任务处理。
用途
1.自动化任务:
系统管理任务是 Shell 脚本的常见应用场景。比如可以编写一个脚本用于自动更新系统软件包。在 Debian 或 Ubuntu 系统中,更新软件包通常需要在命令行输入sudo apt - get update和sudo apt - get upgrade这两个命令。通过 Shell 脚本可以将这两个命令组合起来,还可以添加一些条件判断,如检查网络连接是否正常后再执行更新。
2.文件处理:
可以用于批量处理文件。例如,有一个目录下有很多文本文件,需要将它们的内容全部合并到一个新文件中。可以使用 Shell 脚本通过循环遍历文件目录中的每个文件,读取文件内容并写入到新文件,从而高效地完成文件合并任务。
3.配置管理:
在服务器环境中,配置管理很重要。Shell 脚本可以用于配置软件环境。例如,在安装和配置 Web 服务器(如 Apache)时,通过 Shell 脚本可以自动完成软件的下载、解压、配置文件的修改以及服务的启动等一系列操作。
一、Shell脚本
1、创建脚本
首先建立一个脚本文件
vim 1.sh
可以利用 #! /bin/bash、#! /bin/dash、#! /bin/sh 这三种其实不管用哪种脚本解释器最后调用的还是这个dash
比如ls -l bin/sh 发现调用的还是dash
1.[#! /bin/bash]
含义
#!在脚本语言中被称为 “Shebang”(也称为 “Hashbang”)。#! /bin/bash这一行通常是一个 Shell 脚本文件的第一行内容。它的作用是告诉操作系统这个脚本应该使用/bin/bash这个 Bash 解释器来执行其中的命令。
具体解释
#!部分:
这是一个特殊的标记,用于指示脚本的解释方式。当操作系统看到这个标记时,它会知道接下来的内容是一个脚本,并且需要找到合适的程序来解释执行这个脚本。
/bin/bash部分:
这是 Bash 解释器的路径。/bin是一个常见的系统目录,其中存放着许多基本的可执行文件和命令,bash就是其中之一。Bash 是一种功能强大的 Unix shell,它能够解释和执行脚本中的各种命令,包括变量定义、条件判断、循环以及调用其他程序等操作。
2. [#! /bin/dash]
含义
#! /bin/dash是 Shell 脚本文件开头的一个特殊声明,类似于#! /bin/bash。它表示这个脚本应该使用/bin/dash这个 Dash 解释器来执行。
与 Bash 的区别及适用场景
语法兼容性:
Dash 严格遵循 POSIX 标准,语法较为精简。相比 Bash,Dash 缺少一些 Bash 特有的扩展功能和语法糖。例如,Dash 没有 Bash 中的数组变量的某些高级操作,如${array[@]}这种复杂的数组引用方式。如果你的脚本主要使用 POSIX 标准的命令和语法,使用 Dash 可以保证良好的兼容性和高效的执行。
性能方面:
Dash 通常启动更快,占用的系统资源相对较少。在一些对性能要求较高、资源较为紧张的场景下更具优势。比如在系统启动脚本中,许多 Linux 发行版(如 Ubuntu)会使用 Dash 来执行/etc/init.d目录下的脚本。这是因为在系统启动阶段,快速地执行一系列初始化任务是关键,而 Dash 的轻量级特性可以满足这一需求。
脚本可移植性:
由于 Dash 遵循 POSIX 标准,以#! /bin/dash开头的脚本在其他遵循 POSIX 标准的 Unix - like 系统上可能更容易移植。只要目标系统中有 Dash 或者兼容 Dash 的解释器,脚本就有更大的机会正确执行,而不需要对脚本进行大量修改。
3.[#! /bin/sh]
含义
#! /bin/sh是 Shell 脚本文件头部的一个特殊指令。#!是所谓的 “shebang”(也叫 “hashbang”),用于告诉操作系统这个文件是一个脚本,并且应该使用/bin/sh这个命令解释器来运行脚本中的内容。
其中,/bin/sh在大多数 Linux 系统中通常是指向某种具体的 Shell 解释器。在很多情况下,它可能是指向 Bash(/bin/bash)或者 Dash(/bin/dash)等,这取决于系统的配置和发行版的选择。
Dash: 是 Debian Almquist Shell 的缩写,它是一种 Unix shell,是基于 Almquist Shell(sh)开发而来的。在 Linux 系统环境中,它是一种命令行解释器,用于解释和执行用户在终端输入的命令。
Bash(Bourne - Again Shell)是 Linux 系统中另一种非常流行的 shell。Bash 功能强大,它有很多高级特性,如命令行编辑、自动补全、历史记录功能以及丰富的编程结构(如数组等复杂数据结构)。相比之下,Dash 更加精简。例如,Dash 没有 Bash 中一些用于交互环境的高级特性,但在执行简单的脚本时,Dash 可能会更快。
这三种无论是哪一种脚本解释器,最终调用的还是dash
2、Shell文件命令
2.1文本处理命令
2.1.1 grep
功能:用于在文件中搜索指定的字符串,并打印包含该字符串的行。
示例:
grep "error" log.txt:在log.txt文件中搜索包含 “error” 字符串的行,并将这些行打印出来。
grep "aaa" 1.txt
搜索1.txt中aaa的值:
1txt中的内容
shell脚本
运行结果
grep -r "keyword" directory/:递归地在directory/及其子目录下的所有文件中搜索包含 “keyword” 的行。
2.1.2 sed
功能:用于对文件内容进行编辑,如替换、删除、插入等操作。
示例:
sed's/old_text/new_text/g' file.txt:将file.txt文件中的所有 “old_text” 替换为 “new_text”。其中g表示全局替换,如果没有g,则只替换每行中的第一个匹配项。
sed 's/aaa/bbb/g' 1.txt
sed '1d' file.txt:删除file.txt文件的第一行。
2.1.3awk
功能:用于处理文本文件,它可以对文件中的每一行进行分割、比较、计算等操作。
示例:
awk '{print $1}' file.txt:打印file.txt文件中每一行的第一个字段。默认情况下,awk以空格或制表符作为字段分隔符。
awk '{print $1}' 1.txt
awk -F',' '{print $2}' data.csv:如果data.csv是逗号分隔的文件,-F','选项用于指定逗号为字段分隔符,此命令会打印文件中每一行的第二个字段。
进程管理命令
2.2进程管理命令
2.2.1 ps
功能:用于查看当前系统中的进程状态。
示例:
ps -ef:显示所有进程的详细信息,包括进程的用户、PID(进程 ID)、父进程 ID、启动时间、终端等信息。
ps -ef
ps -aux:类似于ps -ef,不过输出格式略有不同,它也会显示进程占用的 CPU 和内存等资源的使用情况。
2.2.2 kill
功能:用于终止指定的进程。
示例:
kill PID:其中PID是要终止的进程的进程 ID。例如kill 1234会终止进程 ID 为 1234 的进程。
kill -9 PID:强制终止进程。有时候普通的kill命令可能无法终止某些进程,使用kill -9可以更强制地终止进程,但这种方式可能会导致进程没有机会进行清理操作,可能会丢失数据,所以要谨慎使用。
2.3 系统信息查看命令
2.3.1 uname
功能:用于获取系统的相关信息。
示例:
uname -a:显示系统的所有信息,包括内核名称、主机名、内核版本、硬件平台等信息。例如uname -a可能输出类似于Linux server.example.com 5.4.0 - 12 - generic #19 - Ubuntu SMP Wed Dec 23 14:06:04 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux的内容。
2.3.2 df
功能:用于查看文件系统的磁盘空间使用情况。
示例:
df -h:以人类可读的格式(如 KB、MB、GB 等)显示磁盘空间使用情况。例如df -h会显示每个挂载点的文件系统总大小、已使用大小、可用大小、使用率等信息。
2.3.3 free
功能:用于查看系统内存的使用情况。
示例:
free -m:以 MB 为单位显示内存的使用情况,包括总内存、已使用内存、空闲内存、缓存等信息。这有助于了解系统内存资源是否紧张。
3、运行Shell命令
./1.sh
权限不足
查看权限:
ls -l 1.sh
发现缺少执行权限:
“rw-”:这是文件所有者的权限。“r” 表示有读取(read)权限,“w” 表示有写入(write)权限,这里的 “-” 表示没有可执行(execute)权限。所以文件所有者对该文件有读和写的权限,但不能执行它。
“r--”:这是所属组的权限。表示所属组的成员对该文件只有读取权限,没有写入和执行权限。
“r--”:这是其他用户的权限。同样意味着其他用户对该文件也只有读取权限,没有写入和执行权限。
解决方法:
3.1 chmod 加权
chmod +x -R 1.sh
3.2 sh 运行
sh 1.sh
3.3 source
与sh很像,但是颜色会加深
source 2.sh
对比效果:
二、shell 变量
变量:是计算机编程中的一个基本概念。在 Shell 脚本(以及其他编程语言)中,变量就像是一个容器,用于存储数据。这个数据可以是数字、字符串、数组等各种类型的值。例如,你可以把一个人的名字存储在一个变量中,或者把一个文件的路径存储在另一个变量中。
变量有一个名称,通过这个名称可以访问和操作变量中存储的值。就好像每个变量是一个有标签的盒子,标签是变量名,盒子里装的东西就是变量的值。
在 Shell 脚本中,定义变量的方式很简单,变量名不需要提前声明,直接赋值即可。变量名和值之间用 “=” 连接,并且赋值时 “=” 两边不能有空格。例如:
name="A":定义了一个名为name的变量,并将其赋值为 “A”。
可以同时定义多个变量,如:
AA="A"; BB="B":定义了AA和BB两个变量,分别赋值为 “A” 和 “B”。
1.定义变量并输出
首先声明一个变量name,他的值是xiaoyu
name=“xiaoyu”
输出此变量
echo $name
再比如
age=“27”
echo $age
在 Shell(如 Bash、Zsh 等)环境中,$是一个特殊的字符,用于引用变量的值。当你使用$name这种形式时,name被视为一个变量名,$符号告诉 Shell 去获取名为name的变量中存储的值
除了简单的变量引用,$还可以用于更复杂的表达式。例如,${name}_suffix这种形式可以对变量name进行引用,并在其后面添加一个固定的字符串suffix
2进阶一下
echo my name is $name,and my age is $age years old
就可以得到
引号:
1.单引号(' ')
特点:
单引号中的内容会被原样输出,Shell 不会对单引号内的变量进行替换,也不会对其中的特殊字符(如$、\等)进行解释。
示例:
对于特殊字符,比如echo '$(date)',输出结果是$(date),而不是执行date命令后的日期时间,因为单引号阻止了命令替换。
双引号(" ")
特点:
双引号中的变量会被替换为变量的值,并且会对部分特殊字符进行解释。例如,\n会被解释为换行符,\t会被解释为制表符等。但是双引号中的命令替换(如$(command))和算术扩展(如$((expression)))仍然会被执行。
单引号里面的字符视为普通字符,双引号不会或不加引号不会
3.变量拼接
在某些场合下我们想要将变量和字符连接起来
如上,想要实现
my name is“xiaoyu”,and my age is“27”years old
需要为了解决这个问题,问题我们可以使用 双引号" 或者 花括号{}拼接起来
echo my name is $name,and my age is "$age"years old
echo my name is $name,and my age is {$age}years old
上面全部是临时的一个变量变量是由数字,字符串下划线组成,但是不能以数字开头例如9name 这种是不行的,变量中间最好不要有空格,比如 long yu 如果非要用这种可以加个下划线ong_yu="xiaoyu”这种
查看变量:
1.使用echo命令
echo $变量名
2.使用set命令
set
执行set命令后,会显示当前 Shell 会话中定义的所有变量(包括用户自定义变量、环境变量和一些特殊变量,如位置参数变量等)。输出内容可能会比较多,例如会显示变量名和其对应的值,像my_var='Hello'这样的形式,同时还会列出像BASH_VERSION等环境变量和1(如果有命令行参数,第一个参数的值)等位置参数变量。
所以可以使用
set | grep name
就可以显示出关于name的变量
删除变量:
unset name
执行后再查询就没有此变量
shell编程(2)永久环境变量和字符串显位
常见的变量
环境变量
1.PATH 变量
PATH 是 Linux 系统中最重要的环境变量之一。它定义了系统在哪些目录中查找可执行文件。例如,当你在终端输入一个命令(如ls)时,系统会根据 PATH 变量所包含的目录路径依次查找该命令对应的可执行文件。
示例:如果PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,这意味着系统会先在/usr/local/sbin目录中查找命令对应的可执行文件,若没找到,再依次在后面的目录中查找。
用途:方便用户在终端直接执行命令,而不需要输入命令文件的完整路径。
2.HOME 变量
HOME 变量表示当前用户的主目录。它是用户在登录系统后默认的工作目录,存放着用户的个人文件和配置文件等。
示例:对于用户user1,HOME变量可能指向/home/user1。当用户打开终端时,当前目录默认就是/home/user1,并且许多应用程序在保存用户相关文件时也会以HOME变量指向的目录为基础。
用途:确定用户文件的存放位置,以及许多命令(如cd命令在没有参数时)默认的操作目录。
3.SHELL 变量
SHELL 变量指定了当前用户所使用的 shell 程序。shell 是用户与 Linux 系统内核之间的接口,用于解释和执行用户输入的命令。
示例:常见的 shell 有bash(Bourne - Again SHell)、zsh等。如果SHELL = /bin/bash,说明用户正在使用bash作为其 shell 程序。
用途:决定了系统如何解释和执行用户输入的命令,不同的 shell 有不同的语法和功能特点。
4.LANG 变量
LANG 变量用于设置系统的语言环境。它决定了系统显示信息(如菜单、提示信息等)所使用的语言,以及对文本文件的字符编码处理方式等。
示例:如果LANG = en_US.UTF - 8,表示系统采用美国英语作为语言环境,并且使用 UTF - 8 编码。
用途:确保系统在不同语言和编码环境下正确地显示和处理信息。
5.PWD 变量
PWD(Print Working Directory)是一个环境变量,它的值是当前工作目录的绝对路径。绝对路径是从根目录(/)开始的完整路径表示方式。
作用:这个变量用于记录用户当前所在的目录位置,方便系统和用户在执行各种操作(如文件访问、程序执行等)时确定相对路径的起点。许多命令会依赖PWD变量来正确地操作文件和目录。
用户自定义变量
定义方式
用户可以使用变量名=变量值的方式来定义自己的变量。例如,my_var = 10就定义了一个名为my_var的变量,其值为 10。
永久环境变量
配置文件概述
在Linux中,永久环境变量是指在系统启动后始终生效的环境变量。这些变量的配置信息通常存储在特定的配置文件中,不同的Shell有不同的配置文件来管理环境变量。
对于Bash(最常用的Shell)来说,主要的配置文件有/etc/profile、~/.bash_profile、~/.bashrc等。/etc/profile是系统级别的配置文件,对所有用户生效;~/.bash_profile和~/.bashrc是用户级别的配置文件,只对当前用户生效。
系统级别的永久环境变量(/etc/profile)
生效方式:
对于系统级别的配置文件修改,一般需要重新启动系统或者使用source /etc/profile命令来使新的配置生效。这是因为当用户登录系统时,/etc/profile文件会被读取一次,重新读取这个文件才能让新定义的环境变量生效。
用户级别的永久环境变量(~/.bash_profile和~/.bashrc)
我们想要做一个随时可以打开的sh脚本需要:
配置永久变量
方法1:移动到系统定义的路径中
将文件移动到/usr/bin/目录
mv 4.sh /usr/bin/
方法2:将ROOT目录加到环境变量
这样可以将整个目录中的文件都可执行
export PATH=/root:PATH
字符串
想知道一个字符串长度,或者想解析一个字符串的长度,输出字符长度
str="hello world"
echo ${#str}
字符串截取操作
echo ${str:0:5}
${str:0:5} : ${str} 表示变量 str 的值。
:0 :表示起始位置,这里是 0 ,即字符串的第一个字符。
:5 :表示要提取的长度,这里是 5 ,即从起始位置开始提取 5 个字符。也可以是负数(倒序)
shell (3)脚本参数传递与数学运算
脚本参数传递
1.基本概念
在 Shell 脚本中,参数传递是一种将外部的值传递到脚本内部的机制。当执行一个 Shell 脚本时,可以在脚本名称后面跟上一些参数,这些参数可以在脚本内部被使用,就像函数的参数一样。
在 Shell 脚本中,参数可以通过特殊的变量来访问。$0代表脚本本身的名称,$1代表传递给脚本的第一个参数,$2代表第二个参数,以此类推。$#表示传递给脚本的参数的个数。
例如,下面是一个简单的脚本5.sh:
echo "脚本名称是:$0"
echo "第一个参数是:$1"
echo "第二个参数是:$2"
echo "参数的个数是:$#"
当执行./5.sh hello world时,输出结果如下:
2.特殊参数处理
$* 会将所有的参数作为一个字符串传出,以空格分隔的字符串。
$0:脚本名称。
$#:传递给脚本的参数个数。
$@:与 $* 类似,但保留参数的分隔方式。
$$:当前脚本的进程 ID。
$?:上一个命令的返回值(退出状态)。
$_: 上一个命令的最后一个参数。
"$*":将所有参数视为一个整体,参数之间使用$IFS分隔。
"$@":将每个参数视为独立的个体。
例如6.sh:
echo "使用\$*获取所有参数:$*"
3.参数的移位操作
shift命令用于将参数向左移动。每次执行shift命令,$1的值会被丢弃,$2的值会变成$1,$3的值会变成$2,以此类推。
例如,下面的脚本7.sh:
echo "初始的第一个参数:$1"
shift
echo "移位后的第一个参数:$1"
当执行./7.sh arg1 arg2时,输出是:
4.使用参数进行条件判断和运算
可以根据传递的参数进行条件判断。例如,判断参数是否符合特定的格式或者范围。
下面是一个简单的脚本check_arg.sh,用于检查第一个参数是否是数字:
if [[ $1 =~ ^[0 - 9]+$ ]]; thenecho "第一个参数是数字。"
elseecho "第一个参数不是数字。"
fi
也可以对参数进行算术运算。例如,有一个脚本add_args.sh用于计算两个参数的和:
sum=$(($1 + $2))
echo "两个参数的和是:$sum"
向脚本传递参数:
echo 执行的文件名是: $0
echo 第一个参数是: $1
echo 传递的参数作为一个字符串显示: $*
echo 传递的参数独立作为每个字符串显示: $@
echo 传递到脚本的参数个数是: $#
echo 最后命令的退出状态: $?
echo 脚本运行的当前进程ID是: $$
可以向脚本程序传递一个或者多个参数 ,脚本中的$1.里面的数字是可以依次递增的,比如$1.$2,$3等等,其中的$0(比较特殊表示文件名称)
如:
shell的数学运算
基本算术运算
在 Shell 中可以进行基本的算术运算,如加法、减法、乘法和除法。常见的有两种方式,一种是使用expr命令,另一种是使用$(( ))或$( )(在某些情况下)结构。
使用expr命令
加法示例:
expr 2 + 3,在命令行中输入这个命令,会返回结果5。注意,expr命令中的运算符和操作数之间需要用空格隔开。
减法示例:
expr 5 - 2会返回3。
乘法示例:
乘法稍微有点复杂,因为在expr命令中,乘法运算符需要转义。例如,expr 3 \* 4会返回12。
取余运算(模运算)
取余运算可以得到除法运算的余数。使用expr命令
例如,expr 7 % 3会返回1,即 7 除以 3 的余数。
使用$(( ))结构
可以写成echo $((7 % 3)),同样会返回1。
除法示例:
expr 10 / 2会返回5。
使用$(( ))结构
这是一种更方便的算术运算方式。例如,echo $((2 + 3))会在终端输出5。它支持多种算术运算,并且不需要对运算符进行特殊处理(如乘法不需要转义)。减法可以这样写:echo $((7 - 4)),输出为3;乘法如echo $((3*4)),输出为12;除法如echo $((10/2)),输出为5。
加减法:
乘除法:
取余
混合运算(Shell会先乘除后加减)
如果想先加减后乘除可以使用括号,但是需要使用转义符\
如:
运算与变量结合
注意是反引号 [ ` ] ——ESC键下方,1键左方
反引号与单引号的区别:
shell编程(4)脚本与用户交互以及if条件判断
脚本与用户交互
read
在 Shell 脚本中,read是一个非常有用的内置命令。它的主要功能是从标准输入(通常是用户通过键盘输入)读取数据,并将读取到的数据赋值给一个或多个变量。这使得脚本能够与用户进行交互,获取用户输入的信息,如用户名、密码、文件路径等各种数据。
基本语法格式
一般形式为
read [选项] [变量名1] [变量名2...]
例如,read name,这里read命令会等待用户输入,将用户输入的内容赋值给变量name。如果有多个变量,如read name age city,用户输入的内容会按照空格分割,并依次赋值给name、age和city变量。
常用选项
-p(prompt)选项
用于在读取用户输入之前显示一个提示信息。这个提示信息可以告诉用户需要输入什么内容,使得交互更加友好。
read -p "Please enter your username: " user
当脚本执行到这一行时,会先在终端显示Please enter your username:作为提示,然后等待用户输入用户名,并将输入的内容赋值给变量user。
-n(number of characters)选项
指定要读取的字符数。当用户输入达到指定的字符数后,read命令就会停止读取。
read -n 5 password
此时,脚本会读取用户输入的前 5 个字符作为密码,并将其赋值给变量password。例如,用户输入abcdef,那么变量password的值就是abcde。
-t(timeout)选项
设置读取输入的超时时间,单位是秒。如果在指定的时间内没有接收到用户输入,read命令会结束等待,脚本继续执行。
read -t 10 -p "Enter a number within 10 seconds: " num
脚本会显示提示信息Enter a number within 10 seconds:,并等待用户输入一个数字。如果 10 秒内用户没有输入,read命令就会结束,脚本继续执行后面的内容。如果用户在 10 秒内输入了内容,那么输入的内容会赋值给变量num。
-s(silent)选项
用于在读取用户输入时不显示输入的内容,通常用于读取密码等敏感信息。
read -s password
当用户输入密码时,终端不会显示输入的字符,输入完成后,密码会赋值给变量password。
利用read进行交互,批量采集信息
输入信息
echo打印信息
利用read -p "请输入你的姓名" name 输入
read -t 10 -p "请输入你的姓名:" name
解释:我们用户10秒没有输入自动退出程序,那么如果我们在10秒内输入了就会执行成功
如何限制用户输入的字符个数?
read -n 3 -t 10 -p "请输入你的姓名:" name
-n (限制字符输入的数量)
-t (如果十秒不输入的话,自动退出)
请输入你的姓名并且限制你的字符串为三个:
vim 12.sh
read -p "请输入你的姓名:" name
echo "你输入的姓名是:$name,请你确认!"
关系运算符
在 Shell 脚本中,关系运算符用于比较两个操作数的值,以确定它们之间的关系,如大小关系、相等关系等。这些关系运算符通常在条件语句(如if语句)中使用,来根据不同的条件执行不同的代码块。
常见的关系运算符
-eq(等于)
用于比较两个数值是否相等。如果相等,条件为真。例如,在if语句中:
a=5
b=5
if [ $a -eq $b ]; thenecho "a is equal to b"
elseecho "a is not equal to b"
fi
这里,因为a和b的值都是 5,所以会输出a is equal to b
ne(不等于)
用于判断两个数值是否不相等。例如:
a=3
b=5
if [ $a -ne $b ]; thenecho "a is not equal to b"
elseecho "a is equal to b"
fi
由于 3 不等于 5,所以会输出a is not equal to b。
-gt(大于)
用于比较第一个数值是否大于第二个数值。例如:
a=7
b=5
if [ $a -gt $b ]; thenecho "a is greater than b"
elseecho "a is not greater than b"
fi
因为 7 大于 5,所以会输出a is greater than b
。
-lt(小于)
用来判断第一个数值是否小于第二个数值。例如:
a=3
b=5
if [ $a -lt $b ]; thenecho "a is less than b"
elseecho "a is not less than b"
fi
-ge(大于等于)
检查第一个数值是否大于或等于第二个数值。例如:
a=5
b=5
if [ $a -ge $b ]; thenecho "a is greater than or equal to b"
elseecho "a is less than b"
fi
因为a和b相等,满足大于或等于的条件,所以输出a is greater than or equal to b。
-le(小于等于)
用于确定第一个数值是否小于或等于第二个数值。例如:
a=3
b=5
if [ $a -le $b ]; thenecho "a is less than or equal to b"
elseecho "a is greater than b"
fi
if - else语句结构中的else基本概念
在 Shell 脚本中,if语句用于根据条件执行不同的代码块。当if语句中的条件为真时,会执行if代码块中的内容;而当条件为假时,就会执行else代码块中的内容。else是if语句的一部分,用于提供条件不成立时的备用执行路径。
例如,下面的脚本用于判断两个数的大小:
a=5
b=3
if [ $a -gt $b ]; thenecho "$a is greater than $b"
elseecho "$a is not greater than $b"
fi
这里,首先判断$a -gt $b(即 5 是否大于 3)这个条件。因为条件为真,所以会执行if代码块中的echo "$a is greater than $b",输出5 is greater than 3。如果将a的值改为 2,那么$a -gt $b条件为假,就会执行else代码块中的echo "$a is not greater than $b"。
else与多个关系运算符结合使用
可以在if语句中使用多个关系运算符来构建复杂的条件判断,else依然用于处理这些复杂条件不成立的情况。
例如,判断一个数是否在某个区间内:
num=7
if [ $num -ge 5 ] && [ $num -le 10 ]; thenecho "$num is between 5 and 10 (inclusive)"
elseecho "$num is not between 5 and 10 (inclusive)"
fi
这里,if语句中的条件使用了-ge(大于等于)和-le(小于等于)两个关系运算符,判断$num是否在 5 到 10 这个区间内。如果num的值满足这个区间条件,就执行if代码块;否则执行else代码块。
else在嵌套if语句中的应用
在嵌套的if语句中,else可以出现在内层if语句和外层if语句中,用于处理不同层次的条件不成立情况。
例如,判断一个学生的成绩等级:
score=85
if [ $score -ge 90 ]; thenecho "A"
elseif [ $score -ge 80 ]; thenecho "B"elseif [ $score -ge 70 ]; thenecho "C"elseif [ $score -ge 60 ]; thenecho "D"elseecho "F"endendend
end
在这个嵌套的if
结构中,外层if
语句首先判断成绩是否大于等于 90 分。如果不满足,就进入第一个内层if
语句,判断成绩是否大于等于 80 分,以此类推。每个else
部分负责处理当前if
条件不成立的情况,直到确定成绩所属的等级。这种结构可以很精细地划分不同的条件范围,通过else
来确保所有可能的情况都有相应的处理代码。
注意事项
操作数的数据类型:关系运算符主要用于数值比较。如果操作数是字符串,可能会得到意外的结果。不过,在某些情况下,如使用-eq和-ne比较字符串时,会比较它们的长度是否相等和不相等。
空格的重要性:在使用关系运算符时,[和]与操作数之间需要有空格。例如,[ $a -eq $b ]是正确的格式,缺少空格可能会导致语法错误。同时,变量名与运算符之间也需要有空格,如$a -eq $b。
vim 13.sh:
num1=11
num2=89if [ "$num1" -eq "$num2" ]; then
echo "相等"
else
echo "不相等"
fi
也可以使用test来更换[ ]
条件判断部分:
if [ $num1 -eq $num2 ] :这里if语句来进行条件判断。在if语句的条件表达式中,[] (注意使用时该括号与里面的内容都要有空格隔开)在shell脚本中用于进行各种测试操作。
$num1和$num2是对前面定义的两个变量num1和num2的引用,获取它们的值来参与条件判断。-eq是一个比较操作符,用于判断两个值是否相等,。所以整个语句就是在判断两个值是否传相等。
执行逻辑部分:
then:如果前面的条件判断结果为真,那么就会then后面的代码块。
echo 相等:当条件满足时,会执行这段代码,通过echo输出字符串 “相等”
else:当前面的条件判断为假时,就会执行else后面的代码块。
echo 不相等:当前面的条件判断为假时,就会执行这段代码,通过echo输出字符串 “不相等”
shell(5)字符串运算符和逻辑运算符
字符串运算符
定义与用途
字符串运算符用于对字符串进行操作,比如比较两个字符串是否相等、判断一个字符串是否为空等。这些运算符在 Shell 脚本编写中非常有用,特别是在处理文本文件、用户输入以及配置文件等场景下。
常见的字符串运算符
等于(==):和不等(!=)
等于(==):用于判断两个字符串是否完全相同
不等(!=) :用于判断两个字符串是否不同。
大于(>)和小于(<) :在字符串比较中,按照字典序(字符编码顺序)来判断大小。
-z:(字符串长度为零)
-z:用于检查一个字符串是否为空(长度为 0)。
-n:(字符串长度不为零)
-n:与-z相反,用于检查一个字符串是否非空。
创建14.sh
str1="hello"
str2="hello"
if [ "$str1" = "$str2" ]; then
echo True
else
echo False
fi
而将对比字符的字母换成大写后
得到了不同的结果
将脚本中的=改为!=试试(不等于)
然后会自动变成≠
运行,因为对比中一个是大写另一个是小写,对比不相同所以返回为真
-z:检查字符串长度是否为0
同理,-n 检查字符串长度是否不为0
num1=9
# num2=19
if [ "$num1" != "9" ]; then
echo num1 不等于9
else
echo num1 等于9
fi
布尔运算符
布尔运算符主要用于操作布尔值(真或假),在 Shell 脚本中帮助构建复杂的条件判断。它们允许将多个条件组合在一起,以确定是否执行特定的代码块。布尔运算符就像是逻辑连接词,使脚本能够根据多种情况的组合做出决策。
常见的布尔运算符及用法
逻辑与(&&)(使用-a):
运算规则:只有当 && 两边的条件都为真时,整个表达式才为真。如果左边的条件为假,就不会再检查右边的条件,因为只要有一个为假,整个 “与” 运算结果就为假。这被称为短路特性。
num1=5
num2=10
if [ $num1 -gt 0 -a $num2 -lt 20 ]; thenecho "Both conditions are true"
elseecho "At least one condition is false"
end
逻辑或(||)(使用-o):
运算规则:只要 || 两边的条件中有一个为真,整个表达式就为真。如果左边的条件为真,就不会检查右边的条件,因为只要有一个为真,整个 “或” 运算结果就为真,这也是短路特性。
num1=5
num2=30
if [ $num1 -lt 0 -o $num2 -gt 20 ]; thenecho "At least one condition is true"
elseecho "Both conditions are false"
end
逻辑非(!)
运算规则:用于对一个布尔值进行取反操作。如果原始条件为真,加上 “!” 后就变为假;如果原始条件为假,加上 “!” 后就变为真。
num1=5
num2=30
[ $num1 -lt 0 ] || [ $num2 -gt 20 ] || echo "At least one condition is true"
余运算 ——与门、或门对比:
num1=9
num2=19
if [ "$num1" != 9 -a "$num2" -lt 20 ]; then
echo true
else
echo False
fi
首先,代码中进行了两个变量的赋值操作:
num1=9:将数值9赋给变量num1。
num2=19:把数值19赋给变量num2。
条件判断
接着是if语句中的条件判断部分:
在 Shell 中,[ ](也可写成test)用于进行条件测试。这里的条件表达式是[ "$num1"!= 9 -a "$num2" -lt 20 ]。
对于"$num1"!= 9这部分:
双引号括住num1是为了处理可能出现的变量值为空等特殊情况,确保语法正确。在这里,num1的值实际为9,所以"$num1"!= 9这个条件不成立,即为假。
对于-a运算符:
-a是逻辑与运算符,它要求连接的两个条件都为真时,整个条件表达式才为真。
对于"$num2" -lt 20这部分:
同样双引号是为了保证语法正确。num2的值是19,确实小于20,所以"$num2" -lt 20这个条件成立,即为真。
综合起来看,整个条件表达式[ "$num1"!= 9 -a "$num2" -lt 20 ],因为-a连接的两个条件中,"$num1"!= 9为假,根据逻辑与运算规则,只要有一个条件为假,整个表达式就为假。
num1=9
num2=19
if [ "$num1" != 9 -o "$num2" -lt 20 ]; then
echo true
else
echo False
fi
这段 Shell 脚本代码的主要目的是根据对两个变量 num1 和 num2 的条件判断来输出不同的结果。它使用了 if 语句结合条件表达式来实现这种逻辑判断。
代码解析
变量赋值部分:
num1=9:这行代码将整数 9 赋值给变量 num1。
num2=19:同样,这行代码将整数 19 赋值给变量 num2。
if 语句条件判断部分:
在 Shell 中,if 语句用于根据条件的真假来执行不同的代码块。这里的条件判断表达式是 [ "$num1"!= 9 -o "$num2" -lt 20 ]。
[ ](也可写成 test)是用于条件判断的语法结构。其中:
"$num1"!= 9:这部分是检查变量 num1 的值是否不等于 9。这里需要注意将变量 num1 用双引号括起来,是为了防止变量值为空时出现语法错误等情况。在当前代码中,num1 的值实际为 9,所以这部分条件为假。
-o:这是逻辑或运算符,用于连接两个条件判断。表示只要 -o 前后的两个条件中有一个为真,整个条件表达式就为真。
"$num2" -lt 20:这部分是检查变量 num2 的值是否小于 20。同样,变量 num2 用双引号括起来。由于 num2 的值为 19,是小于 20 的,所以这部分条件为真。
综合起来,整个条件表达式 [ "$num1"!= 9 -o "$num2" -lt 20 ] 因为 -o 运算符连接的两个条件中有一个(即 "$num2" -lt 20)为真,所以整个条件为真。
if 语句执行部分:
由于条件判断部分的结果为真,所以会执行 if 语句中对应的代码块,也就是 echo true。
shell(6)if条件判断与for循环结构
if的基本概念
在 Shell 脚本中,if条件判断用于根据不同的条件执行不同的命令块。它允许脚本根据条件的真假来决定程序的流程走向。
条件判断可以基于各种因素,如文件是否存在、变量的值、命令的执行结果等。
基本语法结构
最基本的if语句结构如下:
if [ condition ]; thencommands
fi
其中,[ condition ]是条件表达式,它必须被方括号包围,并且在方括号内部的条件表达式两边要有空格。then关键字后面跟着当条件为真时要执行的命令块,fi是if语句的结束标志。
例如,判断一个变量num是否大于 10:
num=15
if [ $num -gt 10 ]; thenecho "The number is greater than 10"
fi
条件表达式类型
文件测试条件
可以测试文件的各种属性。例如,-e用于测试文件是否存在,-f用于测试是否是普通文件,-d用于测试是否是目录。
示例:
file="/etc/passwd"
if [ -e $file ]; thenecho "The file $file exists."
elseecho "The file $file does not exist."
fi
数值比较条件
用于比较两个数值的大小关系。如-eq(等于)、-ne(不等于)、-lt(小于)、-le(小于等于)、-gt(大于)、-ge(大于等于)。
注意,在进行数值比较时,变量的引用方式要正确,并且要保证是数值类型的比较。例如:
a=5
b=3
if [ $a -gt $b ]; thenecho "a is greater than b"
fi
字符串比较条件
可以比较字符串是否相等(==或=)、是否不等(!=),还可以测试字符串的长度是否为 0(-z)等。
例如,比较两个字符串是否相等:
str1="hello"
str2="world"
if [ $str1!= $str2 ]; thenecho "The two strings are not equal."
fi
if - else和if - elif - else结构
if - else结构
当if条件不满足时,可以使用else分支来执行另外一组命令。语法如下:
if [ condition ]; thencommands1
elsecommands2
fi
例如,判断一个数是偶数还是奇数:
num=7
if [ $(($num % 2)) -eq 0 ]; thenecho "The number is even."
elseecho "The number is odd."
fi
if - elif - else结构
当有多个条件需要依次判断时,可以使用elif(是else if的缩写)。语法如下:
if [ condition1 ]; thencommands1
elif [ condition2 ]; thencommands2
elsecommands3
fi
例如,根据成绩等级输出评价:
score=75
if [ $score -ge 90 ]; thenecho "Excellent"
elif [ $score -ge 80 ]; thenecho "Good"
elif [ $score -ge 60 ]; thenecho "Pass"
elseecho "Fail"
fi
if判断符号
大于 -gt (greater than)检查左边的数值是否大于右边的数值
a=7
b=5
if [ $a -gt $b ]; thenecho "a大于b"
fi
小于 -lt (less than)用于判断左边的数值是否小于右边的数值
a=3
b=5
if [ $a -lt $b ]; thenecho "a小于b"
fi
大于或等于 -ge (greater than or equal)
a=5
b=5
if [ $a -ge $b ]; thenecho "a大于等于b"
fi
小于或等于 -le (less than or equal)
a=3
b=3
if [ $a -le $b ]; thenecho "a小于等于b"
fi
不相等 -ne (not equal)判断两个数值是否不相等。
a=3
b=5
if [ $a -ne $b ]; thenecho "a不等于b"
fi
相等 -eq (equal)用于判断两个数值是否相等。
a=5
b=5
if [ $a -eq $b ]; thenecho "a等于b"
fi
字符串比较运算符
=(等于):用于判断两个字符串是否相等
=(不等于):判断两个字符串是否不相等。
-z(字符串长度为零):检查字符串是否为空
文件测试运算符
-e(文件或目录存在):用于判断文件或目录是否存在
file="test.txt"
if [ -e $file ]; thenecho "文件存在"
fi
-f(文件存在且为普通文件):检查是否是一个普通文件存在
file="test.txt"
if [ -f $file ]; thenecho "是普通文件且存在"
fi
-d(目录存在):用于判断目录是否存在。
dir="mydir"
if [ -d $dir ]; thenecho "目录存在"
fi
-r(文件或目录可读):检查文件或目录是否可读。
file="test.txt"
if [ -r $file ]; thenecho "文件可读"
fi
-w(文件或目录可写):用于判断文件或目录是否可写
file="test.txt"
if [ -w $file ]; thenecho "文件可写"
fi
-x(文件或目录可执行):检查文件或目录是否可执行。
file="test.sh"
if [ -x $file ]; thenecho "文件可执行"
fi
for循环结构
在 Shell 脚本中,for循环用于遍历一系列的值,例如列表中的元素、文件中的行等。它允许你对一组数据中的每个元素执行相同的操作,从而避免了重复编写相似的代码。
基本语法结构
最常见的语法形式如下:
for variable in list; docommands
done
其中,variable是一个变量,在每次循环迭代时,它会被赋予list中的一个值。list可以是一个用空格分隔的值列表,也可以是一个由命令生成的结果列表。do后面跟着要在每次循环中执行的命令块,done标志着for循环的结束。
例如,遍历一个数字列表并打印每个数字:
for i in 1 2 3 4 5; doecho $i
done
不同类型的列表遍历
遍历数字序列
可以使用{start..end}的形式来生成一个数字序列。例如,要遍历从 1 到 10 的数字:
for i in {1..10}; doecho $i
done
还可以指定步长,如{start..end..step}。例如,要遍历 1 到 10 之间的奇数(步长为 2):
for i in {1..10..2}; doecho $i
done
遍历文件列表
可以使用通配符来遍历符合特定模式的文件。例如,要遍历当前目录下所有的.txt文件:
for file in *.txt; doecho $file
done
也可以使用find等命令来生成文件列表,然后在for循环中遍历。例如:
file_list=$(find /path/to/directory -type f)for file in $file_list; doecho $filedone- **遍历命令输出结果**- 很多命令的输出结果可以作为`for`循环的列表。例如,`ls`命令输出当前目录下的文件和目录名。
```bashfor dir in $(ls -d */); doecho $dirdone
这里ls -d */输出当前目录下的所有子目录名,for循环会逐个遍历这些子目录名。
嵌套的for循环
就像其他编程语言一样,Shell 中的for循环也可以嵌套。例如,要打印九九乘法表:
for i in {1..9}; dofor j in {1..9}; doresult=$((i * j))echo -n "$i x $j = $result "doneecho
done
外层for循环控制行数(从 1 到 9),内层for循环控制每行中的列数(也是从 1 到 9)。在每次内层循环中,计算乘法结果并打印,通过echo -n可以不换行打印,当内层循环结束后,使用echo换行,开始下一行的打印。
实例
if实例1
创建 15.sh的脚本
#!/bin/bash
fi
# 定义变量
a=10
b=20
# 进行条件判断
if [ "$a" -eq "$b" ]; then
echo "a=b"
elif [ "$a" -gt "$b" ]; then
echo "a>b"
else
echo "没有符合上述条件"
声明变量a/b,判断:变量A和变量B相等,则输出:A=B,判断:变量A>B则输出,否则输出没有上述情况
if实例2
# 定义变量
a=10
b=20
# 进行条件判断
if [ "$a" -eq "$b" ]; then
echo "a=b"
elif [ "$a" -gt "$b" ]; then
echo "a>b"
elif [ "$a" -lt "$b" ]; then
echo "a<b"
else
echo "没有符合上述条件"fi
for实例1
创建文件16.sh
for num in 1 2 3 4 5
do
echo "the number is $num"
done
for num in 1 2 3 4 5:这是for循环的起始部分。这里定义了一个循环变量num,并且指定了要遍历的列表,在这个例子中,列表就是由数字1、2、3、4、5组成的。循环会依次将列表中的每个元素赋值给变量num。
do:标志着循环体的开始,在do和与之匹配的done之间的代码就是每次循环要执行的操作。
echo "the number is $num":这是循环体内部的代码。它使用echo命令来输出一段文本信息,其中$num是一个变量引用,会被替换为当前循环中num变量所赋的值。也就是说,每次循环时,这里会输出类似"the number is 1"、"the number is 2"等等这样的内容,具体取决于当前循环中num所取到的值。
done:标志着for循环体的结束,当循环遍历完列表中的所有元素后,程序就会继续执行done之后的代码(如果有的话)
for实例2
创建17.sh文件
for str in "hello wold"
do
echo $str
done
for str in "hello world":这是 for 循环的起始部分。这里定义了一个循环变量 str,并且指定了要遍历的字符串 "hello world"。循环会按照空格将字符串分割成一个个单词,然后依次将每个单词赋值给变量 str。
do:标志着循环体的开始,在 do 和与之匹配的 done 之间的代码就是每次循环要执行的操作。
echo $str:这是循环体内部的代码。它使用 echo 命令来输出当前循环中变量 str 的值,也就是会依次输出字符串 "hello world" 被分割后的每个单词,即先输出 "hello",然后下一次循环输出 "world"。
done:标志着 for 循环体的结束,当循环遍历完字符串中所有以空格分隔的单词后,程序就会继续执行 done 之后的代码(如果有的话)。
shell(7)for循环与while循环
一、for循环
1. 反引号 ``
在 Shell 中,反引号(`)用于命令替换。这意味着可以在反引号中放入一个命令,然后在执行包含反引号的语句时,会先执行反引号中的命令,并用命令的输出结果来替换反引号中的内容。
在for循环中使用反引号执行命令的示例
假设要遍历当前目录下所有文件的文件名,可以使用ls命令。以下是一个for循环结合反引号的示例:
for file in `ls`; doecho "文件名是: $file"
done
解释:
for file in ls``:在这个部分,ls命令被放在反引号中。当 Shell 开始执行这个for循环时,首先会执行ls命令。ls命令会列出当前目录下的所有文件和目录的名称,这些名称会以空格为分隔符形成一个列表。然后for循环会将这个列表中的每个元素依次赋值给变量file。
do和done之间的部分是循环体。echo "文件名是: $file"会输出每个文件名,其中$file是当前循环中被赋值的文件名。
注意事项
反引号中的命令如果输出包含特殊字符(如空格、制表符等),可能会导致意外的结果。例如,如果文件名中有空格,上述for循环可能会将文件名错误地分割。在这种情况下,可以使用$( )来代替反引号进行命令替换,例如for file in $(ls); do...,不过它也有同样的潜在问题。更安全的做法是使用find命令并结合-maxdepth和-type等选项来处理文件列表,如for file in $(find. -maxdepth 1 -type f); do...,这样可以更准确地获取文件列表,特别是在处理包含特殊字符的文件名时。
2.$()
在 Shell 中,$()是一种命令替换的语法。它的功能与反引号()类似,都是用于执行其中的命令,并将命令的输出结果作为值来替换或反引号部分。使用()` 的语法更加清晰,特别是在嵌套使用命令替换时,可读性更好。
命令替换的概念
在for循环中使用$()的示例
例如,要遍历当前目录下所有以.txt结尾的文件的文件名,可以使用find命令结合$()在for循环中进行操作,如下所示:
for file in $(find. -name "*.txt" -maxdepth 1); doecho "文件名是: $file"
done
解释:
$(find. -name "*.txt" -maxdepth 1)部分:
find命令用于查找文件。在这里,find的参数含义如下:
.表示从当前目录开始查找。
-name "*.txt"表示查找文件名是以.txt结尾的文件。
-maxdepth 1表示只在当前目录(深度为 1)查找,不包括子目录中的文件。
整个$(find. -name "*.txt" -maxdepth 1)会先执行find命令,得到一个包含所有符合条件(当前目录下以.txt结尾)的文件列表,这些文件名以空格分隔。
for file in...部分:将find命令输出的文件列表中的每个文件名依次赋值给变量file。
echo "文件名是: $file"部分:在循环体中,每次循环都会输出当前文件名,其中$file是当前循环中被赋值的文件名。
与反引号的对比及优势
相比于反引号,$()的嵌套使用更加清晰。
3.双括号 (( ))
双括号(( ))的基本用途
在 Shell 中,双括号(( ))主要用于算术运算。它允许进行更复杂的数学表达式计算,并且语法更接近传统的编程语言中的算术运算语法。在for循环中使用双括号可以方便地控制循环变量的算术运算。
示例一:简单的数字序列循环
以下是一个使用双括号(( ))在for循环中生成数字序列的例子:
for ((i = 1; i <= 5; i++)); doecho $i
done
解释:
((i = 1; i <= 5; i++))部分:
这是for循环的控制表达式,放在双括号中。其中:
i = 1是初始化部分,将变量i初始化为 1。
i <= 5是条件判断部分,每次循环开始时,会检查i的值是否小于等于 5。
i++是迭代部分,在每次循环体执行完后,i的值会自增 1。
echo $i部分:在循环体中,每次循环都会输出变量i的当前值。所以这个循环会依次输出 1、2、3、4、5。
示例二:基于算术运算的条件控制
假设要输出 1 到 10 之间的偶数,可以这样写:
for ((i = 2; i <= 10; i += 2)); doecho $i
done
解释:
((i = 2; i <= 10; i += 2))部分:
初始化i为 2,条件判断是i <= 10,迭代部分是i += 2,这意味着每次循环i的值会增加 2。这样就可以保证只输出偶数。
循环体echo $i会输出每次循环时i的当前值,所以会输出 2、4、6、8、10。
与其他语法的比较
与使用[ ]进行条件判断的for循环相比,(( ))在进行算术运算时更加灵活和方便。例如,在[ ]中进行算术运算需要使用一些特殊的语法,如i=$((i + 1))(在循环体内部)来实现变量的自增,而在(( ))中可以直接使用i++这样自然的算术运算语法。同时,(( ))可以处理更复杂的算术表达式,例如((i = i * 2 + 1)),这在[ ]语法中会比较复杂。
二、while循环
在 Shell 脚本中,while循环是一种控制流结构,用于在满足特定条件时重复执行一段代码块。只要条件为真,循环就会持续进行,直到条件变为假。
语法结构
基本语法如下:
while [ 条件表达式 ]
do循环体(要执行的命令或代码块)
done
其中,[ 条件表达式 ]部分用于判断循环是否继续执行。这个表达式通常会使用比较运算符(如-eq(等于)、-ne(不等于)、-gt(大于)、-lt(小于)、-ge(大于等于)、-le(小于等于))来对数值进行比较,或者使用字符串比较运算符(如=、!=)来比较字符串,也可以包含文件测试运算符(如-e(存在)、-f(普通文件)、-d(目录)等)来检查文件相关的属性。do和done之间的部分就是循环体,这里面放置的是每次循环需要执行的命令。
执行流程
当脚本执行到while循环时,首先会对[ 条件表达式 ]进行计算。如果条件表达式的计算结果为真(在 Shell 脚本中,通常返回值为 0 表示真),那么就会执行do和done之间的循环体代码。在循环体执行完毕后,会再次对[ 条件表达式 ]进行计算,只要结果仍然为真,就会再次执行循环体,如此反复,直到[ 条件表达式 ]的计算结果为假(返回值非 0),此时循环结束,脚本会继续执行done之后的代码。
简单示例
下面是一个简单的示例,用于计算从 1 加到 10 的和:
sum=0
i=1
while [ $i -le 10 ]
dosum=$((sum + i))i=$((i + 1))
done
echo "从1加到10的和为: $sum"
解释:
首先,初始化两个变量sum=0和i=1,sum用于存储累加的结果,i作为计数器。
然后进入while循环,条件是[ $i -le 10 ],即检查i是否小于等于 10。因为初始i = 1,满足条件,所以执行循环体。
在循环体中,sum=$((sum + i))将当前i的值累加到sum中,i=$((i + 1))将i的值加 1。
第一次循环结束后,sum的值变为 1,i的值变为 2。再次检查条件,仍然满足,继续执行循环体。这样一直循环,直到i的值变为 11,此时条件不满足,循环结束。最后通过echo命令输出累加的结果。
实例
for循环实例1反引号
for i in `seq 1 100`
do
echo $i
done
代码详细解释
for i in seq 1 100``:这是for循环的起始部分。
seq 1 100是一个 Shell 命令,它的作用是生成一个从 1 到 100 的整数序列,每个整数之间用空格分隔。
反引号()在这里用于命令替换,即将seq 1 100这个命令的输出结果(也就是生成的整数序列)替换到for i in...这个语句中。然后for循环会将这个整数序列中的每个整数依次赋值给变量i`。
do:标志着循环体的开始,在do和与之匹配的done之间的代码就是每次循环要执行的操作。
echo $i:这是循环体内部的代码。它使用echo命令来输出变量i的值,由于在每次循环中i会被赋值为从seq 1 100得到的整数序列中的不同整数,所以这里会依次输出从 1 到 100 的每个整数。
done:标志着for循环体的结束,当循环遍历完从seq 1 100生成的所有整数后,程序就会继续执行done之后的代码(如果有的话)。
for循环实例2$()
for i in $(seq 1 100)
do
echo $i
done
功能概述
这段 Shell 脚本利用for循环结构结合seq命令,实现了对从 1 到 100 的整数依次进行遍历,并将每个整数输出显示的功能。
代码解析
for i in $(seq 1 100)部分:
$(seq 1 100):这里使用了命令替换的语法$( )。seq是 Shell 中的一个实用命令,用于生成指定范围内的整数序列。在这个例子中,seq 1 100会生成一个从 1 到 100 的整数序列,各个整数之间以空格作为分隔符。然后,通过$( )进行命令替换,将seq命令生成的整数序列替换到for循环的表达式中。
for i in...:定义了一个循环变量i,并且让for循环将$(seq 1 100)所生成的整数序列中的每一个整数依次赋值给变量i。
do部分:它标志着循环体的开始。在for循环结构中,do和与之匹配的done之间的代码段就是每次循环要执行的具体操作内容。
echo $i部分:这是循环体内部的核心代码。echo是 Shell 中用于输出信息的命令,在这里,它会输出变量i的值。由于在每次循环时,变量i都会被赋值为$(seq 1 100)所生成的整数序列中的不同整数,所以每次循环都会输出一个不同的整数,从 1 开始,依次递增,直到 100。
done部分:它标志着for循环体的结束。当for循环完成了对$(seq 1 100)生成的所有整数的遍历操作,即对每个整数都执行了一次循环体中的操作后,程序就会继续执行done之后的代码(如果存在的话)。
seq命令
seq命令用于生成数字序列。它是一个简单而实用的命令行工具,在 Shell 脚本编写和命令行操作中经常用于需要连续数字序列的场景,比如循环计数、生成文件编号序列等。
语法格式
基本语法为seq [选项] 起始值 增量值 结束值或seq [选项] 起始值 结束值。
其中,“起始值” 是序列开始的数字,“增量值” 是序列中相邻两个数字之间的差值(如果省略,默认为 1),“结束值” 是序列结束的数字。
for循环实例3双括号
for ((i=1; i<10;i++))
do
echo $i
done
代码结构与功能
这段代码使用了 Shell 中的一种for循环语法格式,用于实现从 1 到 9 的数字依次输出的功能。
具体分析
for ((i=1; i<10; i++))部分:
这是for循环的控制表达式部分,使用了双括号(( ))的语法形式。
i=1是初始化操作,它定义并初始化了循环变量i的值为 1。
i<10是条件判断部分,在每次循环开始前,都会检查循环变量i的值是否小于 10。只要这个条件满足,循环就会继续执行。
i++是迭代操作,在每次循环体执行完毕后,会对循环变量i进行自增操作,即将其值增加 1。
do部分:
它标志着循环体的开始。在for循环结构中,do和与之匹配的done之间的代码就是每次循环要执行的具体操作内容。
echo $i部分:
这是循环体内部的代码。echo是 Shell 中用于输出信息的命令,在这里它会输出变量i的值。由于在每次循环时,变量i的值会根据循环的迭代操作不断变化,所以每次循环都会输出一个不同的数字,从 1 开始,依次递增,直到 9(因为当i的值达到 10 时,条件i<10不满足,循环就会停止)。
done部分:
它标志着for循环体的结束。当for循环完成了对满足条件的所有数字的遍历操作,即对每个符合条件的数字都执行了一次循环体中的操作后,程序就会继续执行done之后的代码(如果存在的话)。
while循环实例1双括号
i=1
while(( $i<=10 ))
do
echo $i
((i++))
done
功能概述
这段 Shell 脚本利用while循环结构实现了从 1 到 10 的整数依次输出的功能。通过不断地检查循环条件并更新循环变量的值,在满足条件的情况下重复执行循环体内的输出操作。
代码解析
i = 1部分:
这是对变量i进行初始化的操作,将变量i的值初始化为 1,为后续的循环操作提供初始值。
while(( $i <= 10 ))部分:
这是while循环的条件判断部分。使用双括号(( ))进行条件判断,在这里主要用于算术运算相关的条件判断。
$i <= 10是具体的条件表达式,它会检查变量i的值是否小于等于 10。只要这个条件为真(即变量i的值满足小于等于 10 的要求),while循环就会继续执行循环体中的代码。
do部分:
它标志着循环体的开始。在while循环结构中,do和与之匹配的done之间的代码段就是每次循环要执行的具体操作内容。
echo $i部分:
这是循环体内部的代码。echo是 Shell 中用于输出信息的命令,在这里它会输出变量i的值。由于在每次循环时,变量i的值会根据循环的执行情况发生变化,所以每次循环都会输出一个不同的整数,从 1 开始,依次递增,直到满足循环条件的最大整数(在这里是 10)。
((i++))部分:
这是在循环体内部对循环变量i进行更新的操作。使用双括号(( ))进行算术运算,i++表示将变量i的值自增 1。在每次循环体执行完echo $i操作后,就会执行这个操作来更新变量i的值,以便下一次循环时进行新的条件判断和输出操作。
done部分:
它标志着while循环体的结束。当while循环完成了对满足条件的所有整数的遍历操作,即对每个符合条件的整数都执行了一次循环体中的操作后,程序就会继续执行done之后的代码(如果存在的话)。
while循环实例2 双引号和let
i=1
while(( $i<=10 ))
do
echo $i
let "i++"
done
功能说明
这段 Shell 脚本通过while循环实现了从 1 到 10 的整数依次输出的功能。在循环过程中,不断判断循环条件是否满足,并更新循环变量的值以控制循环的执行次数。
代码解析
i = 1:
这一步是对变量i进行初始化,将其值设定为 1,为后续的循环操作提供起始值。
while(( $i <= 10 )):
这里是while循环的条件判断部分。使用双括号(( ))来进行条件的判断,主要用于处理算术运算相关的条件。
具体的条件表达式是$i <= 10,它会检查变量i的当前值是否小于等于 10。只要这个条件成立(即变量i的值满足小于等于 10 的要求),while循环就会继续执行循环体中的代码。
do:
标志着循环体的开始。在while循环结构中,do和与之匹配的done之间的代码就是每次循环要执行的具体操作内容。
echo $i:
这是循环体内部的代码。echo是 Shell 中用于输出信息的命令,在这里它会输出变量i的当前值。由于在每次循环时,变量i的值会根据循环的执行情况而改变,所以每次循环都会输出一个不同的整数,从 1 开始,依次递增,直到满足循环条件的最大整数(也就是 10)。
let "i++":
let是 Shell 中的一个命令,用于执行算术运算。在这里,let "i++"的作用是将变量i的值自增 1。在每次循环体执行完echo $i操作之后,就会执行let "i++"来更新变量i的值,以便下一次循环时进行新的条件判断和输出操作。
done:标志着while循环体的结束。当while循环完成了对满足条件的所有整数的遍历操作,即对每个符合条件的整数都执行了一次循环体中的操作后,程序就会继续执行done之后的代码(如果存在的话)
shell编程(8) until循环以及函数基本创建调用
until循环
基本概念
在 Shell 脚本中,until循环是一种与while循环相对应的控制流结构。while循环是在条件为真时执行循环体,而until循环则是在条件为假时执行循环体,直到条件变为真时才停止循环。
语法结构
基本语法如下:
until [ 条件表达式 ]
do循环体(要执行的命令或代码块)
done
其中,[ 条件表达式 ]部分用于判断循环是否结束。这个表达式和while循环中的条件表达式类似,可以使用比较运算符(如-eq(等于)、-ne(不等于)、-gt(大于)、-lt(小于)、-ge(大于等于)、-le(小于等于))来比较数值,也可以使用字符串比较运算符(如=、!=)来比较字符串,还可以包含文件测试运算符(如-e(存在)、-f(普通文件)、-d(目录)等)。do和done之间的部分就是循环体,这里面放置的是每次循环需要执行的命令。
执行流程
当脚本执行到until循环时,首先会对[ 条件表达式 ]进行计算。如果条件表达式的计算结果为假(在 Shell 脚本中,通常返回值为非 0 表示假),那么就会执行do和done之间的循环体代码。在循环体执行完毕后,会再次对[ 条件表达式 ]进行计算,只要结果仍然为假,就会再次执行循环体,如此反复,直到[ 条件表达式 ]的计算结果为真(返回值为 0),此时循环结束,脚本会继续执行done之后的代码。
简单示例
下面是一个简单的示例,用于计算从 1 加到 10 的和:
sum=0
i=1
until [ $i -gt 10 ]
dosum=$((sum + i))i=$((i + 1))
done
echo "从1加到10的和为: $sum"
首先,初始化两个变量sum = 0和i = 1,sum用于存储累加的结果,i作为计数器。
然后进入until循环,条件是[ $i -gt 10 ],即检查i是否大于 10。由于初始i = 1,条件为假,所以执行循环体。
在循环体中,sum=$((sum + i))将当前i的值累加到sum中,i=$((i + 1))将i的值加 1。
第一次循环结束后,sum的值变为 1,i的值变为 2。再次检查条件,仍然为假,继续执行循环体。这样一直循环,直到i的值变为 11,此时条件为真,循环结束。最后通过echo命令输出累加的结果。
函数
基本概念
Shell 函数是一组可以重复使用的命令集合,将一些相关的操作封装在一起,类似于其他编程语言中的函数。它可以提高代码的复用性和可维护性,使脚本的逻辑结构更加清晰。
实例
until循环1
i=0
until [ ! $i -lt 10 ]
do
echo $i
((i++))
done
功能概述
这段 Shell 脚本利用until循环结构实现了从 0 到 9 的整数依次输出的功能。它通过不断地检查循环终止条件,并在条件未满足时执行循环体内的操作来实现计数输出。
代码解析
i = 0部分:
这是对变量i进行初始化的操作,将变量i的值初始化为 0,为后续的循环操作提供起始值。
until [! $i -lt 10 ]部分:
这是until循环的条件判断部分。
在 Shell 中,[ ](也可写成test)用于条件判断。这里的条件表达式是! $i -lt 10,其中:
$i -lt 10是检查变量i的值是否小于 10。正常情况下,until循环是在条件为假时执行循环体,这里通过在前面加!(逻辑非运算符)进行了反转,即当$i -lt 10这个条件不成立(也就是i的值大于等于 10)时,循环才会停止;而当$i -lt 10成立(即i的值小于 10)时,循环会继续执行。
do部分:
它标志着循环体的开始。在until循环结构中,do和与之匹配的done之间的代码段就是每次循环要执行的具体操作内容。
echo $i部分:
这是循环体内部的代码。echo是 Shell 中用于输出信息的命令,在这里它会输出变量i的值。由于在每次循环时,变量i的值会根据循环的执行情况而改变,所以每次循环都会输出一个不同的整数,从 0 开始,依次递增,直到满足循环终止条件(即i的值达到 10)。
((i++))部分:
这是在循环体内部对循环变量i进行更新的操作。使用双括号(( ))进行算术运算,i++表示将变量i的值自增 1。在每次循环体执行完echo $i操作之后,就会执行((i++))来更新变量i的值,以便下一次循环时进行新的条件判断和输出操作。
done部分:
它标志着until循环体的结束。当until循环完成了对满足循环终止条件之前的所有整数的遍历操作,即对每个符合条件的整数都执行了一次循环体中的操作后,程序就会继续执行done之后的代码(如果存在的话)。
case语句
read -p "请输入一个数值:" num
case $num in
1)echo 你输入的数字是1
;;
2)echo 你输入的数字是2
;;
*)echo 你输入的是:其他的内容
;;
esac
整体流程
首先通过read -p "请输入一个数值:" num这行命令,提示用户在终端输入一个数值,用户输入完成后按回车键,输入的内容就会被存储到num变量中。
然后进入case语句进行判断:
如果num的值等于1,就会执行1)后面的代码,也就是输出你输入的数字是1。
如果num的值等于2,则执行2)后面的代码,输出你输入的数字是2。
如果num的值既不是1也不是2,就会执行*)后面的代码,输出你输入的是:其他的内容。
函数1基本
DemoFunc() {
echo "hello world"
}
DemoFunc
代码功能
这段 Shell 脚本代码定义了一个名为DemoFunc的函数,然后调用了这个函数。函数的功能是在被调用时输出字符串"hello world"。
详细解释
函数定义部分:
DemoFunc() {:这是函数定义的开头部分,声明了一个名为DemoFunc的函数,后面跟着一对花括号{},花括号内的内容就是函数体,定义了函数被调用时要执行的具体操作。
echo "hello world":这是函数体内部的唯一一行代码,当函数DemoFunc被调用时,就会执行这行代码,通过echo命令输出字符串"hello world"。
函数调用部分:
DemoFunc:这是对前面定义的DemoFunc函数进行调用的语句。当执行到这一行时,就会跳转到DemoFunc函数的定义处,执行函数体内部的代码,也就是输出"hello world"。
函数2传递参数
DemoFunc() {
echo "hello world"
echo "My name is $1"
}
DemoFunc Darker
代码功能与执行逻辑
这段 Shell 脚本代码定义了一个名为DemoFunc的函数,然后调用了这个函数并传递了一个参数。函数的主要功能是输出一些固定的字符串以及传入的参数对应的信息。
具体解释
函数定义部分:
DemoFunc() {:这是函数定义的起始部分,声明了一个名为DemoFunc的函数,后面紧跟着一对花括号{},花括号内的内容构成了函数体,也就是函数被调用时要执行的具体操作。
echo "hello world":在函数体中,这是第一条输出语句。当函数DemoFunc被调用时,无论是否传入参数,都会首先执行这行代码,通过echo命令输出字符串"hello world"。
echo "My name is $1":这是函数体中的第二条输出语句。在 Shell 函数中,$1用于指代传入函数的第一个参数。所以当函数DemoFunc被调用并传入参数时,这行代码会输出传入的第一个参数相关的信息,格式为My name is加上传入的第一个参数的值。
函数调用部分:
DemoFunc Darker:这是对前面定义的DemoFunc函数进行调用的语句,并且传入了一个参数Darker。当执行到这一行时,程序会跳转到DemoFunc函数的定义处,按照函数体内部的代码逻辑依次执行。首先会输出"hello world",然后由于传入了参数Darker,$1就获取到了这个值,接着会输出My name is Darker。
函数3多函数调用
DemoFunc(){
echo "hello world"
echo "my name is $1,and is $2 years old"
}
DemoFunc xiaoyu 27
代码功能与执行逻辑
这段 Shell 脚本代码定义了一个名为DemoFunc的函数,然后调用该函数并传递了两个参数。函数的主要功能是输出一些固定的字符串以及传入的两个参数对应的信息。
具体解释
函数定义部分:
DemoFunc() {:这是函数定义的起始部分,声明了一个名为DemoFunc的函数,其后跟着一对花括号{},花括号内的内容构成函数体,即函数被调用时要执行的具体操作。
echo "hello world":在函数体中,这是第一条输出语句。无论是否传入参数,当函数DemoFunc被调用时,都会首先执行这行代码,通过echo命令输出字符串"hello world"。
echo "my name is $1,and is $2 years old":这是函数体中的第二条输出语句。在 Shell 函数中,$1用于指代传入函数的第一个参数,$2用于指代传入函数的第二个参数。所以当函数DemoFunc被调用并传入参数时,这行代码会根据传入的参数值输出相应信息,格式为 “我的名字是传入的第一个参数值,并且是传入的第二个参数年龄”。
函数调用部分:
DemoFunc xiaoyu 27:这是对前面定义的DemoFunc函数进行调用的语句,同时传入了两个参数,第一个参数是xiaoyu,第二个参数是27。当执行到这一行时,程序会跳转到DemoFunc函数的定义处,按照函数体内部的代码逻辑依次执行。首先会输出"hello world",然后由于传入了参数xiaoyu作为第一个参数,27作为第二个参数,所以接着会输出my name is xiaoyu,and is 27 years old。
shell编程(完结)
重定向操作
基本概念
在 Shell 中,重定向是一种改变命令输入输出方向的机制。默认情况下,命令从标准输入(通常是键盘)获取输入,将输出发送到标准输出(通常是显示器),并且将错误信息发送到标准错误输出(也是显示器)。重定向可以让用户改变这些默认行为,比如将输出保存到文件、从文件读取输入或者将错误信息单独处理等。
标准输出重定向
>(覆盖输出)
例如,echo "Hello" > output.txt。这行命令会将echo命令输出的Hello字符串重定向到output.txt文件中。如果output.txt文件不存在,会创建一个新文件;如果文件已经存在,会覆盖文件中原有的内容。
>>(追加输出)
例如,echo "World" >> output.txt。当执行这个命令时,echo输出的World字符串会被追加到output.txt文件的末尾。如果文件不存在,同样会创建一个新文件。
标准输入重定向
<(从文件读取输入)
假设有xt个文件input.txt,内容为1 2 3,有一个命令read a b c < input.txt,这里read命令会从input.txt文件中读取内容,将文件中的三个数字分别赋值给变量a、b和c。
标准错误输出重定向
2>(覆盖错误输出)
例如,运行一个可能会出错的命令ls non - existent - directory 2> error.txt。因为non - existent - directory这个目录不存在,所以ls命令会产生错误信息。这些错误信息会被重定向到error.txt文件中,而不是在终端显示。如果error.txt文件不存在,会创建一个新文件;如果存在,则会覆盖文件中原有的内容。
2>>(追加错误输出)
类似于标准输出的追加重定向,2>>会将错误信息追加到指定文件的末尾。例如,command - that - may - error 2>> error.log,如果命令多次执行产生错误,每次的错误信息都会被追加到error.log文件中。
组合重定向
可以同时对标准输出和标准错误输出进行重定向。例如,command > output.txt 2> error.txt,这个命令会将命令command的正常输出保存到output.txt文件,将错误输出保存到error.txt文件。
还有一种更简洁的方式,&>或>&,可以将标准输出和标准错误输出同时重定向到同一个地方。例如,command &> combined_output.txt会将命令command的所有输出(包括正常输出和错误输出)都保存到combined_output.txt文件中。
不同的脚本互相调用
在 Shell 中调用另一个脚本的基本方法
点号(.)或source命令
语法:. script_name.sh或者source script_name.sh。
例如,有两个脚本script1.sh和script2.sh。如果想在script1.sh中调用script2.sh,可以在script1.sh中使用. script2.sh或者source script2.sh。这种方式会在当前 Shell 环境中执行script2.sh,这意味着script2.sh中定义的变量、函数等会被加载到当前 Shell 环境中,就好像这些内容是在script1.sh中直接定义的一样。
bash或sh命令(创建子进程执行)
语法:bash script_name.sh或者sh script_name.sh。
例如,在一个脚本main.sh中,可以通过bash sub_script.sh来调用sub_script.sh。这种方式会开启一个新的子进程来执行sub_script.sh,sub_script.sh中的变量和函数等在其执行完毕后通常不会影响主脚本main.sh的环境,因为它们是在不同的进程中运行的。不过,可以通过一些手段(如环境变量、文件等)来传递数据。
传递参数给被调用的脚本
当调用另一个脚本时,可以传递参数给它。在被调用的脚本中,参数的获取方式和在普通脚本中一样,通过$1、$2等变量来获取。
例如,在脚本caller.sh中有如下内容:
#!/bin/bash
./callee.sh arg1 arg2
在脚本callee.sh中可以通过$1获取arg1,通过$2获取arg2,就像这样:
#!/bin/bash
echo "The first argument received is: $1"
echo "The second argument received is: $2"
被调用脚本返回值的获取
在 Shell 中,脚本可以通过return命令返回一个整数值(通常用于表示执行状态,0 表示成功,非 0 表示失败)。在调用脚本中,可以使用$?变量来获取被调用脚本的返回值。
例如,在被调用脚本return_script.sh中有:
#!/bin/bash
# 模拟一个成功的操作并返回0
return 0
在调用脚本caller.sh中可以这样获取返回值:
#!/bin/bash
./return_script.shreturn_value=$?echo "The return value of the called script is: $return_value"
脚本调用中的变量作用域和共享
如前面提到的,当使用.或source调用脚本时,变量是共享的,被调用脚本中的变量会影响调用脚本的环境。而使用bash或sh调用脚本时,变量默认是隔离的。
例如,使用.或source:
脚本script1.sh:
#!/bin/bashvar1=10
. script2.shecho "After calling script2.sh, var1 in script1.sh is: $var1"
脚本script2.sh:
#!/bin/bash
var1=20
运行script1.sh后,会发现输出的var1的值是 20,因为script2.sh中的变量定义影响了script1.sh的环境。
而如果使用bash调用:
脚本script1.sh:
#!/bin/bash
var1=10
bash script2.sh
echo "After calling script2.sh, var1 in script1.sh is: $var1"
脚本script2.sh(和上面一样):
#!/bin/bash
var1=20
文件描述符
0通常代表标准输入
1代表标准输出
2代表标准错误输出
基本概念
文件描述符是一个非负整数,用于在操作系统中标识一个打开的文件或者其他输入 / 输出资源。它是进程用来访问文件的抽象表示,在 Unix 和类 Unix 系统(包括 Linux)中广泛使用。可以把文件描述符想象成是进程和文件之间的一个 “通信桥梁”,进程通过这个数字来对文件进行各种操作,如读、写、关闭等。
标准输入(0)
它是进程用于读取输入的默认文件描述符。通常,这个输入来自键盘。例如,当运行一个命令,等待用户输入一些信息时,程序就是从标准输入(文件描述符为0)获取数据。在 Shell 脚本中,read命令就是从标准输入读取用户输入的内容,其底层就是通过文件描述符0来实现的。
标准输出(1)
这是进程用于输出信息的默认文件描述符。通常,输出会显示在终端屏幕上。例如,echo命令输出的内容就是通过标准输出(文件描述符1)发送到终端的。当使用重定向操作符>将输出重定向到一个文件时,实际上就是改变了文件描述符1的输出目标。
标准错误输出(2)
用于输出错误信息的文件描述符。和标准输出类似,但它专门用于显示错误消息,这样可以将正常输出和错误输出区分开来。例如,当运行一个命令,尝试访问一个不存在的文件时,产生的错误信息(如 “文件不存在”)就是通过标准错误输出(文件描述符2)发送的。可以使用2>或2>>来单独重定向标准错误输出。
自定义文件描述符(大于2)
除了标准的0、1、2这三个文件描述符外,进程可以打开更多的文件,并为它们分配自定义的文件描述符。这些自定义的文件描述符可以用于同时操作多个文件。例如,在一个程序中,可能同时打开了一个配置文件、一个数据文件和一个日志文件,分别为它们分配不同的文件描述符(如3、4、5等),然后通过这些文件描述符对不同的文件进行读写操作。在 Shell 中,也可以通过一些高级的重定向操作或者管道操作来利用这些自定义文件描述符,不过这种情况相对复杂一些。
实例
调用实例1
1 . vim 1.sh:
echo "hello word"
2. vim 2.sh
bash 1.sh
调用实例2
1. vim 1.sh
name="xiaoyu"
age=23
2. vim 2.sh
source 1.sh
echo "my name is $name and i am $age years old"
source:
命令的作用是在当前 Shell 环境下读取并执行 1.sh
这个脚本文件的内容。
重定向实例1输出重定向
vim 1.txt
ls > 1.txt
cat 1.txt
ls > 1.txt
操作说明:
ls 命令用于列出当前目录下的文件和目录信息。> 是标准输出重定向符号,它会将 ls 命令原本输出到终端的内容(即当前目录下的文件和目录列表)重定向到指定的文件 1.txt 中。如果 1.txt 不存在,会创建一个新文件;如果已经存在,会覆盖其原有内容。
cat 1.txt
操作说明:
cat 命令用于查看文件内容并输出到终端。这里是查看刚刚通过 ls > 1.txt 操作生成(或覆盖更新)的 1.txt 文件内容。
who > 1.txt
cat 1.txt
who > 1.txt
操作说明:
who 命令用于显示当前登录到系统的用户信息,包括用户名、终端设备、登录时间等。同样使用 > 进行标准输出重定向,将 who 命令输出的用户信息重定向到 1.txt 文件中,会覆盖掉之前 ls 操作在 1.txt 中存储的内容
追加>>
ls >>1.txt
cat 1.txt
ls >/dev/null 一般使用ls会有回显,但是重定向到这里,相当于垃圾箱,无回显
重定向实例2输入重定向1
1.创建目录到txt vim dir.txt
home/user/Documents
home/user/Picturas
home/user/Music
2. ls 结合输入重定向查看这些目录下的文件
ls -l < dir.txt
ls -l 是 ls 命令的一种常见用法,它会以长格式列出文件或目录的详细信息,包括文件类型、权限、所有者、所属组、文件大小、修改时间等。
< 是标准输入重定向符号。在这里,它使得 ls -l 命令不从默认的标准输入(通常是键盘)获取输入,而是从 dir.txt 文件中读取内容作为输入。也就是说,ls -l 会把 dir.txt 文件中的每一行内容都当作是一个文件名或目录名,然后尝试列出它们的详细信息。
在这个输出中:
drwxr-xr-x 表示文件类型(d 表示目录)和权限信息,这里表示所有者有读、写、执行权限,同组用户和其他用户有读和执行权限。
2 表示该目录下的硬链接数。
user 分别表示所有者和所属组都是 user。
4096 表示该目录所占的磁盘空间大小(以字节为单位,这里是一个常见的目录初始大小值)。
Dec 1 12:00 表示该目录的最后修改时间。
文件描述输出
如果输出正确,则输出到8.txt
ls > 8.txt 2> 9.txt
cat 8.txt
ls 命令用于列出当前目录下的文件和目录信息。
> 是标准输出重定向符号,ls > 8.txt 表示将 ls 命令的正常输出(即列出的文件和目录列表)重定向到 8.txt 文件中。如果 8.txt 不存在,会创建一个新文件;如果已经存在,会覆盖其原有内容。
2> 是标准错误输出重定向符号,ls > 8.txt 2> 9.txt 整体表示将 ls 命令的正常输出重定向到 8.txt 文件,同时将 ls 命令可能产生的错误输出(比如当试图列出一个不存在的目录或文件权限不足无法列出时产生的错误信息)重定向到 9.txt 文件。如果 9.txt 不存在,会创建一个新文件;如果存在,会覆盖其原有内容。
cat 命令用于查看文件内容并输出到终端。这里是查看刚刚通过 ls > 8.txt 操作生成(或覆盖更新)的 8.txt 文件内容。
如果输出错误则输出到9.txt
ABC > 8.txt 2> 9.txt
cat 9.txt
这里执行了一个重定向操作,但 “ABC” 不是一个有效的系统命令。
> 用于标准输出重定向,所以原本 “ABC” 命令的报错输出会被尝试重定向到 9.txt 文件中。如果 8.txt 不存在,会创建一个新文件;如果存在,会覆盖原有内容。
2> 用于标准错误输出重定向,这意味着 “ABC” 命令可能产生的错误输出会被重定向到 9.txt 文件。同样,如果 9.txt 不存在,会创建一个新文件;如果存在,会覆盖原有内容。
由于 “ABC”不是有效命令,执行这行操作通常会导致产生错误信息(比如在 bash shell 中可能会提示 “未找到命令” 之类的错误),而这些错误信息会按照重定向规则被发送到 9.txt 文件。