如何列出docker容器中的卷?

当使用来自注册中心的docker映像时,我经常需要查看映像容器创建的卷。

注意:我在Red Hat 7上使用docker 1.3.2版本。

例子

Docker Registry的postgres官方镜像有一个为/var/lib/postgresql/data的容器配置的卷。

postgres容器中显示/var/lib/postgresql/data处的卷的最简洁的命令是什么?

368679 次浏览

使用docker ps来获取容器id。

然后docker inspect -f '\{\{ .Mounts }}' containerid

例子:

终端1

$ docker run -it -v /tmp:/tmp ubuntu:14.04 /bin/bash

终端2

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
ddb7b55902cc        ubuntu:14.04        "/bin/bash"         About a minute ago   Up About a minute                       distracted_banach


$ docker inspect -f "\{\{ .Mounts }}" ddb7
map[/tmp:/tmp]

输出

map[/tmp:/tmp]

显然是由于使用语言来实现docker命令工具。

没有-f formatdocker inspect命令非常冗长。因为它是JSON,你可以将它管道到python或nodejs,并提取你需要的任何东西。

paul@home:~$ docker inspect ddb7
[{
"AppArmorProfile": "",
"Args": [],
"Config": {
"AttachStderr": true,
"AttachStdin": true,
"AttachStdout": true,
"Cmd": [
"/bin/bash"
],
"CpuShares": 0,
"Cpuset": "",
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"ExposedPorts": null,
"Hostname": "ddb7b55902cc",
"Image": "ubuntu:14.04",
"MacAddress": "",
"Memory": 0,
"MemorySwap": 0,
"NetworkDisabled": false,
"OnBuild": null,
"OpenStdin": true,
"PortSpecs": null,
"StdinOnce": true,
"Tty": true,
"User": "",
"Volumes": null,
"WorkingDir": ""
},
"Created": "2015-05-08T22:41:44.74862921Z",
"Driver": "devicemapper",
"ExecDriver": "native-0.2",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/tmp:/tmp"
],
"CapAdd": null,
"CapDrop": null,
"ContainerIDFile": "",
"Devices": [],
"Dns": null,
"DnsSearch": null,
"ExtraHosts": null,
"IpcMode": "",
"Links": null,
"LxcConf": [],
"NetworkMode": "bridge",
"PidMode": "",
"PortBindings": {},
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"RestartPolicy": {
"MaximumRetryCount": 0,
"Name": ""
},
"SecurityOpt": null,
"VolumesFrom": null
},
"HostnamePath": "/var/lib/docker/containers/ddb7b55902cc328612d794570fe9a936d96a9644411e89c4ea116a5fef4c311a/hostname",
"HostsPath": "/var/lib/docker/containers/ddb7b55902cc328612d794570fe9a936d96a9644411e89c4ea116a5fef4c311a/hosts",
"Id": "ddb7b55902cc328612d794570fe9a936d96a9644411e89c4ea116a5fef4c311a",
"Image": "ed5a78b7b42bde1e3e4c2996e02da778882dca78f8919cbd0deb6694803edec3",
"MountLabel": "",
"Name": "/distracted_banach",
"NetworkSettings": {
"Bridge": "docker0",
"Gateway": "172.17.42.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"LinkLocalIPv6Address": "fe80::42:acff:fe11:4",
"LinkLocalIPv6PrefixLen": 64,
"MacAddress": "02:42:ac:11:00:04",
"PortMapping": null,
"Ports": {}
},
"Path": "/bin/bash",
"ProcessLabel": "",
"ResolvConfPath": "/var/lib/docker/containers/ddb7b55902cc328612d794570fe9a936d96a9644411e89c4ea116a5fef4c311a/resolv.conf",
"RestartCount": 0,
"State": {
"Error": "",
"ExitCode": 0,
"FinishedAt": "0001-01-01T00:00:00Z",
"OOMKilled": false,
"Paused": false,
"Pid": 6115,
"Restarting": false,
"Running": true,
"StartedAt": "2015-05-08T22:41:45.367432585Z"
},
"Volumes": {
"/tmp": "/tmp"
},
"VolumesRW": {
"/tmp": true
}
}
]

