一文了解shell语法(二)

前言:咱们接着上面的文章来继续介绍shell脚本语法,整体来看语法量还是挺大的。。。


9,测试运算

(1)test 和 [

  • test 是一种早期的命令形式,等价于 [,它们在功能上几乎完全相同。可以理解为 [ 就是test命令的别名;
  • [ 是现在常用的一种用于进行条件测试的命令,它的语句结构比test更加简洁和容易阅读
  • [ ] 的左右方括号 [ 和 ] 必须用空格与表达式隔开。
  • [ 执行测试操作,而 ] 仅作为语法符号来表示条件表达式的结束位置。
返回值:
  • 返回 0 表示条件为真(True)
  • 返回 1 表示条件为假(False)

(2)test指令的应用分类

  • 文件相关测试:用于检查文件的属性、类型或权限

  • 字符串相关测试:用于比较字符串是否相等、非空等

  • 整数比较:用于比较两个整数

  • 逻辑运算:可以组合多个条件进行测试

(3)举例

# 文件存在性检查
if [ -e /etc/passwd ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

# 字符串非空检查
if [ -e /etc/passwd ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

# 整数比较
if [ -n "$USER" ]; then
    echo "当前用户是 $USER"
else
    echo "用户未定义"
fi

# 逻辑运算
if [ -d /home -a -w /home/user ]; then
    echo "/home 存在并且用户目录可写"
else
    echo "/home 不存在或用户目录不可写"
fi

10 ,语句结构

10.1 分支语句

  • if 分支语句
############
#单分支
if 条件; then
    Command;
fi
##############
#双分支
if 条件; then
    Command;
else
    Command;
fi
##############
#多分支
if 条件;  then
    Command;
elif 条件; then
    Command;
else
    Command;
fi
##############
#举例
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') 打包成功:person_data-${Date}.tar.gz" | tee -a  ${LogFile}
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') 打包失败,请检查密码、网络是否正常" | tee -a   ${LogFile}
    exit 1
fi
  • case 分支语句
注意:下面的模式为通配符,规则如下
1, * :匹配任意长度的任意字符
示例:*.txt 匹配任何以 .txt 结尾的字符串,如 file.txt 和 my_data.txt。
2,? :匹配任意单个字符
示例:file?.txt 匹配 file1.txt 或 fileA.txt,但不匹配 file12.txt。
3,[...] :匹配方括号内的任意一个字符
示例:file[abc].txt 匹配 filea.txt、fileb.txt、filec.txt。
也可以使用字符范围:file[a-z].txt 匹配 filea.txt 到 filez.txt。
4,| :多个模式用管道分隔,表示“或”
示例:*.jpg | *.png 匹配以 .jpg 或 .png 结尾的字符串。
5,转义字符 \:用于匹配特殊字符
示例:\*.txt 匹配文件名为 *.txt 的文件,而不是匹配所有以 .txt 结尾的文件。
6,) :结束当前模式
每个分支的模式必须以 ) 结束。
case 变量 in
    模式1)
        # 当变量匹配模式1时执行的代码
        ;;
    模式2)
        # 当变量匹配模式2时执行的代码
        ;;
    *)
        # 以上模式都不匹配时执行的代码
        ;;
esac

 #####################################
 #举例
 #!/bin/bash

read -p "请输入一个字母: " char

case $char in
    [a-z])
        echo "你输入的是小写字母"
        ;;
    [A-Z])
        echo "你输入的是大写字母"
        ;;
    [0-9])
        echo "你输入的是数字"
        ;;
    *)
        echo "输入的不是字母或数字"
        ;;
esac

10.2 循环语句

  • for 循环语句
# 普通风格
for 变量名 in 参数列表
do
    command;
done

# c语言风格
for ((i=0; i<=5; i++))
do
	command
done


#######################################
#打印99乘法表
#!/bin/bash
for (( i=1; i<=9; i++ )) ;do
    for (( j=1; j<=i; j++ ));do
        echo -ne "$i * $j = $(expr $i \* $j) \t"
        if [ $i -eq $j ];then
            echo
        fi
    done
done
  •  while 循环语句
while 条件; do
    command;
done

#######################
#循环语句举例
#!/bin/bash

