还不会用sed命令吗?

之前写的一个脚手架为了方便 Docker 部署写了一个 Dockerfilebuild.sh 的脚本,大概长这样:

Dockerfile 复制代码
FROM openjdk:17

# 设置容器名称和重启策略
ARG CONTAINER_NAME=quick-spring
ARG RESTART="always"

# 暴露端口
EXPOSE 8888

# 挂载本地文件系统到容器中
ADD ./core-0.0.1.jar app.jar

# 设置环境变量
ENV TZ=Asia/Shanghai

# 启动命令
CMD java -jar app.jar
shell 复制代码
docker rm -f quick-spring
docker build . -t quick-spring
docker run -d -p 8888:8888 --name quick-spring quick-spring

每次需要部署的时候只需要把 Dockefilebuild.sh 以及 jar 包上传到服务就可以运行 build.sh 一键部署了。

但是每当我用这个脚手架新开一个项目的时候,总是需要重新替换一下 Dockerfilebuild.sh 中的名字,虽然工作量不大,但是改多了也会烦,而且有时候甚至会忘记修改。

程序员都是爱偷懒的,我也不例外。

于是我便想着把这个操作通用化,写一个 shell 脚本完成所有的步骤,实现真正的一键部署。

期间用到了许多实用的知识点,于是便写了这篇文章记录一下。

Sed命令

首先想到的是通过 pom.xml 来获取项目名以及版本号:

ini 复制代码
project_name = $(cat pom.xml |  sed -n 's/.*<artifactId>\(.*\)<\/artifactId>.*$/\1/p')

先来介绍一下 sed 命令

sed 是一个流式文本编辑器,用于在文本流中进行替换、删除、插入等操作,可以很方便地和正则表达式配合使用。

它的格式是:

arduino 复制代码
sed OPTIONS 'COMMAND' FILE

一个最基本的例子是:

arduino 复制代码
sed 's/hello/world/' file

其中 s 表示替换命令,即本次操作进行的是替换操作,将 hello 替换为 world,然后打印出来,如:

但是默认情况下只会替换每一行的第一个匹配项:

需要加上 g 命令才能替换所有匹配项:

如果我只想要打印发生替换的行,那么就加上 p 命令(打印模板块的行)和 -n 选项(仅显示处理后的结果)即:

回到上面的问题:

arduino 复制代码
sed -n 's/.*<artifactId>\(.*\)<\/artifactId>.*$/\1/p'

现在来看的话就清晰多了,首先,这里的 -np 是为了确保只输出替换后的行。

至于中中间的字符串其实应该这么看:

arduino 复制代码
's/   .*<artifactId>\(.*\)<\/artifactId>.*$/   \1   /p'

.*<artifactId>\(.*\)<\/artifactId>.*$/ 这个表示的就是要被替换的文本的正则表达式,而 \1 则表示第一个捕获组,也就是这里的 \(.*\)

值得注意的是这里捕获组的括号用到了转义字符,这是因为 sed 命令默认使用的是最原始的正则表达式,捕获组的括号必须是 \(\) 而不是 ()

而这里的 \1 则表示第一个捕获组,也就是 \(.*\) 捕获到的这个 .* 内容,也就是如果我们匹配到的项目名是 quick-spring ,那么这里的 \1 则是 quick-spring

所以可想而知这里最后输出的其实就是尖括号中间的字符串。

但是上面的写法会有一个问题:

不难看出所有的 artifactId 都被匹配了。

于是便用了一个取巧的方法,只读取前10行:

bash 复制代码
head -n 10 pom.xml |  sed -n 's/.*<artifactId>\(.*\)<\/artifactId>.*$/\1/p'

虽然不适用所有情况(比如 artifactId 写到后面去了),但是在这个脚手架里面还是可以解决问题的(而且一般 artifactId 都是写在前十行):

然后用占位符来替换掉原来的硬编码:

ini 复制代码
FROM openjdk:17

# 设置容器名称和重启策略
ARG CONTAINER_NAME={{projectName}}
ARG RESTART="always"

