Обычно я нахожу решения для более сложных задач в сценариях оболочки, разбивая более длинные команды на последовательность простых команд. Вот тот случай, когда я не смог найти решение с помощью этого метода.
Мне нужно выполнить расчеты, чтобы знать, какой аргумент мне нужно использовать. Как только он у меня появится, я смогу его вызвать, как здесь (упрощенная, общая версия):
1 i=1
2 k=$(( i+1 ))
3 echo $i
4 echo $k
5 echo "${!i}"
6 echo "${!k}"
Как и следовало ожидать:
$ ./testo A B
1
2
A
B
Во-первых, я нашел это выражение с восклицательным знаком где-то в Интернете и был рад этому, потому что оно работает. Однако я не понимаю, что он делает.
На мой взгляд, ! обычно означает not, но здесь это точно работает. Без, однако, это не так. Я хотел бы узнать, почему.
Теперь я хотел упростить код и удалить, как мне кажется, ненужную вторую строку, заменив k в последней строке арифметическим выражением, как в строке 2.
К моему удивлению, ни одна из моих попыток скопировать выражение для k из второй строки на самом деле не сработала:
1 i=1
2 k=$(( i+1 ))
3 echo $i
4 echo $k
5 echo "${!i}"
6 echo "${!k}"
7 echo "${!$(( i+1 ))}"
8 echo "${!(( i+1 ))}"
9 echo "${!(( $i+1 ))}"
, как можно увидеть здесь:
./testo: line 7: ${!$(( i+1 ))}: bad substitution
./testo: line 8: ${!(( i+1 ))}: bad substitution
./testo: line 9: ${!(( $i+1 ))}: bad substitution
Что я делаю не так; какая будет хорошая замена; почему я не могу просто скопировать выражение для k из строки 2 на место k в строке 6?
Я действительно видел это, читал вдоль и поперек, но не мог понять. Как i или k можно приравнять к prefix* или около того? В этом документе есть множество примеров, но ничего по этой теме. В любом случае спасибо
Помимо моего ответа ниже, я также отредактировал ваши теги. Я удалил оболочку и добавил bash, так как это применимо только к оболочке bash. Если вы работаете в любой другой оболочке, мой ответ ниже неверен, и вам нужно будет указать (с помощью правильного тега), на какую оболочку вы ориентируетесь.





Из официальной документации (пункт 4):
Если первым символом параметра является восклицательный знак (!), а параметр не является ссылкой на имя, это вводит уровень косвенности. Bash использует значение, полученное путем расширения оставшейся части параметра, в качестве нового параметра; Затем оно расширяется, и это значение используется в остальной части расширения, а не в расширении исходного параметра. Это известно как косвенное расширение.
Итак, в вашем примере "${!i}", где i имеет значение 1, после косвенного расширения становится "$1". $1 — это первый аргумент, передаваемый в ваш пример сценария, A в вашем случае. Вот что выдает эхо.
Другие ваши примеры "${!$(( i+1 ))}" и «${!(( i+1 ))}" с использованием косвенного расширения становятся бессмысленными. $(( i+1 )) и (( i+1 )) являются недопустимыми именами параметров, поэтому вы получаете неверную ошибку замены. Обратите внимание, что «вещь» после ! снова не оценивается, он рассматривается как имя параметра буквально.
Расширения не являются макросами. Для расширения вам нужна переменная. Вы не можете его оптимизировать. Все в порядке, представленный код идеален.
Я не понимаю, что это делает
Косвенное расширение описано в руководстве по bash. См. Что такое непрямое расширение? Что означает ${!var*}? и https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html .
и удалите, как мне кажется, ненужную вторую строку, заменив k в последней строке арифметическим выражением, как в строке 2
Нет возможности.
Что я делаю не так
Ничего.
какая будет хорошая замена
k=$(( i+1 )); echo "${!k}" идеальная замена
почему я не могу просто скопировать выражение для k из строки 2 на место k в строке 6?
Расширения не являются макросами. ${! должен расширить переменную. Вы не можете объединять расширения в цепочку, они просто не анализируются и не реализуются таким образом.
Прочтите Расширение параметров оболочки. Примерно на середине страницы он попадает на
${!prefix*}.