Разыменование переменной среды при расширении параметра в сценарии оболочки

Я пытаюсь разыменовать значение переменной среды, используя расширение параметра $@, но похоже, что это не работает.

Мне нужно вызвать сценарий оболочки с определенными аргументами. Список аргументов содержит переменные среды, и ожидается, что переменные среды будут присутствовать там, где должен выполняться сценарий оболочки. Я не знаю заранее список команд, поэтому я расширяю этот список команд, используя$@. Однако сценарий не может отменить ссылку на значение переменных среды.

Минимальная настройка, объясняющая мою проблему, может быть выполнена, как показано ниже.

  • Dockerfile
FROM alpine:3.10

ENV MY_VAR=production

WORKDIR /app

COPY run.sh .

ENTRYPOINT [ "sh", "run.sh" ]
  • run.sh
#!/bin/sh

echo "Value of MY_VAR is" $MY_VAR

echo "Begin"

$@

echo "Done"

Я могу создать образ, используя docker build . -t env-test. Когда я запускаю его, используяdocker run env-test:latest 'echo $MY_VAR', Я получаю следующий результат.

Value of MY_VAR is production
Begin
$MY_VAR
Done

В то время как ожидаемый результат:

Value of MY_VAR is production
Begin
production
Done

SideNote: На самом деле я пытаюсь запустить его, используя файл набора, как показано ниже:

version: '3'

services:
  run:
    image: env-test:latest
    command: echo $$MY_VAR

но он снова дает мне аналогичный результат.

3 ответа

Решение

Расширяя eval Вот простой сценарий bash, который будет использовать eval для оценки строки как последовательности команд bash:

#!/usr/bin/env bash
echo program args:  $@
eval $@

но будьте осторожны, eval сопряжено с опасностями:

https://medium.com/dot-debug/the-perils-of-bash-eval-cc5f9e309cae

Первым делом, $@ он просто напечатает номер аргумента

#!/bin/sh

echo "Value of MY_VAR is" $MY_VAR

echo "Begin"

$@

echo "Done"

$@ = сохраняет все аргументы в виде списка строк

$* = сохраняет все аргументы как одну строку

$# = сохраняет количество аргументов

Что означает $ @ в сценарии оболочки?

Во-вторых, при запуске следующей команды

docker run env-test:latest 'echo $MY_VAR'

Он будет искать $MY_VAR в хост-системе, а не в контейнере.

Чтобы получить доступ к контейнеру env, вы должны передать их как -e MY_VAR=test, а не в качестве аргумента для команды запуска докера, которая будет в ENV в host.

docker run -e MY_VAR=test env-test:latest

Итак, ценность MY_VAR будет test не production.

Чтобы отладить аргумент docker run

export MY_VAR2="value_from_host"

Теперь беги

docker run env-test:latest "echo $MY_VAR2"

поэтому значение будет value_from_host потому что аргумент выбирается у хоста.

Есть еще несколько способов снять шкуру с этой кошки:

      me@computer:~$ docker run -it --rm ubuntu:20.04 bash -c 'echo $HOSTNAME'
e610946f50c1

Здесь мы вызываем bash внутри контейнера для обработки всего, что находится внутри одинарных кавычек, поэтому подстановка и / или расширение переменных применяется не вашей оболочкой, а оболочкой внутри контейнера.

Другой подход:

      me@computer:~$ cat test.sh
#!/bin/bash

echo $HOSTNAME

me@computer:~$ cat test.sh | docker run -i --rm ubuntu:20.04 bash
62ba950a60fe

В этом случае, "подталкивает" содержимое скрипта к контейнер, поэтому он функционально эквивалентен моему первому примеру. Первый метод «чище», однако, если у вас есть более сложный сценарий, многострочные переменные или другие вещи, которые сложно объединить в одну команду, то второй метод - лучший выбор.

Примечание. Имя хоста в каждом примере разное, потому что я использую опция, которая отбрасывает контейнер при выходе. Это замечательно, если вы хотите запустить команду в контейнере, но впоследствии не нужно сохранять контейнер.

Другие вопросы по тегам