yash's array
builtin имеет некоторые параметры, которые работают только с переменными массива.Пример: параметр -d
сообщит об ошибке для переменной, не являющейся массивом:
$ a=123
$ array -d a
array: no such array $a
Таким образом, мы можем сделать что-то вроде этого:
is_array() (
array -d -- "$1"
) >/dev/null 2>&1
a=(1 2 3)
if is_array a; then
echo array
fi
b=123
if ! is_array b; then
echo not array
fi
Этот подход не будет работать, если переменная массива только для чтения . Попытка изменить переменную только для чтения приводит к ошибке:
$ a=()
$ readonly a
$ array -d a
array: $a is read-only
В bash
вы должны использовать массив для хранения путей, прочитанных пользователем. В общем, лучше хранить отдельные строки (пути )отдельно, чем объединять их в одну строку, которую впоследствии нужно будет правильно проанализировать для извлечения исходных составляющих строк.
#!/bin/bash
echo 'Enter paths, one by one followed by Enter. End input with Ctrl+D' >&2
mypaths=()
while IFS= read -r -p 'Path: ' thepath; do
mypaths+=( -v "$thepath:/opt/$thepath" )
done
docker run "${mypaths[@]}" fedora
Здесь пользователю предлагается ввести путь несколько раз, пока он не нажмет Ctrl+D . Введенные пути сохраняются в массиве mypaths
, который расположен таким образом, что docker
может использовать его напрямую.
Как только не останется путей для чтения, вызывается команда docker
. "${mypaths[@]}"
будет расширен до отдельных элементов массива mypaths
. Поскольку записи массива хранятся в том виде, в котором они есть (с -v
в качестве отдельного элемента перед каждой специально отформатированной строкой pathname:/opt/pathname
), это будет правильно интерпретировано оболочкой и docker
.Единственными символами, которые не допускаются в именах путей приведенным выше кодом, являются символы новой строки, поскольку они разделяют строки, считываемые с помощью read
.
Приведенный выше сценарий также принимает ввод, перенаправленный из текстового файла, содержащего один путь на строку ввода.
Обратите внимание, что цитирование важно. Без двойных кавычек вокруг расширений переменных вы не сможете использовать пути, содержащие пробелы, и у вас также могут возникнуть проблемы с путями, содержащими символы, характерные для оболочки.
Связанные:
Для корпусов не-bash
(sh
):
#!/bin/sh
echo 'Enter paths, one by one followed by Enter. End input with Ctrl+D' >&2
set --
while printf 'Path: ' >&2 && IFS= read -r thepath; do
set -- "$@" -v "$thepath:/opt/$thepath"
done
docker run "$@" fedora
Здесь мы используем список позиционных параметров вместо массива (, поскольку массивы, отличные от $@
, обычно недоступны в sh
), но в остальном рабочий процесс идентичен, за исключением явного вывода подсказки. с printf
.
Реализовано предложение в конце комментария Stéphane Chazelas , чтобы сценарий брал пути в своей командной строке, а не считывал их из стандартного ввода. Это позволяет пользователю передавать скрипту произвольные пути, даже те, которые read
не могут быть легко прочитаны или пользователь не может легко печатать на клавиатуре.
Для bash
с использованием массива:
#!/bin/bash
for pathname do
mypaths+=( -v "$pathname:/opt/$pathname" )
done
docker run "${mypaths[@]}" fedora
Для sh
с использованием списка позиционных параметров:
#!/bin/sh
for pathname do
shift
set -- "$@" -v "$pathname:/opt/$pathname"
done
docker run "$@" fedora
Оба они будут выполняться как
./script.sh path1 path2 path3...
#!/bin/bash
echo -n "Enter the Path : "
read path
echo -n "docker run "
echo "${path}" | tr " " "\n" | while read value
do
echo -n "-v ${value}:/opt/${value} "
done
Попробуйте так, имена каталогов не должны содержать пробелов:
#!/bin/bash
echo -n "Enter the Directories, space separated : "
read dirs
docker run $( set -- $dirs; for path; do echo -v $path:/opt/$path/; done ) fedora
Введите что-то вроде foo bar
, и он запустится
docker run -v foo:/opt/foo/ -v bar:/opt/bar/ fedora