-
概述
- 感觉是个 比较重要的东西
-
有个疑问
- 我是先讲 docker build 还是 先讲 Dockerfile
- 穿插讲
-
docker build
- 最基本的东西
- 原理
- -t
- -f
- 最基本的东西
-
docker file
- 各种命令
- 命令本身
- 如果需要 docker build 配合, 那就和 docker build 一起讲
- 各种命令
-
- 穿插讲
- 我是先讲 docker build 还是 先讲 Dockerfile
-
准备
-
os
- centos7
-
docker
- client
- 18.09.6
- engine
- 18.09.6
- client
-
知识
- docker
- docker 镜像
- shell 编程
-
1. Dockerfile
-
概述
- 简介 Dockerfile
-
回顾
- docker 镜像
-
概述
- docker 容器的模板
-
结构
- 由若干个 layer 组成
-
构建容器机制
- 构建时, 自底向上依次构造 layer
- 只读模式
- 向外提供一个读写层
- 构建时, 自底向上依次构造 layer
-
创建方式
-
docker commit
- 概述
- 将当前的容器, 构造成一个镜像
- 概述
-
docker build
- 概述
- 由 Dockerfile, 构建一个镜像
- 概述
-
对比
-
docker commit
- 方便构建
- 但是会缺失一些信息
-
docker build
- 方便管理
- 环境及代码
- 可以用 git 管理
- 方便移动
- 方便修改, 结构清晰
- 环境及代码
- 方便管理
-
-
-
建议
- 尽量用 Dockerfile 构建镜像
-
- docker 镜像
-
Dockerfile
-
概述
- docker 构建镜像的源文件
-
机制
- docker 依次读取 Dockerfile 里的命令
- 指定的环境
- 逐层构建镜像
-
语法
- Dockerfile 语法想对较多
- 这个后面慢慢描述
- Dockerfile 语法想对较多
-
2. docker build
-
概述
- docker client 构造镜像
-
准备
- 一个 Dockerfile
- 记录构建镜像的命令
- 一个上下文
- 准备构建镜像时需要的资源
- 一个 Dockerfile
-
Dockerfile
-
例子
# 最简单的 Dockerfile
# 文件名为 Dockerfile
FROM ubuntu:14.04
RUN echo 'hello' -
注意
- Dockerfile 的文件名
-
默认文件名是 Dockerfile
- 如果首字母没有大写, docker 可能会找不到文件
- 如果硬要执着名字, 需要 -f 参数来制定
- 这个后面会讲
-
Dockerfile 里的 命令, 一定要 大写
- 小写了 docker 不认识
-
- Dockerfile 的文件名
-
-
docker build
-
概述
- 构建镜像的命令
- 这里简单讲下使用
- 其他的参数, 后面会跟 Dockerfile 的语法一起讲
-
准备
-
context
- 作用
- 存放 Dockerfile
- 存放 image 需要的其他文件
- 作用
-
Dockerfile
- 作用
- 构建镜像的说明书
- 作用
-
其他
- 执行命令时, 需要进入 context 目录
-
-
命令执行
-
最简单的那种
-
命令
# 是的, 你没看错, 这就完了...
# 格式: docker build <context>
> docker build . -
结果
- 镜像生成成功
-
问题
- 生成的镜像, 没有 仓库 和 tag 信息, 很难定位
-
-
添加 仓库信息 定位
-
命令
# -t 选项, 可以提供 标签 的配置
# 格式: docker build -t <repo>[:tag] <context>
> docker build -t myrepo/image:0.0.1 . -
结果
- 镜像生成成功
- 带有 repo 和 tag 信息
-
-
自定义 Dockerfile 和 context
-
命令
# 手动指定 Dockerfile 和 context
# 格式: docker build -t <repo>[:tag] -f <DockerfilePath> <context>
> docker build -t myrepo/image:0.0.2 -f /root/myDockerfile /root/context -
结果
- 镜像生成成功
- 使用的是 指定的资源
-
-
-
-
执行结果
-
结果
> docker build -t <repo>/demo:0.0.2 -f Dockerfile .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM ubuntu:latest
---> 7698f282e524
Step 2/2 : RUN echo 'hello'
---> Using cache
---> 331b9ab46190
Successfully built 331b9ab46190
Successfully tagged <repo>/demo:0.0.2
-
3. Dockerfile 命令简介
- 概述
- 简单介绍命令
1. 注释
-
概述
- Dockerfile 的注释
-
格式
# 以 # 开头的行
# 行中出现的 # 则一律不被视为 注释
# 注释不支持 换行 -
特殊注释
-
概述
- 有部分特殊的注释, 会影响 Dockerfile 的构建
-
注意
- 一类特殊注释, 只能出现一次
- 出现的位置, 必须在 FROM 语句之前
- 而且格式必须 符合要求, 否则就是 普通注释
- 不能换行
- 不能随便加空格
后跟一个空格
- = 前后没有空格
- 下面给的例子, 肯定没问题
-
syntax
-
概述
- Dockerfile 语法指定
-
例子
# syntax=docker/dockerfile
-
其他
- 需要有 BuildKit 的支持
- 默认是 docker/Dockerfile
- 具体可用版本, 请查询官方文档
-
-
escape
-
概述
- 指定 转义字符 符号
- 这个名字叫啥, 我也不确定
- 指定 转义字符 符号
-
转义字符
- 默认
- \ 开头, 后面的一个字符会被转义
- 设置
- 可以配置成其他的
- windows 环境下, 常用 `
- 默认
-
例子
# 这个例子
# escape=`
-
-
2. FROM
-
概述
- 指定一个 基础镜像
-
基础镜像
-
概述
- 在某个镜像的基础上, 再构建镜像
-
作用
- 方便构建
- 省去基础的准备
- 加快速度
- 构建直接从新内容开始
- 基础层沿用基础镜像的内容
- 发展快速
- 你的构建, 也可以成为别人构建的基础
- 方便构建
-
-
示例
FROM ubuntu:latest
-
其他
-
通常在 Dockerfile 第一句
- 例外
- 注释
- 常规注释
- syntax
- escape
- arg
- 指定参数
- 注释
- 例外
from 一定要大写
-
tag
- 最好指定明确版本, 不要用 latest
-
3. ARG
-
概述
- 给 指定镜像参数
-
参数
- 镜像在 构建中 使用的变量
- 构建完成后就会 无效
- 构建中如果声明了 同名的环境变量, 就会被 替代
- 环境变量后面会提到
-
示例1: 定义一个变量, 用来定义 基础镜像的版本
-
Dockerfile
# Version 0.0.4
ARG version
FROM ubuntu:$version -
命令
# 通过 --build-arg 指定了 version 参数
# -f 指定了 Dockerfile
> docker image build --build-arg version=19.04 -t repo/demo:0.0.4 -f Dockerfile04 . -
结果
构建成功
-
版本正确
> docker image inspect -f '{{.RepoTags}}' repo/demo:0.0.4
-
其他
- 构建中
- 命令行中的 step 里, 看到的还是 $version
- 构建中
-
问题: 万一我忘了加参数, 会怎么样呢
-
结果
- 生成会报错
-
有没有什么好办法呢
- 当然有啦, 加默认值
-
-
-
示例2: 为 arg 添加默认值
-
Dockerfile
# Version 0.0.5
ARG version=19.04
FROM ubuntu:${version} -
命令
> docker image build -t repo/demo:0.0.5 -f Dockerfile05 .
-
结果
- 创建成功
-
问题1: 如果我又想指定值了, 有办法吗?
- 当然有啦
- 还是用 --build-arg 指定
- 当然有啦
-
问题2: 这个 arg 除了指定 from 的版本信息, 还能干别的吗?
- 也可以在其他地方用啊
- 马上就开始讲了
- 也可以在其他地方用啊
-
-
示例3: arg 的其他使用
-
Dockerfile
# Version 0.0.6
ARG version=19.04
FROM ubuntu:${version}
RUN echo ${version} -
命令
> docker image build -t repo/demo:0.0.6 -f Dockerfile06 .
-
结果
- 镜像成功创建
- echo 那行, 却没有显示出 版本号
-
问题1: 为什么版本号不见了?
-
结果
- 作用域问题
- from 前面的 arg, 作用域只能到 from 语句
- 之后就消失了
- ref
- 作用域问题
-
后续
-
如何使用 from 前的 arg
-
重新声明即可
# Version 0.0.7
ARG version=19.04
FROM ubuntu:${version}
ARG version
RUN echo "hello ${version}"
-
或者说, 在 from 后面使用 arg
再者, 还可以直接使用 env
-
-
-
-
问题: 既然在 构建完就无法使用了, 能不能用来存放 密码 之类的东西
- 不建议
- 虽然重新起来的容器看不到了
- 但是可以通过 'docker image history' 查看这个东西
- 不建议
-
预定义 arg
-
概述
- docker 预定义了一些 变量
-
列表
# 本质上只有 四个
# 具体干啥, 我现在还不知道
# 但是乍一看, 是跟 网络相关的
# 这个等以后有机会, 再讲吧
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
-
4. ENV
-
概述
- 镜像对应容器的 环境变量
-
环境变量
-
概述
- 由镜像启动容器后, 默认会带一些 环境变量
-
作用
- 环境变量可以改变环境的很多东西
- 或者说, 改变环境变量, 就能改变系统行为
- 而且环境变量这种东西, 一般是 所有用户 都能获取到的
- 环境变量可以改变环境的很多东西
-
-
示例1: 简单使用 环境变量
-
Dockerfile
# Version 0.0.8
ARG version=19.04
FROM ubuntu:${version}
ARG version
RUN echo "hello ${version}"
ENV var="docker"
RUN echo "hello ${var}" -
命令
> docker image build -t repo/demo:0.0.8 -f Dockerfile08 .
-
结果
- 镜像创建成功
- 变量成功使用
-
问题1: 为啥这次一上来就设置 env 的默认值, 不设置可以吗?
-
当然可以啦
- 但是, 弥补时机, 不太一样
-
弥补时机
- arg
- docker image build
- --build-arg
- docker image build
- env
- docker container run
- -e / --env
- 这个后面应该会 找机会讲, 还是有点用的
- docker container run
- arg
-
-
问题2: 会不会有这种场景, 我的某个 arg 和 env, 值其实是一样的
-
场景
- arg 和 env 值是一样的
- 我想在 build 时确认, 以免 后面忘了
-
当然可以
- arg 和 env 可以联动的
-
-
-
示例2: arg 联动 env
-
Dockerfile
# Version 0.0.9
ARG version=19.04
FROM ubuntu:${version}
ARG version
RUN echo "hello ${version}"
ENV var=${version}
RUN echo "hello ${var}" -
命令
> docker image build -t repo/demo:0.0.9 -f Dockerfile09 .
-
结果
- 镜像正常产生
- var 也被赋予了 verison 的值
-
其他
- 在这种场景下, env 甚至可以和 arg 重名
- 结果
- env 被赋予 arg 的值
- arg 就没了
- 结果
- 在这种场景下, env 甚至可以和 arg 重名
-
问题1: env 可以取消吗
- 这个在 shell 里是可以的
- 但是 Dockerfile 里, 是否有, 我暂时还没找到...
-
5. run
-
概述
- 执行命令
-
执行
- 表面
- 执行命令
- 实际
- 将上一层的镜像, 启动为一个容器
- 在容器里执行命令
- 将执行命令后的容器, 再整成一层新的镜像
- 表面
-
模式
-
shell 模式
-
概述
- 启动一个 shell, 然后执行命令
-
默认shell
- linux
- /bin/sh -c
- win
- cmd /S /C
- linux
-
切换 shell
- 这个可以通过后面的 SHELL 命令来做
-
命令
# RUN <command> [<options and args>]
RUN echo "hello, docker."
-
-
exec 模式
-
概述
- 不启动 shell, 直接执行命令
-
不启动 shell
-
这个我也看不懂
- 官网说的很模糊
- 强调的, 也只有 exec 模式取不到 环境变量
-
好吧, 那我就理解为
- 取不到 环境变量
- 原因可能是害怕某种干扰吧
-
-
命令
# 1. 使用 json 的 数组格式
# 2. 命令和参数作为数组的成员
# 3. 空格隔开的, 就是一个参数
# 4. 每个参数, 都要用 "" 引起来
RUN ["echo", "hello, docker."]
# 如果硬要 环境变量
RUN ["/bin/sh", "-c", "echo", "hello, docker."]
-
-
-
建议
- 加速
- 因为执行一个 run, 会生成一个容器和镜像
- run 越多, 构造时间就越长
- 解决
-
将多个命令, 写到一个 run 里
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
-
- 因为执行一个 run, 会生成一个容器和镜像
- 加速
6. shell
-
概述
- 指定 运行命令 的 shell
-
shell
-
默认 shell
- 上一部分提过
-
切换 shell
- Dockerfile 中可以随时切
-
问题
- 切换 shell, 会不会导致 环境变量 丢失
-
-
命令
# linux
SHELL ["/bin/bash"]
# win
SHELL ["powershell", "-command"]
7. copy
-
概述
- 将文件从 宿主机 拷贝到 镜像
-
拷贝
-
源
- 拷贝的源, 必须在 context 下
- 所以路径信息, 都是 以context为根 的路径
- 内容
- 文件
- 目录
- 原内容支持 通配符
- 通配符 不是 正则表达式
- 解压
- 不会做
- 拷贝的源, 必须在 context 下
-
目的
-
拷贝的目的
- 文件
- 结尾不带 /
- 目录
- 结尾带 /
- 文件
-
路径
- 如果路径不存在, 会自动创建
-
-
dest 文件权限
-
默认
- uid 和 gid 都为 0
-
命令
# 官网上给的例子
# 其他的搭配, 估计只有自己尝试了...
--chown=<userId>:<groupName>
--chown=<userName>
--chown=<userId>
--chown=<userId>:<groupId>
-
-
权限
- 默认 0755
- 这个需要用 命令 改
- 默认 0755
-
-
命令
COPY [--chown=<user>:<group>] <src> ... <dest>
8. add
-
概述
- 将文件拷贝到 镜像
- 来源丰富
- 可以解压
- 将文件拷贝到 镜像
-
拷贝
-
源
-
拷贝的源
- context 下, 同 copy
- url
-
解压
- 不会做
-
其他
- 同 copy
-
-
目的
-
解压
- 源是 压缩包
- gz 等
- 需要去 官网 确认
- 目的
- 一个 目录
- 如果目的有同名文件
- 不会覆盖
- 源是 压缩包
-
其他
- 同 copy
-
-
dest 文件归属
- 同 copy
-
权限
- 默认 0755
- 这个需要用 命令 改
- 默认 0755
-
-
命令
# 从 url 获取(不解压)
ADD http://wordpress.org/latest.zip /root/wordpress.zip
# 解压
ADD http://wordpress.org/latest.zip /root/wordpress/
9. cmd
-
概述
- 容器启动命令
- 配合 entrypoint
- 这个后面再说
-
启动命令
-
启动命令
-
时机
- 容器启动时执行的命令
-
只会有 一个
- 所以 cmd 命令只有 最后一个 会生效
-
替代
- 如果 docker run 指定了 启动命令的话
- cmd 的命令, 不会再执行
- 如果 docker run 指定了 启动命令的话
-
-
执行模式
-
shell 模式
-
命令
# 类似 RUN
CMD command param1 param2
-
-
exec 模式
```
# 类似 RUN
CMD ["executable","param1","param2"]
```
-
-
docker run
- 没有命令
- 执行 cmd
- 有 命令
- 执行 docker run 的命令
- 没有命令
-
10. entrypoint
-
概述
- 优先级更高的 启动命令
- 配合 cmd 可以指定 命令的默认参数
-
启动命令
-
工作模式
- shell 模式
- 同 run
- exec 模式
- 同 run
- shell 模式
-
单独使用 entrypoint
- 同 单独使用 cmd
-
配合使用
-
entrypoint
- 使用 exec 模式
- 第一个参数为, 可执行命令
- 后面的参数, 为 稳定的参数 或者 选项
- 使用 exec 模式
-
cmd
- 使用 exec 模式
- 所有参数, 都是 entrypoint 的 参数
- 如果 cmd 可以执行, 则会 覆盖 entrypoint
- 使用 exec 模式
-
-
docker run
- 没有命令
- 执行 entrypoint + cmd
- 有命令
- 执行 entrypoint + docker run 后面跟的 参数
- 没有命令
-
-
ref
11. label
-
概述
- 添加 描述信息
-
描述信息
- 镜像元数据
-
命令
LABEL maintainer='repo'
-
查看
> docker image inspect -f '{{json .ContainerConfig.Labels}}' repo/demo:0.0.1
12. user
-
概述
- 指定默认用户
-
默认用户
默认执行命令的用户
-
默认值
- root
-
命令
USER <user>[:<group>]
USER <UID>[:<GID>]
13. workdir
-
概述
- 指定默认目录
-
默认目录
-
docker 启动后的 pwd
- 命令如果不指定路径, 都会以 那里为 pwd
-
默认值
- /root/
-
路径
-
绝对路径
- / 开头
-
相对路径
- 直接是 路径开头
- 相对的是 上一个 workdir
- 直接是 路径开头
可以解析环境变量
-
如果指定到一个 空路径
- 会主动创建
-
-
命令格式
WORKDIR /absolutePath
WORKDIR relativePath
-
14. onbuild
-
概述
- 触发器
-
触发器
-
触发场景
- 该镜像察觉到自己作为其他镜像的 基础镜像
-
结果
- 执行以 ONBUILD 开头的命令
- 可以理解为 在 from 语句后, 按顺序执行 onbuild 语句
- 然后再执行 Dockerfile 里的语句
- 执行以 ONBUILD 开头的命令
-
-
命令
ONBUILD <otherInstruction>
15. volume
-
概述
- 添加 挂载点
-
挂载点
-
概述
- 一个路径
- 但这个路径下, 会 挂载一个 卷
-
机制
- Dockerfile
- 指定挂载点
- 创建镜像
- 生成容器
-
默认行为
- 在 host 生成一个 卷
- 卷名随机
- 将这个卷挂载到 容器的挂载点
- 在 host 生成一个 卷
-
-v
- 将 -v 指定的内容, 对接到挂载点
-
- Dockerfile
-
其他
- 如果 路径不存在, 会在容器里创建
-
-
命令
# 列表式
VOLUME /myvol /root/test
# json 式
VOLUME ["/myvol", /root/test]
16. expose
-
概述
- 暴露 容器端口
-
暴露容器端口
-
概述
- 指定某个容器端口
- 让这个端口 在默认的情况下, 暴露出来
-
暴露
- 对容器外可见
-
机制
- expose 某个端口
- 启动容器
-
-
命令
# 指定端口和协议
# 默认协议是 tcp
# 可以指定 多个
expose <port>[:<protocol>] -
创建容器
# 一定要加 -P
# 这样 expose 的端口, 会随机映射到 host 的可用端口上
# 如果没有, 则会别 映射到 null
# 不影响 -p 选项来暴露端口
> docker container run --rm --name demo03 -it -P -p 32769:90/tcp repo/demo:0.0.1 -
验证
# 可以在 ports 那里, 看到暴露端口
> docker container ls
17. healthcheck
-
概述
- 健康检查
-
健康检查
-
机制
- 定期在容器中 执行命令,
- 根据 执行结果 判断容器是否健康
- 将健康情况, 反馈到
docker container ps
的 status 栏里
-
执行机制
-
参数
- 时间间隔
- --interval
- 默认值 30 s
- 超时时间
- --timeout
- 默认值 30s
- 重试次数
- --retries
- 默认值 3
- 时间间隔
-
健康状态
- starting
- 开始状态
- healthy
- 健康状态
- unhealthy
- 不健康状态
- starting
-
注意
- 一个镜像, 只能有一个 生效的 checkhealth
- 如果当前 Dockerfile 里没写, 会继承父镜像的
- 如果 当前 和 父镜像都有, 则以当前为准
-
-
命令
# 拒绝继承,
CHECKHEALTH NONE
# 简单示例
# 注意, 那个 CMD 是格式, 跟 CMD 命令要区别开
# curl 如果失败, 则容器状态变为 不健康
checkout --interval=10s --timeout=3s --retries=3 CMD curl http://192.168.30.5:5000/v2
-
ps
-
ref
- Dockerfile reference
- docker build
- Dockerfile HEALTHCHECK详解
- 书籍
- 第一本 docker 书(修订版)
- docker 容器与容器云
- spring 微服务实战
- docker 实践
-
后续
-
整理
- 花了一晚上整理的内容, 感觉还是有点乱
- 想把它 拆开
- 放一块的话, 内容可能会不全
搭建一些环境, 稍微实战一下
-
学习容器编排
- compose
- k8s
-
Docker - Dockerfile - 常见命令简介的更多相关文章
-
Docker:常见命令
Docker常见命令(持续更新中): 说明 命令 截图 1 查看Docker版本 Docker -v 2 查看镜像 Docker image ls 3 查看容器 Docker conta ...
-
docker 的常见命令行解析
1.查看本地镜像 sudo docker images 2.查看本地容器 sudo docker ps 3.根据Dockerfile制作镜像命令 sudo docker build -t Myimag ...
-
Dockerfile常见命令
Dockerfile结构 Dockerfile的结构分成了若*分,每个部分之间的先后顺序有明确的要求: 部分 命令 基础镜像信息 FROM 维护者信息 MAINTAINER 镜像操作指令 RUN.C ...
-
docker删除常见命令
$ docker stop $(docker ps -a | grep "Exited" | awk '{print $1 }') //停止容器 1b7067e19d6f a840 ...
-
小D课堂 - 新版本微服务springcloud+Docker教程_1_01课程简介
笔记 ============================================= SpringCloud课程笔记.txt 第一章 课程介绍和学习路线 1.微服务架构SpringClou ...
-
学习Docker之Dockerfile的命令
使用Dockerfile去构建镜像好比堆积木.使用pom去构建maven项目一样,有异曲同工之妙,下面就把Dockerfile中主要的命令介绍一下. 组成部分 部分 命令 基础镜像信息 FROM 维护 ...
-
Dockerfile指令及docker的常用命令
DockerfileFROM: FROM <image> FROM <image>:<tag> MAINTAINER: MAINTAINER <name> ...
-
Docker 常见命令
Docker 运行流程 辅助命令 # 1.安装完成辅助命令 docker version -------------------------- 查看docker的信息 docker info ---- ...
-
【原创】运维基础之Docker(1)简介、安装、使用
docker 18.09 官方:https://docs.docker.com/ 一 简介 Docker is a platform for developers and sysadmins to d ...
随机推荐
-
java 反编译
JavaDecompiler http://jd.benow.ca/jd-eclipse/update/
-
Jquery操作下拉框(DropDownList)实现取值赋值
Jquery操作下拉框(DropDownList)想必大家都有所接触吧,下面与大家分享下对DropDownList进行取值赋值的实现代码 1. 获取选中项: 获取选中项的Value值: $('sele ...
-
HOWTO: InstallScript MSI工程取Log
InstallShield的各种类型安装包如果遇到安装问题(尤其是在客户安装时遇到问题),获取Log分析是最有效的方法之一. 对于封装一个Setup.exe的InstallScript MSI工程,我 ...
-
【BZOJ】【1045/1465】【HAOI2008】糖果传递
思路题/神奇的转化…… orz hzwer 或许这个思路可以从单行而非环形的递推中找到?(单行的时候,从左往右直接递推即可…… 感觉好神奇>_<脑残患者想不出…… P.S.话说在$n\le ...
-
hadoop安装与WordCount例子
1.JDK安装 下载网址: http://www.oracle.com/technetwork/java/javase/downloads/jdk-6u29-download-513648.html ...
-
C# Eval在asp.net中的用法及作用
Eval( " ")和Bind( " ") 这两种一个单向绑定,一个双向绑定,bind是双向绑定,但需数据源支持 ASP.NET 2.0改善了模板中的数据绑定操 ...
-
Web App 图片上传编辑器
使用cropper.jqueryUpload插件.Jquery.src-dataurl-canvas-blob文件. @{ ViewBag.Title = "更新头像"; Layo ...
-
利用最新的CentOS7.5,hadoop3.1,spark2.3.2搭建spark集群
1. 桥接模式,静态ip上外网:vi /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE=EthernetPROXY_METHOD=noneBROWSER_ ...
-
写了一个简单的Linux Shell用来下载文件
#!/bin/sh ; i<; i=i+ )); do # 利用spider来探测请求的资源是否存在,并把请求的结果写入到一个文件 wget --spider --http-user=usern ...
-
C++ 利用栈解决运算问题
2017-06-27 19:19:18 第一步需要将中缀表达式转为后缀表达式.这步的转化可以说是本题的核心. 主要的转化手段是利用栈,有如下几个规则: 数字直接输出 "("直接进栈 ...