Почему я получаю неожиданный вывод при попытке выполнить цикл по количеству раз, введенному пользователем?

Почему я получаю неожиданный вывод при попытке выполнить цикл по количеству раз, введенному пользователем?

Я пишу этот скрипт оболочки bash:

#!/bin/bash

declare -i N
read N
for i in {1..$N}
do
  echo "Number: $i"
done

(Я считаю, declare -i Nчто это Nцелое число)

Однако при запуске я получаю следующий вывод:

>vim new.sh
>chmod +x passgen.sh
>./passgen.sh
15
Number: {1..15}

Здесь я хочу взять лимит у пользователя, а затем запустить цикл.

решение1

От man bash:

Порядок расширений следующий: расширение фигурных скобок; расширение тильды, расширение параметров и переменных, арифметическое расширение и подстановка команд (выполняется слева направо); разделение слов; и расширение имени пути.

Как вы видите, сначала идет раскрытие скобок, так что, по-видимому, в вашей задаче оно пропущено. Я бы вместо этого использовал другой цикл.

решение2

Хотя проблема с расширением скобок уже была обозначена, я просто прокомментирую:

(Я считаю, что declare -i N делает N целым числом)

Я отвечу, да, это так, и это проблема, поскольку это делает уязвимость инъекции команд. С этим набором целочисленных атрибутов, всякий раз, когда переменной присваивается значение, это значение интерпретируется как арифметическое выражение.

Если пользователь введет a[$(reboot)]это readприглашение, это вызовет, например, попытку перезагрузки.

Это общая проблема с bash, zshи kshвсякий раз, когда оцениваются арифметические выражения. Даже использование for (( i = 1; i <= N; i++ ))формы в стиле ksh93 (с или без declare -i N) было бы проблемой, поскольку содержимое Nвсе равно оценивается в этом арифметическом контексте.

for i in {1..$N}будет нормально (без declare -i N) в ksh, zsh или yash -o braceexpand(будет зацикливаться на бессмысленной фразе, но не приведет к уязвимости внедрения команд), или вы можете использовать стандартный shсинтаксис, при условии, что ваша shреализация не основана на ksh.

#! /bin/sh -
IFS= read -r N
i=1; while [ "$i" -lt "$N" ]; do
  printf '%s\n' "Number: $n"
done

ksh's [по-прежнему обрабатывает операнд -ltкак арифметические выражения, поэтому все равно будет вносить уязвимости инъекции команд. Не используйте [[ $i -lt $N ]]или (( i < N ))в bash/ zsh/ ksh, которые также имеют проблему.

Или вы можете использовать awk/ perlили любой подходящий язык программирования для реализации цикла, или вы можете сначала очистить входные данные.

Связанный контент