简体   繁体   English

在这个简单的 Docker 包装器脚本示例中,如何正确传递包含空格的当前工作目录路径?

[英]In this simple Docker wrapper script example, how may one correctly pass a current working directory path which contains spaces?

My Docker wrapper script works as intended when the current working directory does not contain spaces, however there is a bug when it does.当当前工作目录不包含空格时,我的 Docker 包装器脚本按预期工作,但是当它包含时存在一个错误。

I have simplified an example to make use of the smallest official Docker image I could find and a well known GNU core utility.我简化了一个示例,以使用我能找到的最小的官方 Docker 映像和一个众所周知的 GNU 核心实用程序。 Of course this example is not very useful.当然这个例子不是很有用。 In my real world use case, a much more complicated environment is packaged.在我的实际用例中,打包了一个更复杂的环境。

Docker Wrapper Script: Docker 包装脚本:

#!/usr/bin/env bash
##
## Dockerized ls
##

set -eux

# Only allocate tty if one is detected
# See https://stackoverflow.com/questions/911168/how-to-detect-if-my-shell-script-is-running-through-a-pipe
if [[ -t 0 ]]; then
    DOCKER_RUN_OPTIONS+="-i "
fi
if [[ -t 1 ]]; then
    DOCKER_RUN_OPTIONS+="-t "
fi

WORK_DIR="$(realpath .)"

DOCKER_RUN_OPTIONS+="--rm --user=$(id -u $(logname)):$(id -g $(logname)) --workdir=${WORK_DIR} --mount type=bind,source=${WORK_DIR},target=${WORK_DIR}"

exec docker run ${DOCKER_RUN_OPTIONS} busybox:latest ls "$@"

You can save this somewhere as /tmp/docker_ls for example.例如,您可以将其保存为/tmp/docker_ls Remember to chmod +x /tmp/docker_ls记得chmod +x /tmp/docker_ls

Now you are able to use this Dockerized ls in any path which contains no spaces as follows:现在,您可以在任何不包含空格的路径中使用此 Dockerized ls,如下所示:

/tmp/docker_ls -lah
/tmp/docker_ls -lah | grep 'r'

Note that /tmp/docker_ls -lah /path/to/something is not implemented.请注意, /tmp/docker_ls -lah /path/to/something未实现。 The wrapper script would have to be adapted to parse parameters and mount the path argument into the container.包装器脚本必须适应解析参数并将路径参数安装到容器中。

Can you see why this would not work when current working directory path contains spaces?当当前工作目录路径包含空格时,您能明白为什么这不起作用吗? What can be done to rectify it?可以做些什么来纠正它?

Solution:解决方案:

@david-maze's answer solved the problem. @david-maze 的回答解决了这个问题。 Please see: https://stackoverflow.com/a/55763212/1782641请参阅: https : //stackoverflow.com/a/55763212/1782641

Using his advice I refactored my script as follows:根据他的建议,我重构了我的脚本如下:

#!/usr/bin/env bash
##
## Dockerized ls
##

set -eux

# Only allocate tty if one is detected. See - https://stackoverflow.com/questions/911168
if [[ -t 0 ]]; then IT+=(-i); fi
if [[ -t 1 ]]; then IT+=(-t); fi

USER="$(id -u $(logname)):$(id -g $(logname))"
WORKDIR="$(realpath .)"
MOUNT="type=bind,source=${WORKDIR},target=${WORKDIR}"

exec docker run --rm "${IT[@]}" --user "${USER}" --workdir "${WORKDIR}" --mount "${MOUNT}" busybox:latest ls "$@"

If your goal is to run a process on the current host directory as the current host user, you will find it vastly easier and safer to use a host process, and not an isolation layer like Docker that intentionally tries to hide these things from you.如果您的目标是作为当前主机用户在当前主机目录上运行一个进程,您会发现使用主机进程更容易和更安全,而不是像 Docker 这样故意试图向您隐藏这些东西的隔离层。 For what you're showing I would just skip Docker and run对于您所展示的内容,我将跳过 Docker 并运行

#!/bin/sh
ls "$@"

