【学习笔记】一文打通Docker!(项目部署orCTF)

news2024/12/22 23:27:06

Docker

What is Docker?

利用Docker 可以快速安装应用,Docker会自动搜索并下载应用镜像(image)。镜像不仅包含应用本身,还包含应用运行所需要的环境,配置,系统函数库。

注意这个系统函数库,相当于在不同的操作版本运行该应用都是没问题的,因为Docker自身打包了系统函数库,可以实现跨系统运行,也利于在一个服务器上部署多台应用

容器 : Docker在运行镜像时会创建一个隔离环境,称为容器

镜像仓库 : 存储和管理镜像的平台,Docker Hub 用户自身可以上传自己构建的应用

image-20240124095603481

Docker in VScode

注册dockerhub账号

用户名:happysuperman

在kali中可以进行登录

在root权限下输入 docker login

开启ssh服务

该服务所在位置

/etc/init.d/ssh status

设置为开机自启动

update-rc.d ssh enable

建立win系统中的vscode与kali中的连接

为提高本地操作的流畅性 选择进行公私钥连接

首先在win本地生成公钥

C:\Users\xxx>ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key 

passphrase私钥密码 因为在本地操作 直接设置为空即可

生成ssh.txt 为私钥 ssh.pub为公钥

下面将公钥进行上传到kali中

image-20230803024954066

修改权限:

sudo chmod 600 authorized_keys
sudo chmod 700 ~/.ssh

编辑ssh配置文件:

sudo vim /etc/ssh/sshd_config

image-20230803025242640

RSAAuthentication yes
PubkeyAuthentication yes

首先i进入insert模式 然后esc退出
:wq 保存并退出

最后重启ssh服务

sudo service ssh restart

配置win中的vscode

在vs中的ssh中配置

# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host xxx.xxx.xxx.xxx(ip)
    HostName xxx.xxx.xxx.xxx
    User kali
    IdentityFile C:\Users\xxx\.ssh\sshdocker

到此在vs中已经可以连接kali了

在左下角点开 connect to host即可

image-20230803031049342

Get The Docker Extension

刚进入拓展插件还是不行 存在权限问题 要把当前用户添加到组

image-20230803031532281

修改完后 重启docker服务

reboot重启 重新在vs登录


Docker in Package

在服务器安装Docker

本安装教程参考Docker官方文档,地址如下:

https://docs.docker.com/engine/install/centos/

1.卸载旧版

首先如果系统中已经存在旧的Docker,则先卸载:

yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
2.配置Docker的yum库

首先要安装一个yum工具

yum install -y yum-utils

安装成功后,执行命令,配置Docker的yum源:

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
3.安装Docker

最后,执行命令,安装Docker

yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
4.启动和校验
# 启动Docker
systemctl start docker

# 停止Docker
systemctl stop docker

# 重启
systemctl restart docker

# 设置开机自启
systemctl enable docker

# 执行docker ps命令,如果不报错,说明安装启动成功
docker ps
5.配置镜像加速

这里以阿里云镜像加速为例。

5.1.注册阿里云账号

首先访问阿里云网站:

https://www.aliyun.com/

注册一个账号。

5.2.开通镜像服务

在首页的产品中,找到阿里云的容器镜像服务

点击后进入控制台:

首次可能需要选择立刻开通,然后进入控制台。

5.3.配置镜像加速

找到镜像工具下的镜像加速器:

页面向下滚动,即可找到配置的文档说明:

具体命令如下:

# 创建目录
mkdir -p /etc/docker

# 复制内容,注意把其中的镜像加速地址改成你自己的
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF

# 重新加载配置
systemctl daemon-reload

# 重启Docker
systemctl restart docker

image-20240124020052395

到此安装成功!配置成功!

部署

docker创建命令:

官方文档:http://docs.docker.com/

image-20240124104355347

命令解释:


针对镜像:

docker build : 将自己本地编写的docker file文件创建为本地镜像

docker push + docker pull : 将自己本地的镜像 上传到镜像仓库中 便于其他人使用docker pull访问拉取

docker save + docker load -i xxx.tar : 利用本地拷贝的方式对镜像进行分享 首先对本地镜像进行打包生成压缩文件 然后拷贝到待分享的主机 对压缩包使用docker load加载即可 其中-i 全称input

docker images : 查看本地镜像

docker rmi : 全称 docker remove image 删除本地镜像


针对容器:

docker run : 创建并运行容器命令 在下面细致讲解

