Какой способ лучше реализовать print_last_arg
?
#!/bin/sh
print_last_arg () {
eval "echo \${$#}" # this hurts
}
print_last_arg foo bar baz
# baz
(Если бы это было, скажем, #!/usr/bin/zsh
вместо того, #!/bin/sh
чтобы знать, что делать. Моя проблема - найти разумный способ реализовать это #!/bin/sh
.)
РЕДАКТИРОВАТЬ: выше, это только глупый пример. Моя цель не в том, чтобы напечатать последний аргумент, а в том, чтобы иметь возможность ссылаться на последний аргумент в функции оболочки.
EDIT2: я прошу прощения за такой неясный вопрос. Я надеюсь сделать это правильно на этот раз.
Если бы это было /bin/zsh
вместо /bin/sh
, я мог бы написать что-то вроде этого
#!/bin/zsh
print_last_arg () {
local last_arg=$argv[$#]
echo $last_arg
}
Выражение $argv[$#]
является примером того, что я описал в своем первом EDIT как способ ссылки на последний аргумент в функции оболочки .
Поэтому я действительно должен был написать свой оригинальный пример так:
print_last_arg () {
local last_arg=$(eval "echo \${$#}") # but this hurts even more
echo $last_arg
}
... чтобы было ясно, что то, что я ищу, - это менее ужасная вещь, которую можно поставить справа от задания.
Однако обратите внимание, что во всех примерах к последнему аргументу обращаются неразрушающим образом . Таким образом, доступ к последнему аргументу оставляет позиционные аргументы в целом без изменений.
источник
var=$( eval echo \${$#})
кeval var=\${$#}
- два не похожи.shift
иset -- ...
основанные решения могут быть разрушительными, если они не используются в функциях, где они также безвредны.eval "var=\${$#}"
по сравнению с тем,var=${arr[evaled index]}
за исключением того, что$#
это гарантированное безопасное значение. зачем копировать весь набор, а затем уничтожать его, когда вы можете просто индексировать его напрямую?Ответы:
... либо напечатает строку,
the last arg is
за которой следуют <пробел> , значение последнего аргумента и завершающий <newline>, если есть хотя бы 1 аргумент, либо для нулевых аргументов он вообще ничего не напечатает.Если вы сделали:
... тогда либо вы присвоите значение последнего аргумента переменной оболочки,
$lastarg
если есть хотя бы один аргумент, либо вообще ничего не сделаете. В любом случае, вы бы сделали это безопасно, и я думаю, что он должен быть переносимым даже для раковины Олд Борн.Вот еще один, который будет работать аналогичным образом, хотя он требует двойного копирования всего массива arg (и требует использования
printf
in$PATH
для оболочки Bourne) :источник
${1+":"} return
сразу - потому что, кто хочет, чтобы она что-то делала или рисковала побочными эффектами любого рода, если ее вызывали даром? Математика хороша для того же - если вы можете быть уверены, что вы можете расширить положительное целое число, вы можетеeval
весь день.$OPTIND
отлично подходит для этого.Вот упрощенный способ:
(обновлено на основе замечания @ cuonglm о том, что оригинал не прошел, если не было передано ни одного аргумента; теперь это отображает пустую строку -
else
при желании измените это поведение в предложении)источник
echo "$# - 1" | bc
Приведенный пример вступительного поста (позиционные аргументы без пробелов):
По умолчанию
IFS=' \t\n'
, как насчет:Для более безопасного расширения
"$*"
установите IFS (per @ StéphaneChazelas):Но приведенное выше не удастся, если ваши позиционные аргументы могут содержать пробелы. В этом случае используйте это вместо:
Обратите внимание, что эти методы избегают использования
eval
и не имеют побочных эффектов.Протестировано на shellcheck.net
источник
$IFS
- это пробел.IFS=' '
здесь было просто дать понять, что оно используется для расширения"$*"
.Хотя этому вопросу чуть больше двух лет, я подумал, что поделюсь несколько компактным вариантом.
Давайте запустим это
Расширение параметров оболочки Bash .
редактировать
Еще более лаконично:
echo "${@: -1}"
(Следи за пространством)
Источник
Протестировано на macOS 10.12.6, но также должно возвращать последний аргумент для большинства доступных * nix-вариантов ...
Болит гораздо меньше
¯\_(ツ)_/¯
источник
echo "${*: -1}"
чтоshellcheck
не будет жаловаться.${array:n:m:}
это расширение. (вопрос явно упоминается/bin/sh
)POSIXly:
(Этот подход также работает в старой оболочке Bourne)
С другими стандартными инструментами:
(Это не будет работать со старым
awk
, которого не былоARGV
)источник
awk
также может быть старый awk, которого не былоARGV
.awk
подход, или используйте другой простойfor
цикл, как другие, или передавая их функции.Это должно работать с любой POSIX-совместимой оболочкой и с прежней POSIX-оболочкой Solaris Bourne:
и вот функция, основанная на том же подходе:
PS: не говорите мне, что я забыл фигурные скобки вокруг тела функции ;-)
источник
in ...
вfor
цикле, так и отсутствие фигурных скобок вокругif
оператора, используемого в качестве тела функции. Смотритеfor_clause
иcompound_command
в pubs.opengroup.org/onlinepubs/9699919799 .Из "Unix - Часто задаваемые вопросы"
(1)
Если количество аргументов может быть равно нулю, тогда
$0
будет присвоен нулевой аргумент (обычно это имя скрипта)$last
. Это причина, если.(2)
(3)
Чтобы избежать вывода пустой строки при отсутствии аргументов, замените
echo "$last"
for:Нулевой счетчик аргументов избегается
if [ $# -gt 0 ]
.Это не точная копия того, что находится по ссылке на странице, некоторые улучшения были добавлены.
источник
Это должно работать на всех системах с
perl
установленным (так большинство UNICES):Хитрость заключается в том, чтобы использовать ,
printf
чтобы добавить\0
после каждого аргумента оболочки , а затемperl
«s-0
переключатель , который устанавливает свой разделитель в NULL. Затем мы перебираем ввод, удаляем\0
и сохраняем каждую NULL-концевую строку как$l
.END
Блок (это то , что}{
есть) будет выполняться после того, как все входные данные были считаны так распечатывает последнюю «линию»: последний аргумент оболочки.источник
sed
,awk
илиperl
тогда это может быть ценной информацией в любом случае. Тем не менее, вы можете сделать то же самое сsed -z
современными версиями GNU.Вот версия с использованием рекурсии. Не знаю, насколько это соответствует POSIX ...
источник
Простая концепция, без арифметики, без цикла, без оценки , просто функции.
Помните, что у оболочки Борна не было арифметики (нужна внешняя
expr
). Если вы хотите получить свободный арифметический,eval
свободный выбор, это вариант. Необходимые функции означают SVR3 или выше (без перезаписи параметров).Посмотрите ниже для более надежной версии с printf.
Эта структура вызова
printlast
является фиксированной , аргументы должны быть установлены в списке аргументов оболочки$1
,$2
и т.д. (стек аргумент) и вызов осуществляется как данность.Если список аргументов необходимо изменить, просто установите их:
Или создайте более простую в использовании функцию (
getlast
), которая могла бы разрешать общие аргументы (но не так быстро, аргументы передаются два раза).Обратите внимание, что аргументы (
getlast
или все, что включено в$@
printlast) могут содержать пробелы, переводы строки и т. Д. Но не NUL.Лучше
Эта версия не печатает,
0
когда список аргументов пуст, и использует более надежный printf (отступите,echo
если внешнийprintf
не доступен для старых оболочек).Используя EVAL.
Если оболочка Bourne еще старше и нет функций, или если по какой-то причине использование eval является единственным вариантом:
Чтобы напечатать значение:
Чтобы установить значение в переменной:
Если это нужно сделать в функции, аргументы необходимо скопировать в функцию:
источник
eval
?for loop
илиwhile loop
?echo "Hello"
, поскольку ЦП должен считывать ячейки памяти в цикле. Опять же: мой код не имеет добавленных циклов.for
,while
илиuntil
петли. Вы видите какой-for
while
либоuntil
цикл или цикл, написанный в коде? Нет? Тогда просто примите факт, примите это и учитесь.Этот комментарий предложил использовать очень элегантно:
источник