docker history <image name>将显示烘烤到图像中的层。不幸的是,docker history似乎因其格式和缺乏选择显示内容的选项而步履蹒跚。

你可以通过——no-trunc标志来选择简洁和冗长的格式。

$ docker history drpaulbrewer/spark-worker
IMAGE               CREATED             CREATED BY                                      SIZE
438ff4e1753a        2 weeks ago         /bin/sh -c #(nop) CMD [/bin/sh -c /spark/my-s   0 B
6b664e299724        2 weeks ago         /bin/sh -c #(nop) ADD file:09da603c5f0dca7cc6   296 B
f6ae126ae124        2 weeks ago         /bin/sh -c #(nop) MAINTAINER drpaulbrewer@eaf   0 B
70bcb3ffaec9        2 weeks ago         /bin/sh -c #(nop) EXPOSE 2222/tcp 4040/tcp 60   0 B
1332ac203849        2 weeks ago         /bin/sh -c apt-get update && apt-get --yes up   1.481 GB
8e6f1e0bb1b0        2 weeks ago         /bin/sh -c sed -e 's/archive.ubuntu.com/www.g   1.975 kB
b3d242776b1f        2 weeks ago         /bin/sh -c #(nop) WORKDIR /spark/spark-1.3.1    0 B
ac0d6cc5aa3f        2 weeks ago         /bin/sh -c #(nop) ADD file:b6549e3d28e2d149c0   25.89 MB
6ee404a44b3f        5 weeks ago         /bin/sh -c #(nop) WORKDIR /spark                0 B
c167faff18cf        5 weeks ago         /bin/sh -c adduser --disabled-password --home   335.1 kB
f55d468318a4        5 weeks ago         /bin/sh -c #(nop) MAINTAINER drpaulbrewer@eaf   0 B
19c8c047d0fe        8 weeks ago         /bin/sh -c #(nop) CMD [/bin/bash]               0 B
c44d976a473f        8 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.879 kB
14dbf1d35e28        8 weeks ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   701 B
afa7a164a0d2        8 weeks ago         /bin/sh -c #(nop) ADD file:57f97478006b988c0c   131.5 MB
511136ea3c5a        23 months ago                                                       0 B

这里有一个详细的例子。