docker start + docker stop : 区分docker run,容器创建好之后一直存在 使用start和stop只是开关的作用(docker run相当于你买了个手机 start stop则是开关键)

docker ps : 查看正在启动运行的容器 相当于看看你有多少个开机的手机

docker ps -a : 添加-a参数之后 查看所有容器 相当于看看你有多少个手机 不管是否开机

docker rm : 全称 remove 删除容器 相当于把你刚刚的手机扔了

docker exec : 进入到容器中 如一个Nginx容器 里面相当于存在一个独立的操作系统

docker logs : 查看容器的运行状态 被访问情况等 加参数-f 表示跟随 不退出 一直检测


针对以上命令实践:

image-20240124110100075

image-20240124145309542

官网:hub.docker.com

注意一下网络,我们在配置的时候使用了阿里云的镜像加速 所以如果连接到外网 然后在拉取非常慢 相当于在国外访问我们国内的东西

---镜像
#拉取
docker pull nginx
#查看本地镜像列表
docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    605c77e624dd   2 years ago   141MB
#打包压缩本地镜像  将镜像名 输出到nginx.tar文件中
docker save -o nginx.tar nginx

#加载压缩镜像
docker load -i nginx.tar


---容器
#默认端口为80 创建并运行容器
docker run -d --name nginx -p 80:80 nginx
497cae5920378497a44673a7d66f2c1581364f8c58b7196c94cc9580cef2cd09
#查看容器
docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                               NAMES
497cae592037   nginx     "/docker-entrypoint.…"   26 seconds ago   Up 25 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   nginx
image-20240124153402994

直接访问

#进入容器
docker exec -it nginx bash
#退出
exit
#删除容器
docker rm nginx
docker rm nginx -f   #强制删除

简化命令

预定义命令别名

编辑 vi ~/.bashsrc

添加 alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'

生效 source ~/.bashsrc

docker run运行命令:
docker run -d --name mysql -p 3306:3306 -e TZ=Asia/Shanghai -e MYSQL_ROOT_PASSWORD=123 mysql

命令解释:

docker run : 创建并运行容器

-d : 容器在后台运行

--name : 给自己的容器起名字 必须唯一

-p : 端口映射,从宿主机的端口(前)映射到容器的端口(后), 其中容器端口固定不变 如果部署多个相同容器 需要调整宿主机的端口进行区分

image-20240124100814727

-e KEY=VALUE : 设置容器运行的环境变量 可以在docker hub中查看有哪些KEY

mysql : 指定运行镜像的名字 后面可以加版本号 如mysql:5.4 如果不加 默认latest

docker 数据卷挂载 部署静态资源

原理介绍:

我们创建一个Nginx, 这是一个web高性能的HTTP和反向代理Web服务器,其作用可以实现将我们的项目(静态资源)挂载到服务器上面,实现外部访问。

但是在docker容器中,我们进入到对应的目录·/usr/share/nginx/html,因为docker容器只包含一些必备的命令,所以如果想编辑文件的话可能命令无法执行,但是在宿主中命令是齐全的,同时各类编辑器效果更便捷,所以我们将docker容器中的数据卷挂载到宿主机中,实现该目录下的内容双向映射,即在宿主机编辑或者在docker容器中编辑两边都会同时更新

image-20240124174852990

命令执行过程:

按需image-20240124180154982

想把数据卷挂载 一定要在docker run启动容器的时候加参数 如果创建之后就无法实现挂载了 无需额外创建数据卷 因为如果不存在自动创建

docker run -d --name nginx -p 80:80 -v <数据卷名称>html:<容器目录在docker hub可以找到>/usr/share/nginx/html nginx

其他命令:

#创建数据卷
[]docker volume create
84d95cfac67b448c74566823acd1769603325e57fc639a07282bed1ea82758c3


#查看所有数据卷
[]docker volume ls
DRIVER    VOLUME NAME
local     84d95cfac67b448c74566823acd1769603325e57fc639a07282bed1ea82758c3
local     html

#删除指定数据卷
docker volume rm

#清除数据卷 未使用的
docker volume prune

#查看某个数据卷的详情
[]docker volume inspect html
[
    {
        "CreatedAt": "2024-01-24T17:22:03+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/html/_data",
        "Name": "html",
        "Options": null,
        "Scope": "local"
    }
]
[]cd /var/lib/docker/volumes/html/_data
[]ls
50x.html  index.html

#查看容器详情 查看容器是否有挂载 看Mounts
docker inspect <容器名>
docker 目录挂载