counter=1
while [ $counter -le 5 ]; do
    echo "计数器:$counter"
    ((counter++))  # 计数器加 1
done

11,shell中的括号的作用的总结

11.1 大括号

  • 变量分隔
使用 $  引用变量时,如果变量名后面紧跟其他的字符串,这个时候Shell就没法正确识别正确的变量名,这个时候使用 ${} 就可以将变量名和后续的字符串进行分隔
ubuntu@yyy:~/test$ name=TOM

ubuntu@yyy:~/test$ echo ${name}
TOM

# 无输出
ubuntu@yyy:~/test$ echo $namefdas
  • 命令块
如果有多个语句或者命令需要作为一个整体进行执行,可以使用大括号将这些命令都括起来
格式 { cmd1; cmd2; }
特点
1、大括号两边必须有空格
2、如果写在一行每个命令都需要以分号结尾
3、整个的退出状态码是最后一个命令的退出状态码
  • 字符串组合
echo {a,b,c} 会输出 a b c
  • 生成有序序列
格式: { 开始..结束 }
echo {1..5} 会输出 1 2 3 4 5。

11.2  小括号

  • 命令组合
将多个命令或语句通过小括号括起来后,会将这些命令组合作为一个整体来进行执行,但是和大括号有以下不同
格式: ( cd /some/dir && ls )
注意
1、通过在当前进程下开启一个子进程来执行这个命令组合,子 Shell 中的变量和更改不会影响当前 Shell,但是当前进程的相关内容是被子shell继承了的。
2、整个的退出状态码是最后一个命令的退出状态码
  • 启用子shell
使用小括号括起来的命令会在当前进程开启一个子shell来执行,子进程的相关环境变量信息会继承父进程的,但是子进程的环境变量信息父进程看不到
格式: ( command )
  • 进程替换
进程替换会将一个命令的输出或输入通过临时文件或命名管道(FIFO)替换,允许命令之间高效协作
1,输入替换
语法: command <(another_command)
作用:将一个命令的输出作为文件名传递给另一个命令,模拟为输入文件
解释:
  • another_command 的输出被视为一个临时文件或命名管道的内容。
  • command 可以从这个“文件”中读取数据
举例:
# 使用 diff 比较两个命令的输出
diff <(ls dir1) <(ls dir2)
# 使用 grep 过滤动态生成的文本
grep "pattern" <(echo -e "line1\npattern\nline3")
2,输出替换
语法: command >(another_command)
作用:将另一个命令的输入作为文件名传递,模拟为输出文件
工作原理
  • command 的输出被重定向到一个临时文件或命名管道。
  • another_command 从这个文件或管道中读取数据
# 将ls的输出传递给sort, 最终结果是对 ls 的输出进行排序
ls > >(sort)

11.3 中括号

  • 条件测试
作为 test 命令的简写。用于测试文件、字符串和数字等条件。返回的是命令的退出状态码
  • 通配符
用于匹配特定的字符集或字符范围
  • 单字符匹配
[abc]:匹配任意一个字符,如 a、b 或 c
  • 范围匹配
[a-z]:匹配小写字母 a 到 z 中的任意一个字符。
[0-9]:匹配数字 0 到 9 中的任意一个字符。
  • 否定匹配
[^abc]:匹配除了 a、b、c 以外的任何字符。^ 放在 [] 中的开头表示取反。

12,Shell 中的引号

12.1 双引号

使用双引号括起来的字符串,变量值中的命令和变量会替换为输出值,其他字符串原样输出;

# 变量会替换为具体的变量值
ubuntu@yyy:~$ name=TOM
ubuntu@yyy:~$ test="name is ${name}"

ubuntu@yyy:~$ echo $test
name is TOM

12.2 单引号

使用单引号括起来的字符串,变量值中的内容会完全保留字面值,所有的字符都不会被解释或扩展 ;

ubuntu@yyy:~/test$ test='name is ${name}'

ubuntu@yyy:~/test$ echo $test
name is ${name}

11.3 反引号

反引号的作用等同于 $(),会将括起来的内容当作命令执行,并将其输出作为一个字符串返回;

ubuntu@yyy:~/test$ filename=$(ls)

