如何使用 docker cp 将多个文件从容器复制到主机

How to copy multiple files from container to host using docker cp

我想使用通配符 select 容器目录中的多个文件,并使用 docker cp 将这些文件从容器复制到 docker 主机。

我找不到 docker cp 是否支持使用通配符。

docker cp fd87af99b650:/foo/metrics.csv* /root/metrices_testing/

这导致错误 metrics.csv*: no such file or directory

我遇到了一个示例,其中 for loop 用于 select 一些文件,然后发送到容器,但我想将文件从容器传输到主机,并希望在 docker 主机本身作为脚本 运行 仅在主机上。

首先使用 docker exec 到 select 文件,然后使用 docker cp 复制它们是一个选项。但这是一个两步过程。

有人可以帮我一步完成吗?

编辑:

我试过了。接近一步但仍然失败。

# for f in $(docker exec -it SPSRS bash -c "ls /opt/tpa/logs/metrics.csv*");
     do docker cp SPSRS:$f /root/metrices_testing/;
 done


: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-08:45
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-09:00
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-09:15
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-09:30
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-09:45
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-10:00
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-10:15
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-10:30
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-10:45
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-11:00
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-11:15
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-11:30
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-11:45
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-12:00
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-12:15
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-12:30
: no such file or directory lstat /docker/overlay2/193d2ad0d8d087377e3b96cbfb672b0e39132ae5e961872127614c9396f8c068/merged/opt/SPS_18_5_R1/logs/metrics.csv.2018.07.10-12:45

Docker cp 仍然不支持通配符。但是,您可以通过以下方式在 Docker 文件中使用它们:

COPY hom* /mydir/        # adds all files starting with "hom"
COPY hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

参考:https://docs.docker.com/engine/reference/builder/#copy

其实你的解决方案可以让你的目标只需要一点点改变:

for f in $(docker exec -it SPSRS bash -c "ls /opt/tpa/logs/metrics.csv*"); do docker cp SPSRS:$f /root/metrices_testing/; done

->

for f in $(docker exec -it SPSRS bash -c "ls /opt/tpa/logs/metrics.csv*"); do docker cp SPSRS:`echo $f | sed 's/\r//g'` /root/metrices_testing/; done

这是因为docker exec -it SPSRS bash -c "ls /opt/tpa/logs/metrics.csv*"在每个匹配的字符串中都会有\r,所以最终cp找不到容器中的文件。

所以,我们使用 echo $f | sed 's/\r//g' 去掉每个文件名的 \r,这会让你工作。

Docker cp命令支持复制文件夹中的所有内容

docker cp -a container-id:/opt/tpa/logs/  /root/testing/

在上面的示例中,将文件从容器文件夹 /opt/tpa/logs 复制到本地计算机 /root/testing/ 文件夹。这里 /logs/ 中的所有文件将被复制到本地。这里的技巧是使用 -a 选项以及 docker cp

运行 这个 容器内:

dcp() {
  if [ "$#" -eq 1 ]; then
    printf "docker cp %q .\n" "$(hostname):$(readlink -e "")"
  else
    local archive="$(mktemp -t "export-XXXXX.tgz")"
    tar czf "$archive" "$@" --checkpoint=.52428800
    printf "docker exec %q cat %q | tar xvz -C .\n" "$(hostname)" "$archive"
  fi
}

然后select你要复制出来的文件:

dcp /foo/metrics.csv*

它将在容器内创建一个存档,并为您发出一个命令 运行。 运行 主机上的那个命令。

例如

docker exec 1c75ed99fa42 cat /tmp/export-x9hg6.tgz | tar xvz -C .

或者,我猜你可以在没有临时存档的情况下做到这一点:

dcp() {
  if [ "$#" -eq 1 ]; then
    printf "docker cp %q .\n" "$(hostname):$(readlink -e "")"
  else
    printf "docker exec %q tar czC %q" "$(hostname)" "$PWD"
    printf " %q" "$@"
    printf " | tar xzvC .\n"
  fi
}

将为您生成一个命令,例如:

docker exec 1c75ed99fa42 tar czC /root .cache .zcompdump .zinit .zshrc .zshrc.d foo\ bar | tar xzvC .

那时你甚至不需要别名,这只是一个方便。

docker cp 接受文件或 tar 档案,因此您可以打包 list of files provided as arguments to an tar archive, return the archive to stdout 并通过管道传输到 docker cp.

#!/bin/bash

if [[ "$#" -lt 2 || "" == "-h" || "" == "--help" ]]; then
    printf "Copy files to docker container directory.\n\n"
    echo "Usage: $(basename [=10=]) files... container:directory"
    exit 0
fi

SOURCE="${*%${!#}}"
TARGET="${@:$#}"

tar cf - $SOURCE | docker cp - $TARGET