相当于给数据卷指定一个本地的目录进行挂载

image-20240124181515199

在上面这个案例中 注意MySQL一般会自动创建一个匿名卷

所以在目录的挂载过程中 同样在容器创建的时候添加命令

docker run -d \
	--name mysql \
	-p 3306:3306 \
	-e TZ=Asia/Shanghai \
	-e MYSQL_ROOT_PASSWORD=123 \
	-v /root/mysql/data:/var/lib/mysql \
	-v /root/mysql/init:/docker-entrypoint-initdb.d \
	-v /root/mysql/conf:/etc/mysql/conf.d \
	mysql

Dockerfile

基本概念:

自定义镜像:目的在于给自己的java应用制作

镜像就是包含了应用程序,程序运行过程的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。

解释其意义:

  • 部署一个Java应用的步骤:
    1. 安装一个Linux服务器
    2. 安装JRE并配置环境变量
    3. 拷贝Jar包
    4. 运行Jar包
  • 构建一个Java镜像的步骤:
    1. 准备一个Linux运行环境
    2. 安装JRE并配置环境变量
    3. 拷贝Jar包
    4. 编写运行脚本
image-20240124223615539

在编写镜像的时候是分层的,底层的一些逻辑其实是可以直接使用的,避免重复编写

image-20240124223504193

可以在上面这个例子中发现 第一个显示Already exits 就是证明之前已经拉取过

编写指令:

image-20240124223706047

示例:

image-20240124223745814

构建镜像:

docker build -t myImage:1.0 .
  • -t : 给镜像起名,格式是repository:tag 不指定版本默认为latest
  • . : Dockerfile的相对路径

结构:

image-20240124230502108

注意上面Dockerfile的名字 必须一字不差

同时在部署的时候 Dockerfile中有from的基础镜像 这个需要提前拉取

Network

image-20240124231509953

注意/16 表示前16位不能动,也就是172.17不能动

但是在上面根据ip访问的话 因为内部的ip地址是随机生成的,所有当重启容器的时候可能会造成ip地址冲突,变化,被别的容器占用,导致MySQL服务可能出问题 所以这种连接方式不推荐

方法二:自定义网络

类比数据卷命令

image-20240124232147947

过程:

  • 首先创建一个网络

查看一下网络的初始情况

image-20240124233156202

docker network create happySu

image-20240124233217481

创建成功

  • 然后可以把我们启动的容器添加到我们创建的自定义网桥中

两个方法:

  1. 容器已经启动了

    docker network connect <network> <container>
    
  2. 容器未启动

    docker run -d --name <container> -p 8080:8080 --network <network> <image>
    

查看容器的网络状况

docker inspect <container>

容器互联:

进入到一个我们网桥上的容器

docker exec -it <container> bash

使用ping命令可以测试互联结果

提醒:可以通过容器名ping 如ping mysql

Final work

理论部分全部学习完毕,下面通过真实的一个项目进行总结,部署一个java项目分为两个部分

  • 部署Java应用(后端)
  • 部署前端

部署后端

项目代码:D:\学习资料汇总\ctf\Docker\hmall

首先对java项目打包(好慢)

右侧Maven 去掉单元测试 就是那个闪电标 然后双击package

image-20240125095144256

服务器中Docker容器前置配置:

  • mysql

拉取镜像

image-20240125100848131

挂载到本地目录

image-20240125103039647

image-20240125103049446

创建结果 把mysql的配置文件导入D:\学习资料汇总\ctf\Docker\mysql

创建容器:挂载目录到宿主机 作用是数据的持久保存 不会因为Docker的变化丢失

docker run -d \
	--name mysql \
	-p 3306:3306 \
	-e TZ=Asia/Shanghai \
	-e MYSQL_ROOT_PASSWORD=123 \
	-v /root/mysql/data:/var/lib/mysql \
	-v /root/mysql/init:/docker-entrypoint-initdb.d \
	-v /root/mysql/conf:/etc/mysql/conf.d \
	mysql

image-20240125104120678

data中自动生成

使用heidiSQL连接测试

注意这里有一个配置问题

因为开发一般在本地嘛 不会直接在服务器上面测 但是我这服务器没有任何资产 就是学习用着玩的就直接在服务器上面部署的

但是mysql去链接的时候不成功是因为服务器安全组的设置,无法访问到3306端口