ubuntu@yyy:~/test$ echo $filename
file1 file2 file3 file4 file5 file6

13,管道符使用

Linux 相关操作系统中,使用 | 符号来表示一个匿名管道符,从而实现将前一个语句或命令的标准输出(stdout)作为输入(stdin)传递给下一个语句或命令

语法:语句1 | 语句2

13.1 单个命令的使用场景

ps aux | grep "apache"

13.2 复杂命令组合(语句)的场景

# 将 for语句本来应该输出到屏幕的内容作为sort命令的输出,然后将sort命令本该输出到屏幕的内容作为while语句的输入
for key_name in "${!key_arry[@]}"; do
  echo "${key_arry[$key_name]} $key_name"
done | sort -nr | while read size key; do
  echo "$size   $key"
done

13.3 不能直接使用管道符处理方法

存在某些命令不能直接使用管道符来处理从上一个命令传递的数据,例如:rm、mv、cp、kaill等。可以通过 xargs 来实现管道操作。xargs 可以将管道传递的输入转换为命令的参数,使得这些命令能够处理数据流

格式:语句1 | xargs 命令或语句

xargs 会自动将多行输入转换为单行参数传递给命令


 14, 使用 heredoc

heredoc 是一种特殊的重定向方式,允许一次性从标准输入读取多行内容给一个命令。有两种语法格式

14.1 定界符无引号

语法:

# <<DELIMITER  是固定搭配  
# DELIMITER-----定界符
command <<DELIMITER
line_1
line_2
...
DELIMITER

举例:

################################
#  将多行文本直接传递给  cat 命令进行输出
################################
#!/bin/bash
cat <<EOF
这是一个多行字符串。
Heredoc 示例演示。
EOF
# 输出结果
#=======================
 这是一个多行字符串。
Heredoc 示例演示。
#=======================

################################
# 将 Heredoc 的内容保存到文件中
################################
#!/bin/bash
cat <<EOF > output.txt
这是保存到文件的内容。
包含多行文本数据。
EOF
# 输出结果
#=======================
#执行后会创建一个output.txt 文件,内容如下:
 这是一个多行字符串。
Heredoc 示例演示。
#=======================

################################
# 默认情况下,Heredoc 中的变量会被替换
################################
#!/bin/bash
name="小明"
cat <<EOF
你好,$name!
欢迎来到 Shell 脚本学习。
EOF
# 输出结果
#=======================
你好,小明!
欢迎来到 Shell 脚本学习。
#=======================

14.2 定界符有引号

定界符加上单引号或双引号都可以;内容中的变量、通配符、转义字符都不会被Shell解释,而是将内容视为纯文本,不会进行任何拓展

语法:

command <<'DELIMITER'
line_1
line_2
...
DELIMITER

举例:

################################
# 使用单引号或 <<'DELIMITER' 来禁止变量替换
################################
#!/bin/bash
name="小明"
cat <<'EOF'
你好,$name!
这是不替换变量的示例。
EOF

15,重定向

Linux 中的三个文件描述符 0 1 2 固定和标准输入(stdin)、标准输出(stdout)和标准错误(stderr)进行绑定。当某个进程启动时,操作系统会自动将它的标准输入(stdin)、标准输出(stdout)和标准错误(stderr)绑定到对应的终端设备上

  • 标准输入:文件描述符:0 文件路径:/dev/stdin 符号表示:< 或 0
  • 标准输出:文件描述符:1 文件路径:/dev/stdout 符号表示:> 或 >1
  • 标准输入:文件描述符:2 文件路径:/dev/stderr 符号表示: 2>
ubuntu@ubuntu:~$ ls  -l /dev/std*
lrwxrwxrwx 1 root root 15 10月  8 15:31 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 10月  8 15:31 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 10月  8 15:31 /dev/stdout -> /proc/self/fd/1

15.1 输入重定向

wc -l < CheckEncryption.log

15.2 输出重定向

# 追加内容,会覆盖以前内容
# 如果文件不存在,会先创建对应的文件,如果文件存在且存在内容,会将以前的内容全部清空
echo "12345" > 1.txt

15.3 错误重定向

# 同时将标准输出和标准错误都输出到不同文件中
output 1> file1  2> file2 