docker history --no-trunc=true drpaulbrewer/spark-worker
IMAGE                                                              CREATED             CREATED BY                                                                                                                                                                                                                                                                                                                                                                                                                        SIZE
438ff4e1753a60779f389a3de593d41f7d24a61da6e1df76dded74a688febd64   2 weeks ago         /bin/sh -c #(nop) CMD [/bin/sh -c /spark/my-spark-worker.sh]                                                                                                                                                                                                                                                                                                                                                                      0 B
6b664e29972481b8d6d47f98167f110609d9599f48001c3ca11c22364196c98a   2 weeks ago         /bin/sh -c #(nop) ADD file:09da603c5f0dca7cc60f1911caf30c3c70df5e4783f7eb10468e70df66e2109f in /spark/                                                                                                                                                                                                                                                                                                                            296 B
f6ae126ae124ca211c04a1257510930b37ea78425e31a273ea0b1495fa176c57   2 weeks ago         /bin/sh -c #(nop) MAINTAINER drpaulbrewer@eaftc.com                                                                                                                                                                                                                                                                                                                                                                               0 B
70bcb3ffaec97a0d14e93b170ed70cc7d68c3c9dfb0222c1d360a300d6e05255   2 weeks ago         /bin/sh -c #(nop) EXPOSE 2222/tcp 4040/tcp 6066/tcp 7077/tcp 7777/tcp 8080/tcp 8081/tcp                                                                                                                                                                                                                                                                                                                                           0 B
1332ac20384947fe1f15107213b675e5be36a68d72f0e81153d6d5a21acf35af   2 weeks ago         /bin/sh -c apt-get update && apt-get --yes upgrade     && apt-get --yes install sed nano curl wget openjdk-8-jdk scala     && echo "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64" >>/etc/environment     && export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m"     && ./build/mvn -Phive -Phive-thriftserver -DskipTests clean package     && chown -R spark:spark /spark     && mkdir /var/run/sshd   1.481 GB
8e6f1e0bb1b0b9286947d3a4b443cc8099b00f9670aab1d58654051e06f62e51   2 weeks ago         /bin/sh -c sed -e 's/archive.ubuntu.com/www.gtlib.gatech.edu\/pub/' /etc/apt/sources.list > /tmp/sources.list && mv /tmp/sources.list /etc/apt/sources.list                                                                                                                                                                                                                                                                       1.975 kB
b3d242776b1f1f1ae5685471d06a91a68f92845ef6fc6445d831835cd55e5d0b   2 weeks ago         /bin/sh -c #(nop) WORKDIR /spark/spark-1.3.1                                                                                                                                                                                                                                                                                                                                                                                      0 B
ac0d6cc5aa3fdc3b65fc0173f6775af283c3c395c8dae945cf23940435f2785d   2 weeks ago         /bin/sh -c #(nop) ADD file:b6549e3d28e2d149c0bc84f69eb0beab16f62780fc4889bcc64cfc9ce9f762d6 in /spark/                                                                                                                                                                                                                                                                                                                            25.89 MB
6ee404a44b3fdd3ef3318dc10f3d002f1995eea238c78f4eeb9733d00bb29404   5 weeks ago         /bin/sh -c #(nop) WORKDIR /spark                                                                                                                                                                                                                                                                                                                                                                                                  0 B
c167faff18cfecedef30343ef1cb54aca45f4ef0478a3f6296746683f69d601b   5 weeks ago         /bin/sh -c adduser --disabled-password --home /spark spark                                                                                                                                                                                                                                                                                                                                                                        335.1 kB
f55d468318a4778733160d377c5d350dc8f593683009699c2af85244471b15a3   5 weeks ago         /bin/sh -c #(nop) MAINTAINER drpaulbrewer@eaftc.com                                                                                                                                                                                                                                                                                                                                                                               0 B
19c8c047d0fe2de7239120f2b5c1a20bbbcb4d3eb9cbf0efa59ab27ab047377a   8 weeks ago         /bin/sh -c #(nop) CMD [/bin/bash]                                                                                                                                                                                                                                                                                                                                                                                                 0 B
c44d976a473f143937ef91449c73f2cabd109b540f6edf54facb9bc2b4fff136   8 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list                                                                                                                                                                                                                                                                                                                                                          1.879 kB
14dbf1d35e2849a00c6c2628055030fa84b4fb55eaadbe0ecad8b82df65cc0db   8 weeks ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-rc.d                                                                                                                                                                                                                                                                                                                                                                               && echo 'exit 101' >> /usr/sbin/policy-rc.d    && chmod +x /usr/sbin/policy-rc.d                        && dpkg-divert --local --rename --add /sbin/initctl    && cp -a /usr/sbin/policy-rc.d /sbin/initctl    && sed -i 's/^exit.*/exit 0/' /sbin/initctl                        && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup                        && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean    && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean    && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean                        && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages                        && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes   701 B
afa7a164a0d215dbf45cd1aadad2a4d12b8e33fc890064568cc2ea6d42ef9b3c   8 weeks ago         /bin/sh -c #(nop) ADD file:57f97478006b988c0c68e5bf82684372e427fd45f21cd7baf5d974d2cfb29e65 in /                                                                                                                                                                                                                                                                                                                                  131.5 MB
511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158   23 months ago                                                                                                                                                                                                                                                                                                                                                                                                                                         0 B