所以在安全组里面设置一下 把3306端口打开就行 为了一定的安全性 源设置为本机ip即可 就是只有在你的电脑上才能访问到该服务器的3306端口

image-20240125104158185

  • 网络桥

创建一个网 happySu

image-20240125104407279

把mysql容器添加到该网桥中

image-20240125104533884

image-20240125104549528

添加成功

打包jar寄了

image-20240125153823864

把打包的内容jar包 + Dockerfile文件 放到root目录下 然后把jar包导入到Docker中

#基础镜像 可能有点慢
[root@happySu ~]# docker build -t hmall .

image-20240125170745472

然后启动后端镜像

#直接添加到我们的网桥中
[root@happySu ~]# docker run -d --name hmall -p 8080:8080 --network happySu hmall

配置服务器安全组 开放8080

访问成功

image-20240125170900264

后端检测日志:

[root@happySu ~]# docker logs -f hmall

部署前端

挂载

访问前端就一定需要nginx 注意不仅仅是界面 还需要和后端连接

所以需要挂载conf文件

现将D:\学习资料汇总\ctf\Docker\nginx

这两个文件放到服务器的root/nginx 目录下

image-20240125172703538

然后运行下面的挂载

端口解释:

18080:前端

18081:管理员

挂载解释:

<服务器目录>:<容器目录>

docker run -d \
	--name nginx \
	-p 18080:18080 \
	-p 18081:18081 \
	-v /root/nginx/html:/usr/share/nginx/html \
	-v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
	--network happySu \
	nginx

修改服务器安全组 开放18080成功实现访问

image-20240125172918566

DockerCompose

安装:

sudo yum install python3 python3-pip

sudo pip3 install docker-compose

docker-compose --version
#出现报错 需要更新
sudo yum update python3 python3-pip

python3 --version  #需要3.6及以上

pip3 install --upgrade pip

sudo pip3 install docker-compose

参考:https://edu.yijinglab.com/post/273

使用:

这是一个工具 实现上面的快速构建n个相关联的容器

image-20240126000521785

服务描述的信息其实相当于docker run后面跟的命令去启动容器,只不过语法上有些不同下面举个例子

image-20240126001516048

image-20240126001721815 image-20240126001922311

depends_on: 表示依赖 创建会先创建依赖的内容

命令格式:

image-20240126002534593

注意该文件的放置位置

image-20240126002752362

Docker in CTF

主要进行题目的部署,后期会专门出一个密码交互题出题手册,先占坑,敬请期待~!

Reference

官方笔记文档
黑马程序员视频课
探姬师傅视频课

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1453144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

反向迭代器------封装的力量

目录 一、list封装中模板参数Ref和Ptr的理解 二、反向迭代器的实现 一、list封装中模板参数Ref和Ptr的理解 对于反向迭代器&#xff0c;是我们在前面STL模拟实现中留下的一个问题。在之前的文章中&#xff0c;我们极大程度上的利用了模板&#xff0c;从而减少了许多的代码&…

【半监督图像分割 2023 】BHPC

【半监督图像分割 2023 】BHPC 论文题目&#xff1a;Semi-supervised medical image segmentation via hard positives oriented contrastive learning 中文题目&#xff1a;通过面向硬阳性的对比学习进行半监督医学图像分割 论文链接&#xff1a; 论文代码&#xff1a;https:/…

CCF编程能力等级认证GESP—C++6级—20231209

CCF编程能力等级认证GESP—C6级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)闯关游戏工作沟通 答案及解析单选题判断题编程题1编程题2 单选题…

Midjourney绘图欣赏系列(五)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

2024023期传足14场胜负前瞻

新的一年祝大家行大运、发大财、中大奖&#xff01;2024023期赛事由英超2场&#xff0c;德甲2场、意甲4场、西甲3场、法甲3场组成。售止时间为2月18日&#xff08;周六&#xff09;21点30分&#xff0c;敬请留意&#xff1a; 本期中深盘较少&#xff0c;1.5以下赔率仅1场&#…

二、ActiveMQ安装

ActiveMQ安装 一、相关环境二、安装Java8三、下载安装包四、启动五、其他命令六、开放端口七、后台管理 一、相关环境 环境&#xff1a;Centos7.9安装ActiveMQ版本&#xff1a;5.15.9JDK8 二、安装Java8 安装教程&#xff1a;https://qingsi.blog.csdn.net/article/details/…

RCS系统之:基础算法