# 将标准输出和标准错误都输出到同一文件中
output 1> file1  2> file1

# &符号的作用是表示1是描述符不是文件名1
output 1> file1 2>&1

# 简写形式 &> 或 >& 等价
outpu &> file1

# 错误形式。因为此时标准输出也不知道自己应该重定向到哪个文件,故会将内容输出到屏幕
output  2>&1 > file.txt


16,环境变量管理

15.1 PATH 变量简介

  • PATH变量定义了可执行文件的路径,当以相对路径执行某个命令时,会通过PATH变量定义的路径来进行查找;
  • 通过PATH定义的路径进行查找时,不会递归查找,只会查找所指定路径下是否存在该可执行文件
  • Linux中的PATH变量是一个全局变量,对所有用户和进程可见,所以系统启动时需要首先加载PATH变量,这样在才能在当前或后续的子进程中使用PATH变量

16.2 查看PATH变量值

ubuntu@ubuntu:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/xtrabackup-8.0.35-31/bin

16.3 临时修改PATH变量

# 这条命令的作用是将 /directory 添加到当前终端的 PATH 环境变量中
export PATH=$PATH:/directory
  • 在前面添加路径
# 解释:将 /my/custom/path 添加到 PATH 变量的前面。 # 结果:系统会优先搜索 /my/custom/path 目录下的可执行文件 export PATH=/my/custom/path:$PATH
  • 在后面添加路径
# 解释:将 /my/custom/path 添加到 PATH 变量的后面。
# 结果:系统会先搜索原有的路径,再搜索 /my/custom/path 目录下的可执行文件
export PATH=$PATH:/my/custom/path

16.4 永久修改PATH变量

方式一:通过在当前Shell的配置文件中进行定义,后续启动Shell进程的时候加载配置文件的同时,也会使得定义的PATH变量生效;

用户级配置文件:仅在当前用户下生效,对其他用户无影响。例如:PATH 修改添加到 ~/.bashrc、~/.bash_profile

系统级配置文件:所有用户在启动 Shell 进程时都会加载这些配置文件。例如/etc/profile 或 /etc/profile.d/

方式二:通过在/etc/environment 这个配置文件中定义PATH变量,系统初始化时会读取该文件中的内容,使其对所有用户生效

16.5 不受PATH影响的命令

# 例如sudo、crontab等命令具有自己的PATH变量,默认情况下不会继承用户的 PATH

/etc/crontab
crontab:
可以通过修改配置文件中的PATH路径来自定义crontab的PATH变量

/etc/sudoers
sudo
可以通过修改 Defaults secure_path 来修改sudo的PATH变量,或者注释掉该选项,就会默认使用当前用户的PATH


[Service]
Environment="PATH=/custom/path:/usr/bin:/bin"
systemd也拥有自己的PATH变量,不会继承用户的 PATH;可以通过在service文件中添加Environment 指令来指定PATH路径

16.6 env 命令

env是用于查看、临时设置和管理环境变量。它可以显示当前会话中所有可用的环境变量,并且允许在临时环境中设置变量后再运行命令

# 查看当前所有的环境变量
env
# 临时设置一个或多个环境变量,并运行指定的命令
env  variable=value  command

16.7 其他变量

$$ :获取当前进程的pid; $PPID :获取当前进程的父进程 pid

17,子Shell 和 子进程

17.1 子Shell

在Shell 中通过将某些命令在小括号中执行,就会启动一个子shell来执行这个命令。子 Shell 在启动时会完全继承当前Shell的相关环境信息,例如局部变量、环境变量等

ubuntu@yyy:~$ name=tom 
ubuntu@yyy:~$ (echo $name) tom

17.2 子进程

#使用bash这种解释器时,可以通过bash -c 来创建一个子进程,此时子进程只继承父进程的 环境变量,而不继承局部变量
##########################################
ubuntu@ubuntu:~$ name=tom
ubuntu@ubuntu:~$ export sex=m

# 不会继承定义的局部变量
ubuntu@ubuntu:~$ bash -c 'echo $name'

ubuntu@ubuntu:~$ bash -c 'echo $sex'
m

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是星凡呢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值