您可以通过检查容器、查看JSON输出并比较两个字段来获得哪些卷被特别烘焙到容器中的信息。当你运行docker inspect myContainer时,VolumesVolumesRW字段会给你关于容器中挂载的卷的Volumes3的信息,包括在Dockerfile中使用VOLUME指令挂载的卷,以及在命令行中使用docker run -v命令挂载的卷。然而,你可以通过检查docker inspect JSON输出中的HostConfig.Binds字段,使用docker run -v命令来隔离容器中挂载了哪些卷。为了澄清,这个HostConfig.Binds字段告诉你在你的docker run命令中使用Volumes0选项具体挂载了哪些卷。因此,如果你将这个字段与Volumes字段交叉引用,你将能够使用Dockerfile中的VOLUME指令确定哪些卷被烘焙到容器中。

grep可以像这样完成:

$ docker inspect myContainer | grep -C2 Binds
...
"HostConfig": {
"Binds": [
"/var/docker/docker-registry/config:/registry"
],

和…

$ docker inspect myContainer | grep -C3 -e "Volumes\":"
...
"Volumes": {
"/data": "/var/lib/docker...",
"/config": "/var/lib/docker...",
"/registry": "/var/docker/docker-registry/config"

在我的例子中,你可以看到我已经使用docker run命令中的-v选项将/var/docker/docker-registry/config作为/registry挂载到容器中,并且我已经使用Dockerfile中的VOLUME指令挂载了/data/config卷。容器需要运行以获取此信息,但它需要至少运行一次才能填充docker inspect命令的HostConfig JSON输出。

在docker 1.10中,你现在有了数据卷容器的新命令 (对于常规容器,请参见下一节,对于docker 1.8+):


在docker 1.8.1(2015年8月)中,docker inspect -f '\{\{ .Volumes }}' containerid将是空!

你现在需要检查Mounts,这是一个挂载路径列表,比如:

   "Mounts": [
{
"Name": "7ced22ebb63b78823f71cf33f9a7e1915abe4595fcd4f067084f7c4e8cc1afa2",
"Source": "/mnt/sda1/var/lib/docker/volumes/7ced22ebb63b78823f71cf33f9a7e1915abe4595fcd4f067084f7c4e8cc1afa2/_data",
"Destination": "/home/git/repositories",
"Driver": "local",
"Mode": "",
"RW": true
}
],

如果你想要第一个挂载的路径(例如),那将是(使用索引0):

docker inspect -f '\{\{ (index .Mounts 0).Source }}' containerid

正如迈克·米特注释下面:

漂亮的打印整件事:

 docker inspect -f '\{\{ json .Mounts }}' containerid | python -m json.tool

或者,像评论 by Mitja一样,使用jq命令

docker inspect -f '\{\{ json .Mounts }}' containerid | jq

对于Docker 1.8,我使用:

$ docker inspect -f "\{\{ .Config.Volumes }}" 957d2dd1d4e8
map[/xmount/dvol.01:{}]
$
docker inspect -f '\{\{ json .Mounts }}' containerid | jq '.[]'

显示容器使用的卷的名称和挂载点目的地:

docker container inspect \
-f '\{\{ range .Mounts }}\{\{ .Name }}:\{\{ .Destination }} \{\{ end }}' \
CONTAINER_ID_OR_NAME

这与Docker 1.13兼容。

下面是一行命令来获取正在运行的容器的卷信息:

for contId in `docker ps -q`; do echo "Container Name: "   `docker ps -f "id=$contId" | awk '{print $NF}' | grep -v NAMES`; echo "Container Volume: " `docker inspect -f '\{\{.Config.Volumes}}' $contId`; docker inspect -f '\{\{ json .Mounts }}' $contId  | jq '.[]';   printf "\n"; done

输出是:

root@ubuntu:/var/lib# for contId in `docker ps -q`; do echo "Container Name: "   `docker ps -f "id=$contId" | awk '{print $NF}' | grep -v NAMES`; echo "Container Volume: " `docker inspect -f '\{\{.Config.Volumes}}' $contId`; docker inspect -f '\{\{ json .Mounts }}' $contId  | jq '.[]';   printf "\n"; done


Container Name:  freeradius
Container Volume:  map[]


Container Name:  postgresql
Container Volume:  map[/run/postgresql:{} /var/lib/postgresql:{}]
{
"Propagation": "",
"RW": true,
"Mode": "",
"Driver": "local",
"Destination": "/run/postgresql",
"Source":     "/var/lib/docker/volumes/83653a53315c693f0f31629f4680c56dfbf861c7ca7c5119e695f6f80ec29567/_data",
"Name": "83653a53315c693f0f31629f4680c56dfbf861c7ca7c5119e695f6f80ec29567"
}
{
"Propagation": "rprivate",
"RW": true,
"Mode": "",
"Destination": "/var/lib/postgresql",
"Source": "/srv/docker/postgresql"
}


Container Name:  rabbitmq
Container Volume:  map[]

码头工人版本:

root@ubuntu:~# docker version
Client:
Version:      1.12.3
API version:  1.24
Go version:   go1.6.3
Git commit:   6b644ec
Built:        Wed Oct 26 21:44:32 2016
OS/Arch:      linux/amd64


Server:
Version:      1.12.3
API version:  1.24
Go version:   go1.6.3
Git commit:   6b644ec
Built:        Wed Oct 26 21:44:32 2016
OS/Arch:      linux/amd64

这是我的版本,找到一个docker组合的挂载点。 在使用此备份卷时。< / p >

 # for Id in $(docker-compose -f ~/ida/ida.yml ps -q); do docker inspect -f '\{\{ (index .Mounts 0).Source }}' $Id; done
/data/volumes/ida_odoo-db-data/_data
/data/volumes/ida_odoo-web-data/_data

这是以前解决方案的组合。

对docker-compose用户有用的变体:

docker-compose ps -q | xargs docker container inspect  \
-f '\{\{ range .Mounts }}\{\{ .Name }}:\{\{ .Destination }} \{\{ end }}'

这将非常整洁地输出可解析的音量信息。例子来自我的wordpress docker-compose:

ubuntu@core $ docker-compose ps -q | xargs docker container inspect  -f '\{\{ range .Mounts }}\{\{ .Name }}:\{\{ .Destination }} \{\{ end }}'
core_wpdb:/var/lib/mysql
core_wpcode:/code core_wphtml:/var/www/html

每个容器的输出都包含一行,列出了使用的卷(和挂载点)。改变\{\{.Name}}:\{\{.Destination}}部分来输出你想要的信息。

如果您只想要一个简单的卷列表,则每行一个

$ docker-compose ps -q | xargs docker container inspect  \
-f '\{\{ range .Mounts }}\{\{ .Name }} \{\{ end }}' \
| xargs -n 1 echo
core_wpdb
core_wpcode
core_wphtml

非常适合生成要备份的卷列表。我使用这种技术和Blacklabelops Volumerize来备份docker-compose中所有容器使用的所有卷。voluerize的文档没有调用它,但您不需要在持久容器中使用它,也不需要使用内置工具来启动和停止服务。我更倾向于将备份和服务控制等关键操作留给实际用户(docker之外)。我的备份是由实际的(非docker)用户帐户触发的,使用docker-compose stop停止服务,备份所有正在使用的卷,最后使用docker-compose start重新启动。

如果你想列出所有的容器名称和每个容器的相关卷,你可以尝试这样做:

docker ps -q | xargs docker container inspect -f '\{\{ .Name }} \{\{ .HostConfig.Binds }}'

示例输出:

< p > / opt_rundeck_1 [/ opt / var / lib / mysql: / var / lib / mysql: rw光碟 /var/lib/rundeck/var/storage: / var / lib / rundeck / var /存储:rw光碟 / opt / var / rundeck / . ssh: / var / lib / rundeck / . ssh: rw光碟 / opt / etc / rundeck: / etc / rundeck: rw /var/log/rundeck: / var / log / rundeck: rw / opt / rundeck-plugins: / opt / rundeck-plugins: rw光碟 / opt / var / rundeck: / var / rundeck rw): < / p >

/ opt_r十一k_1 -容器名称

(. .-附在容器上的卷

如果您正在使用pwsh (powershell核心),可以尝试一下

(docker ps --format='\{\{json .}}' |  ConvertFrom-Json).Mounts

你也可以看到下面的容器名称和装载

docker ps --format='\{\{json .}}' |  ConvertFrom-Json | select Names,Mounts

当输出被转换为json时,您可以获得它所具有的任何属性。

我在谷歌上搜了一下,找到了我自己的答案:)我最近的记忆力……对于那些不了解它的人来说,commandlinefu是一个找到并发布这些片段的好地方。

按容器列出docker卷。

docker ps -a --format '\{\{ .ID }}' | xargs -I {} docker inspect -f '\{\{ .Name }}\{\{ printf "\n" }}\{\{ range .Mounts }}\{\{ printf "\n\t" }}\{\{ .Type }} \{\{ if eq .Type "bind" }}\{\{ .Source }}\{\{ end }}\{\{ .Name }} => \{\{ .Destination }}\{\{ end }}\{\{ printf "\n" }}' {}

示例输出。

root@jac007-truserv-jhb1-001 ~/gitlab $ docker ps -a --format '\{\{ .ID }}' | xargs -I {} docker inspect -f '\{\{ .Name }}\{\{ printf "\n" }}\{\{ range .Mounts }}\{\{ printf "\n\t" }}\{\{ .Type }} \{\{ if eq .Type "bind" }}\{\{ .Source }}\{\{ end }}\{\{ .Name }} => \{\{ .Destination }}\{\{ end }}\{\{ printf "\n" }}' {}
/gitlab_server_1


volume gitlab-data => /var/opt/gitlab
volume gitlab-config => /etc/gitlab
volume gitlab-logs => /var/log/gitlab


/gitlab_runner_1


bind /var/run/docker.sock => /var/run/docker.sock
volume gitlab-runner-config => /etc/gitlab-runner
volume 35b5ea874432f55a26c769e1cdb1ee3f06f78759e6f302e3c4b4aa40f3a495aa => /home/gitlab-runner

我们可以不使用-f Go模板语法:

docker inspect <CONTAINER_ID> | jq .[].Mounts

第一个jq操作jq .[]剥离对象{}包装器。

第二个jq操作将返回所有Mount项。

来自Docker文档在这里

.Mounts Names of the volumes mounted in this container.

docker ps -a --no-trunc --format "\{\{.ID}}\t\{\{.Names}}\t\{\{.Mounts}}"

应该工作

使用Type:Source:Destination格式打印mount:

docker container inspect \
-f '\{\{range .Mounts}}\{\{.Type}}:\{\{.Source}}:\{\{.Destination}}\{\{println}}\{\{ end }}' \
<containerId>

使用Type="volume"只打印mount的Source:

docker container inspect \
-f '\{\{range .Mounts}}\{\{ if eq .Type "volume" }}\{\{println .Source }}\{\{ end }}\{\{end}}' \
<containerId>

在docker版本>= 1.8上使用单引号

docker inspect -f '\{\{ .Mounts }}' containerid

导致以下错误-

Template parsing error: template: :1: unclosed action

用双引号代替-

docker inspect -f "\{\{ .Mounts }}" <contained-id>

打印所有容器及其Docker卷:

docker container inspect $(docker container ls -q) \
-f '\{\{$container := .Name}}\{\{range .Mounts}}\{\{if eq .Type "volume"}}\{\{$container}} \{\{.Name}}\{\{"\n"}}\{\{end}}\{\{end}}' \
| grep -v '^$'