В этом простом примере сценария-оболочки Docker, как правильно передать текущий путь к рабочей директории, содержащий пробелы? - PullRequest
1 голос
/ 19 апреля 2019

Скрипт My Docker работает так, как задумано, когда текущий рабочий каталог не содержит пробелов, однако при этом возникает ошибка.

Я упростил пример, чтобы использовать наименьшее официальное изображение Docker Iмог бы найти и хорошо известную утилиту ядра GNU.Конечно, этот пример не очень полезен.В моем случае использования в реальном мире упаковывается гораздо более сложная среда.

Скрипт Docker Wrapper:

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

set -eux

# Only allocate tty if one is detected
# See /758520/kak-opredelit-rabotaet-li-moi-stsenarii-obolochki-cherez-kanal
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 "$@"

Вы можете сохранить это где-нибудь как /tmp/docker_ls дляпример.Не забудьте chmod +x /tmp/docker_ls

Теперь вы можете использовать Dockerized ls в любом пути, который не содержит пробелов, как указано ниже:

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

Обратите внимание, что /tmp/docker_ls -lah /path/to/something не реализовано.Сценарий оболочки должен быть адаптирован для анализа параметров и монтирования аргумента пути в контейнер.

Можете ли вы понять, почему это не будет работать, если текущий путь к рабочей директории содержит пробелы?Что можно сделать, чтобы исправить это?

Решение:

@ Дэвид-лабиринт решил проблему.Пожалуйста, смотрите: https://stackoverflow.com/a/55763212/1782641

Используя его советы, я переработал свой сценарий следующим образом:

#!/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 "$@"

Ответы [ 2 ]

1 голос
/ 19 апреля 2019

Если ваша цель - запустить процесс в текущем каталоге хоста от имени текущего хост-пользователя, вам будет гораздо проще и безопаснее использовать хост-процесс, а не слой изоляции, такой как Docker, который намеренно пытается скрыть эти вещиот тебя.Для того, что вы показываете, я бы просто пропустил Docker и запустил

#!/bin/sh
ls "$@"

Большинство программ довольно просто установить без Docker, используя менеджер пакетов, такой как APT, или изоляцию на уровне файловой системы, такую ​​как виртуальные среды Python и Node.node_modules каталог.Если вы пишете этот сценарий, то Docker просто мешает вам.


В сценарии переносимой оболочки нет способа составить «список слов» таким образом, чтобы сохранить их индивидуальность.Если вы знаете, что вам всегда захочется передать некоторые проблемные параметры, это все еще довольно просто: включите их непосредственно в команду 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 "$@"

Некоторые оболочки, такие как ksh, bash и zsh, имеют типы массивов, но эти оболочки могут отсутствовать в каждой системе или среде (например, в вашем образе busybox нет ни одного из них).Вы также можете рассмотреть возможность выбора языка сценариев более высокого уровня, который может более явно передавать слова в вызов типа exec.

0 голосов
/ 19 апреля 2019

Я пытаюсь дать вам кое-что попробовать: Изменить это:

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

К этому:

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

По сути, мы помещаем туда ', чтобы избежать пробела, когда переменная $ DOCKER_RUN_OPTIONS оценивается bash по команде' exec docker '.

Я не пробовал это - это просто догадка / первый выстрел.

...