设计仓库机器人的控制管理系统涉及到路径规划、任务分配、库存管理、通信系统等方面。以下是一个基本的仓库机器人控制管理系统方案的概述&#xff1a; 路径规划&#xff1a;设计一个路径规划系统&#xff0c;用于确定机器人在仓库内的最佳行驶路径&#xff0c;以最大程度地提…

学习数据结构和算法的第9天

题目讲解 移除元素 ​ 给你一个数组nums和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val的元素&#xff0c;并返回移除后数组的新长度。 ​ 不要使用额外的数组空间&#xff0c;你必须仅使用0(1)额外空间并 原地 修改输入数组。 ​ 元素的顺序可以改变。你不需要…

使用Taro开发鸿蒙原生应用——快速上手,鸿蒙应用开发指南

导读 本指南为开发者提供了使用 Taro 框架开发鸿蒙原生应用的快速入门方法。Taro&#xff0c;作为一个多端统一开发框架&#xff0c;让开发者能够使用一套代码同时适配多个平台&#xff0c;包括鸿蒙系统。文章将详细介绍如何配置开发环境&#xff0c;以及如何利用 Taro 的特性…

leetcode hot100 拆分整数

在本题目中&#xff0c;我们需要拆分一个整数n&#xff0c;让其拆分的整数积最大。因为每拆分一次都和之前上一次拆分有关系&#xff0c;比如拆分6可以拆成2x4&#xff0c;还可以拆成2x2x2&#xff0c;那么我们可以采用动态规划来做。 首先确定dp数组的含义&#xff0c;这里dp…

linux学习进程控制【创建-终止-等待】

目录 1.进程创建 1.1fork函数 1.2写时拷贝 2.进程终止 2.1进程退出场景 2.2进程退出方式 3.进程等待 3.1进程等待的必要性 3.2等待方式 3.2.1wait&#xff08;&#xff09; 3.2.2waitpid&#xff08;&#xff09; 3.3轮训等待 总结&#xff1a; 1.进程创建 …

给定n个结点m条边的简单无向图,判断该图是否存在鱼形状的子图:有一个环,其中有一个结点有另外两条边,连向不在环内的两个结点。若有,输出子图的连边

题目 思路: #include <bits/stdc++.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn = 1e6 + 5, inf = 1e18 * 3, maxm = 4e4 + 5,…

对树莓派上配置mdadm的一些补充

1、如果要重新配置该如何回退到初始状态&#xff1f; 答&#xff1a;可参考以下指令&#xff1a; cat /proc/mdstat sudo umount /dev/md0 sudo mdadm --stop /dev/md0 sudo mdadm --zero-superblock /dev/sda sudo mdadm --zero-superblock /dev/sdb sudo nano /etc/fstab&a…

不具备这十个能力,真不能说是专业的B端系统设计师

B端系统的复杂程度要远远的超过C端&#xff0c;作为这类设计师绝对不能满足于&#xff0c;画个界面&#xff0c;拼一下组件能搞定的&#xff0c;真的需要精心研究&#xff0c;本文列举了十项能力&#xff0c;帮助设计师们针对的提升。 一、什么是B端管理系统设计 B端管理系统设…

谷歌新动作:双子模型大放送,开发者福音来了!

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

wayland(xdg_wm_base) + egl + opengles——dma_buf 作为纹理数据源(五)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、EGL dma_buf import 相关的数据结构和函数1. EGLImageKHR2. eglCreateImageKHR()3. glEGLImageTargetTexture2DOES()二、egl 中 import dma_buf 作为纹理的代码实例1. egl_wayland_dmabuf_…

Flink理论—Flink架构设计

Flink架构设计 Flink 是一个分布式系统&#xff0c;需要有效分配和管理计算资源才能执行流应用程序。它集成了所有常见的集群资源管理器&#xff0c;例如Hadoop YARN&#xff0c;但也可以设置作为独立集群甚至库运行,例如Spark 的 Standalone Mode 本节概述了 Flink 架构&…

单片机学习笔记---直流电机驱动(PWM)

直流电机介绍 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&#xff08;转子&#xff09;和换向器…

leetcode(双指针)15.三数之和(C++详细解释)DAY10

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的…

shell脚本之高级变量

目录 一、高级变量赋值 1、高级变量赋值总结表 2、相关操作 二、变量间接引用 1、eval命令 一、高级变量赋值 1、高级变量赋值总结表 变量配置方式str 无配置str 为空字符串str 已配置为非空字符串var${str-expr}varexprvarvar$strvar${str:-expr}varexprvarexprvar$str…