Можно ли ссылаться на индексы в $@
? Я не могу найти какую-либо ссылку для использования, как, например, в вики-сайте GrayCat , и Руководство по расширенному написанию сценариев и другие присваивают его другой переменной, прежде чем изменять ее.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
Цель - СУХОЙ : первый аргумент используется для одной цели , а остальные - для чего-то другого, и я бы хотел избежать дублирования либо кода для нормализации, $@
массива, либо создания для этого отдельной функции (хотя на этом дык это наверное самый простой выход).
Пояснение: цель состояла в том, чтобы изменить значения переменной длины, $@
чтобы облегчить отладку кода . Текущая версия мне не нравится, хотя она работает даже для странных путей, таких как
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Обновление : похоже, что это невозможно. Теперь код использует дублирование кода и данных, но по крайней мере это работает:
path_common()
{
# Get the deepest common path.
local common_path="$(echo -n "${1:-}x" | tr -s '/')"
common_path="${common_path%x}"
shift # $1 is obviously part of $1
local path
while [ -n "${1+defined}" ]
do
path="$(echo -n "${1}x" | tr -s '/')"
path="${path%x}"
if [[ "${path%/}/" = "${common_path%/}/"* ]]
then
shift
else
new_common_path="${common_path%/*}"
[ "$new_common_path" = "$common_path" ] && return 1 # Dead end
common_path="$new_common_path"
fi
done
printf %s "$common_path"
}
Bounty идет к любому , кто может избавиться от дублирования кода коллапса дубликатов слэшей или дублирования данных , чтобы держать $1
и другие параметры, или оба, сохраняя при этом коде разумного размера и успеха всех модульных тестов:
test "$(path_common /a/b/c/d /a/b/e/f; echo x)" = /a/bx
test "$(path_common /long/names/foo /long/names/bar; echo x)" = /long/namesx
test "$(path_common / /a/b/c; echo x)" = /x
test "$(path_common a/b/c/d a/b/e/f ; echo x)" = a/bx
test "$(path_common ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
test "$(path_common $'\n/\n/\n' $'\n/\n'; echo x)" = $'\n/\n'x
test "$(path_common --/-- --; echo x)" = '--x'
test "$(path_common '' ''; echo x)" = x
test "$(path_common /foo/bar ''; echo x)" = x
test "$(path_common /foo /fo; echo x)" = x
test "$(path_common $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n' $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'; echo x)" = $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'x
test "$(path_common /foo/bar //foo//bar//baz; echo x)" = /foo/barx
test "$(path_common foo foo; echo x)" = foox
test "$(path_common /fo /foo; echo x)" = x
Ответы:
POSIX
Чтобы нормализовать косые черты во всех параметрах, я буду использовать трюк с вращающимся аргументом: сдвинуть
$1
, преобразовать его и поместить результат в конец списка параметров. Если вы делаете это столько раз, сколько есть параметров, вы преобразуете все параметры и возвращаете их в порядок.Для второй части кода я изменил вашу логику, чтобы она была менее запутанной: внешний цикл перебирает параметры, а внутренний цикл перебирает компоненты пути.
for x; do … done
перебирает позиционные параметры, это удобная идиома Я использую POSIX-совместимый способ сопоставления строки с шаблоном:case
конструкцией.Протестировано с dash 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Примечание: в bash 4.1.5, по-видимому, есть ошибка (не в 3.2): если шаблон случая
"${common_path%/}"/*
один из тестов не пройден.баш, кш
Если вы используете bash (или ksh), вы можете использовать массивы - я не понимаю, почему вы, похоже, ограничиваетесь позиционными параметрами. Вот версия, которая использует массив. Я должен признать, что он не особенно понятен, чем версия POSIX, но он избегает начального перемешивания n ^ 2.
Для части нормализации слэша я использую конструкцию ksh93,
${foo//PATTERN/REPLACEMENT}
чтобы заменить все вхожденияPATTERN
в$foo
byREPLACEMENT
. Шаблон+(\/)
должен соответствовать одному или нескольким слешам; под bash,shopt -s extglob
должен быть в силе (эквивалентно, начать bash сbash -O extglob
). Конструкцияset ${!a[@]}
устанавливает позиционные параметры в список индексов массиваa
. Это обеспечивает удобный способ перебора элементов массива.Для второй части я использую ту же логику цикла, что и версия POSIX. На этот раз я могу использовать,
[[ … ]]
так как все оболочки, предназначенные здесь, поддерживают это.Протестировано с bash 3.2.39, bash 4.1.5, ksh 93s +.
ЗШ
К сожалению, в zsh отсутствует
${!array[@]}
возможность запуска версии ksh93 как есть. К счастью, у zsh есть две особенности, которые делают первую часть легкой. Вы можете индексировать позиционные параметры, как если бы они были@
массивом, поэтому нет необходимости использовать промежуточный массив. Кроме того, zsh имеет конструкцию итерации массива :"${(@)array//PATTERN/REPLACEMENT}"
выполняет замену шаблона для каждого элемента массива по очереди и вычисляет массив результатов (что приводит к путанице в двойных кавычках, даже если результат состоит из нескольких слов; это обобщение"$@"
). Вторая часть практически не изменилась.Контрольные примеры
Мои решения минимально проверены и прокомментированы. Я изменил синтаксис ваших тестовых случаев, чтобы анализировать их в оболочках, в которых их нет,
$'…'
и сообщать о сбоях более удобным способом.источник
Почему бы вам просто не использовать $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. и так далее? Это еще более DRY -er , чем то , что вы пытаетесь сделать :)
Подробнее об отношении между $ number и $ @:
$ @ можно рассматривать как сокращение для «всех элементов массива, содержащих все аргументы»
Таким образом, $ @ - это своего рода сокращение от $ {args [@]} (здесь args - это «виртуальный» массив, содержащий все аргументы - не реальная переменная, заметьте)
$ 1 - это $ {args [1]}, $ 2 - это $ {args [2]} и так далее.
Когда вы нажмете [9], используйте фигурную скобку: $ {10} равно $ {args [10]}, $ {11} равно $ {args [11]} и так далее.
Косвенно использовать аргумент командной строки
Пример:
источник
${args[$i]}
.Я думаю, что вы хотите
shift
источник
Я не совсем понимаю, почему вы не просто используете $ 1 $ 2 и т. Д., Но ... Это может удовлетворить ваши потребности.
вывод
set
Произведения всего, что следует за ним, для создания $ 1, $ 2 .. и т. д. Это, конечно, переопределит исходные значения, так что просто помните об этом.источник
eval
некоторые считают этоevil
... (может быть, это из-за написания :) ... Еслиeval
«плохо», то равно ли $ {! Var} «плохо»? ... Для меня это всего лишь часть языка и полезная часть, но я определенно предпочитаю $ {!Примечание. Я поддерживаю пробелы в именах файлов.
Я добавил тестовый пример для имен файлов с пробелами и исправил 2 теста, в которых отсутствовал ведущий /
источник