# 暴露端口
EXPOSE 8888

# 挂载本地文件系统到容器中
ADD ./core-{{version}}.jar app.jar

# 设置环境变量
ENV TZ=Asia/Shanghai

# 启动命令
CMD java -jar app.jar

接着只需要通过 sed 命令进行正则匹配并替换文本即可:

bash 复制代码
sed -e "s/{{projectName}}/${project_name}/" -e "s/{{version}}/${version}/" Dockerfile.template | cat > Dockerfile

注意到这个 -e 选项可以组合多个命令,将多个命令作用于同一个文本。

接下来就是构建的操作了:

bash 复制代码
docker rm -f "${project_name}"
docker build . -t "${project_name}"
docker run -d -p 8888:8888 --name "${project_name} ${project_name}"

test命令

值得注意的是,为了防止多次重复生成 Dockerfile,脚本还对文本是否存在进行了检测,这里用到了 test 命令 -f!

bash 复制代码
if [ ! -f Dockerfile ]; then
  echo "生成Dockerfile"
  sed -e "s/{{projectName}}/${project_name}/" -e "s/{{version}}/${version}/" Dockerfile.template | cat > Dockerfile
fi

test 命令是用于测试文件或条件的工具,通常用于 shell 脚本中的条件判断。在 Unix/Linux 系统中,test 命令通常由 [ ] 表示,它们可以用于测试各种条件,并返回一个布尔值作为结果。

以下是常见的 test 命令及其功能:

  1. 文件测试

    • e FILE:检查文件是否存在。
    • f FILE:检查文件是否存在且为普通文件。
    • d FILE:检查文件是否存在且为目录。
    • r FILE:检查文件是否存在且可读。
    • w FILE:检查文件是否存在且可写。
    • x FILE:检查文件是否存在且可执行。
  2. 字符串测试

    • z STRING:检查字符串是否为空。
    • n STRING:检查字符串是否非空。
    • STRING1 = STRING2:检查两个字符串是否相等。
    • STRING1 != STRING2:检查两个字符串是否不相等。
  3. 整数比较

    • INTEGER1 -eq INTEGER2:检查两个整数是否相等。
    • INTEGER1 -ne INTEGER2:检查两个整数是否不相等。
    • INTEGER1 -gt INTEGER2:检查 INTEGER1 是否大于 INTEGER2。
    • INTEGER1 -lt INTEGER2:检查 INTEGER1 是否小于 INTEGER2。
    • INTEGER1 -ge INTEGER2:检查 INTEGER1 是否大于或等于 INTEGER2。
    • INTEGER1 -le INTEGER2:检查 INTEGER1 是否小于或等于 INTEGER2。
  4. 逻辑测试

    • ! EXPRESSION:返回 EXPRESSION 的逻辑否定值。
    • EXPRESSION1 -a EXPRESSION2:返回 AND 逻辑运算结果。
    • EXPRESSION1 -o EXPRESSION2:返回 OR 逻辑运算结果

代码

shell 复制代码
echo "解析pom.xml"
pom_xml_head10=$(head -n 10 pom.xml)
project_name=$(echo "$pom_xml_head10" | sed -n 's/.*<artifactId>(.*)</artifactId>.*$/\1/p')
version=$(echo "$pom_xml_head10" | sed -n 's/.*<version>(.*)</version>.*$/\1/p')

echo "项目名:$project_name"
echo "版本号:$version"

if [ ! -f Dockerfile ]; then
  echo "生成Dockerfile"
  sed -e "s/{{projectName}}/${project_name}/" -e "s/{{version}}/${version}/" Dockerfile.template | cat > Dockerfile
fi

echo "删除原有容器"
docker rm -f "${project_name}"

echo "构建镜像"
docker build . -t "${project_name}"

echo "启动容器"
docker run -d -p 8888:8888 --name "${project_name} ${project_name}"
相关推荐
热爱嵌入式的小许1 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
2401_857622662 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589362 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
韩楚风5 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学5 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO5 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
杨哥带你写代码5 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
Pythonliu75 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器