Most software is fairly straightforward to install without Docker, either using a package manager like APT or filesystem-level isolation like Python's virtual environments and Node's node_modules directory.大多数软件在没有 Docker 的情况下安装起来相当简单,要么使用 APT 之类的包管理器,要么使用 Python 的虚拟环境和 Node 的node_modules目录之类的文件系统级隔离。 If you're writing this script then Docker is just getting in your way.如果您正在编写此脚本,那么 Docker 就会妨碍您。


In a portable shell script there's no way to make “a list of words” in a way that keeps their individual wordiness.在可移植的 shell 脚本中,没有办法以保持它们各自冗长的方式制作“单词列表”。 If you know you'll always want to pass some troublesome options then this is still fairly straightforward: include them directly in the docker run command and don't try to create a variable of options.如果你知道你总是想传递一些麻烦的选项,那么这仍然相当简单:将它们直接包含在docker run命令中,不要尝试创建选项变量。

#!/bin/sh
RM_IT="--rm"
if [[ -t 0 ]]; then RM_IT="$RM_IT -i"; fi
if [[ -t 1 ]]; then RM_IT="$RM_IT -t"; fi
UID=$(id -u $(logname))
GID=$(id -g $(logname))

# We want the --rm -it options to be expanded into separate
# words; we want the volume options to stay as a single word
docker run $RM_IT "-u$UID:$GID" "-w$PWD" "-v$PWD:$PWD" \
  busybox \
  ls "$@"

Some shells like ksh, bash, and zsh have array types, but these shells may not be present on every system or environment (your busybox image doesn't have any of these for example).一些 shell,如 ksh、bash 和 zsh 具有数组类型,但这些 shell 可能不会出现在每个系统或环境中(例如,您的 busybox 映像没有任何这些)。 You also might consider picking a higher-level scripting language that can more explicitly pass words into an exec type call.您还可以考虑选择一种更高级的脚本语言,它可以更明确地将单词传递到exec类型调用中。

I'm taking a stab at this to give you something to try: Change this:我正在尝试这个给你一些尝试:改变这个:

DOCKER_RUN_OPTIONS+="--rm --user=$(id -u $(logname)):$(id -g $(logname)) --workdir=${WORK_DIR} --mount type=bind,source=${WORK_DIR},target=${WORK_DIR}"

To this:对此:

DOCKER_RUN_OPTIONS+="--rm --user=$(id -u $(logname)):$(id -g $(logname)) --workdir=${WORK_DIR} --mount type=bind,source='${WORK_DIR}',target='${WORK_DIR}'"

Essentially, we are putting the ' in there to escape the space when the $DOCKER_RUN_OPTIONS variable is evaluated by bash on the 'exec docker' command.本质上,当 $DOCKER_RUN_OPTIONS 变量由 'exec docker' 命令上的 bash 评估时,我们将 ' 放在那里以逃避空间。

I haven't tried this - it's just a hunch / first shot.我还没有尝试过——这只是一种预感/第一次尝试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无论当前/工作目录如何,脚本目录路径 - Script directory path regardless of current/working directory 如何将当前路径的目录名称(带空格)作为 arguments 传递给 bash 脚本? - How to pass current path's directories names (with spaces) as arguments to a bash script? 如何将包含空格的文件路径传递给Gensim LDA Mallet包装器? - How do I pass a file path containing spaces to the Gensim LDA Mallet wrapper? 如何将参数传递给使用空格的docker run - How can one pass an argument to docker run with spaces 如何将当前工作目录设置为 Bash 中脚本的目录? - How can I set the current working directory to the directory of the script in Bash? 如何在Windows的bash脚本的变量中存储当前目录路径? - How to store current directory path in variable from bash script for windows? 如何在当前目录的不同目录访问文件中运行 Python 脚本(参见示例解释问题) - How to run a Python script in a different directory accessing file of current directory(see example explaining issue) 将工作目录更改为当前脚本的目录 - Change working directory to current script's directory 如何检测bash中可能包含空格的空字符串? - How to detect empty string which may include white spaces in bash? 如何将一个 bash 脚本中的 arguments 数组传递给另一个 arguments 有空格的脚本 - How to pass array of arguments in one bash script to another where some arguments have spaces
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM