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

17

我想使用通配符从容器中选择多个文件,并使用docker cp命令将这些文件从容器复制到docker主机。

我还没有找到是否支持在docker cp命令中使用通配符的信息。

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

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

我遇到一个例子,在其中使用了for循环来选择一些文件,然后将它们发送到容器中,但我想将文件从容器传输到主机,并且希望在Docker主机上完成此操作,因为脚本仅在主机上运行。

使用docker exec首先选择文件,然后使用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
6个回答

8
实际上,您的解决方案只需要稍作调整就可以实现您的目标:
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 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 SPSRS bash -c "ls /opt/tpa/logs/metrics.csv*"中每个匹配字符串都有\r,所以最终cp在容器中找不到文件。
因此,我们使用echo $f | sed 's/\r//g'来消除每个文件名中的\r,这可以让您正常工作。
注意:对于alpine系统,我们需要使用sh替换bash,同时删除-it以避免在alpine中引入彩色打印一些不可见字符,如^[[0;0m等。

它列出了完整路径的文件,但仍然没有显示任何文件,可能在alpine镜像中无法工作?@atline - AATHITH RAJENDRAN
通常情况下,Alpine镜像不包含bash,因此您可以将其更改为sh -c - atline
是的,我在发布之前尝试过了,但没有成功。 - AATHITH RAJENDRAN
node-14-alpine,它有一个sh。 - AATHITH RAJENDRAN
@AATHITHRAJENDRAN 你是正确的,我在alpine上做了错误的实验。在alpine镜像中,它启用了ls的“彩色打印”,这意味着每一行都会有类似于^[[0;0m的控制字符在打印时不可见,但确实会影响程序。我更新了答案以删除-it,现在它适用于alpine和非alpine。 - atline

6

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

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

在上面的例子中,从容器文件夹 /opt/tpa/logs 复制文件到本地机器 /root/testing/ 文件夹。这里将复制/ logs /内的所有文件到本地。诀窍在于使用 -a 选项与 docker cp 命令一起使用。

1
你所指的 -a 的技巧是什么? - not2savvy
这个不起作用,它会在/root/testing目录下创建一个logs/文件夹,就像这样/root/testing/logs/,然后文件将存在其中。--archive,-a 归档模式(复制所有uid/gid信息) - AATHITH RAJENDRAN

2

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

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

本文介绍了 Docker 的 COPY 命令。该命令用于将文件或目录从主机复制到 Docker 镜像中的指定路径。使用 COPY 命令时,可以通过添加多个参数来指定源文件/目录和目标路径。此外,还可以使用通配符指定多个源文件/目录。COPY 命令还支持从 URL 复制文件。


谢谢回复。但是我不能使用Dockerfile。我将文件夹映射为卷,在运行时会拷贝指标数据。由于某些访问限制,我需要将它们拷贝到Docker主机上。 - Lucky Tyagi
嗯,如果在主机上的文件夹和容器中的文件夹之间有一个绑定卷,这样它们就可以同步,而且您就不需要手动复制文件了,这不是更方便吗? - Neekoy

1

Run this inside the container:

dcp() {
  if [ "$#" -eq 1 ]; then
    printf "docker cp %q .\n" "$(hostname):$(readlink -e "$1")"
  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
}

然后选择你想要复制出来的文件:
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 "$1")"
  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 .

那么你甚至不需要别名,它只是一种方便。


0

docker cp 可以接受文件或 tar 归档,因此您可以将作为参数提供的文件列表打包成 tar 归档,将归档返回到标准输出并将其管道传输到 docker cp

#!/bin/bash

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

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

tar cf - $SOURCE | docker cp - $TARGET

0
另一个一行代码: 首先在容器内使用通配符和ls获取所需文件的列表。然后在while循环中将ls的每一行作为docker cp的参数传递:
在您的情况下:
docker exec container bash -c "ls foo/metrics.csv*" | while read line; do docker cp container:/$line /root/metrices_testing/; done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接