С GNU grep
вы можете сделать:
grep -Eo '\S+\s+\S+\s+\S+\s*$'
Это позволит сохранить интервал во входных данных. Обратите внимание, что строки, содержащие менее 3 полей, пропускаются.
POSIX эквивалентом будет:
S='[^[:space:]]\{1,\}' s='[[:space:]]\{1,\}'
sed -n "s/$S$s$S$s${S}[[:space:]]*$/\\
&/;s/.*\n//p"
Разбор аргумента может быть утомительным. Я бы посоветовал вам использовать getopt (1). Отсюда вы можете указать один и тот же флаг несколько раз:
datt -p Package1 -p Package2 -p Package3 --build
Если по какой-то причине вы не можете повторно использовать флаг (не уверен, что это будет, но... )вы также можете передать аргумент как отдельный элемент и разбить его на пробел:
datt -p "Package1 Package2 Package3" --build
Обычно разумнее всего перебирать все параметры в одном цикле и размещать их в нужных местах. Обычно я не выполняю обработку из цикла синтаксического анализа аргумента -, но это может иметь смысл, если порядок параметров имеет значение.
. такой цикл (для Bash или zsh):
#!/usr/bin/zsh
packages=()
while [ "$#" -gt 0 ]; do
case $1 in
-p) echo "p option seen...";;
--build) echo "--build option seen after ${#packages[@]} packages...";;
*) echo "adding package '$1'";
packages+=("$1");;
esac
shift;
done
typeset -p packages;
дал бы:
$ zsh dattest.sh -p foo bar doo --build
p option seen...
adding package 'foo'
adding package 'bar'
adding package 'doo'
--build option seen after 3 packages...
typeset -a packages=( foo bar doo )
Для такого разбора проще использовать цикл while и shift
пока массив не станет пустым.
packages=()
while (($#)); do
case $1 in
-p)
while shift; [[ $1 != -* ]]; do
packages+=($1)
done
…
esac
shift
done
Вы можете использовать флаг нижнего индексаi
для выполнения внутреннего цикла в поисках следующей опции. $array[(i)PATTERN]
— индекс первого элемента, соответствующего PATTERN
,с индексами, начинающимися с 1, поэтому вычтите 1, чтобы получить количество оставшихся элементов. Если совпадения для PATTERN
нет, значение равно единице плюс индекс последнего элемента, именно поэтому такой код работает и в этом случае.
packages=()
while (($#)); do
case $1 in
-p) ((n = $@[(i)-*] - 1)); packages+=($@[1,$n]); shift $n;;
…
esac
shift
done
Синтаксис, который вы описываете, не соответствует -стандарту. По этой причине я не рекомендую :это сбивать с толку ваших пользователей. Обычно datt -p Package1 Package2 Package3 --build
делает то же самое, что и datt -p Package1 Package2 --build Package3
.