Bash: Eval и Echo используют вместе

623
M.O.

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

Вот почему я задаю этот вопрос, я хочу знать, можно ли улучшить приведенный ниже код того, как он написан, как его написать. Если неясно, я новичок в bash, но мой сценарий выполняет свою задачу.

Этот код пытается определить переменные s$counter= s1, s2, s3, s4...в терминах ранее определенных переменных s1$jи s2$jс jпомощью строки, которая является элементом списка (все определены ранее).

counter=1  for j in $ do eval s$counter=$(eval "echo \$s1$j") eval s$((counter+1))=$(eval "echo \$s2$j") counter=$((counter+2)) done 

Это сбивает с толку, но со мной. Внутреннее evalзначение $(eval "echo \$s1$j")es означает возвращение значения s1$j. Второе evalзначение eval s$counter =...предназначено для определения переменных.s1, s2, s3, s4 ...

Так примером может быть: скажем, для первого цикла FOOR j=aзатем $(eval "echo \$s1$j") == $s1a, со значением s1a определены ранее в сценарии, например, пусть это будет « s1a=10», так что, когда второй evalоценивается мы имеем команду, которая гласит « s1=10».

Это работает, но может ли что-то случиться, что сделает это возможной угрозой памяти или что-то в этом роде?

Та же идея с этой строкой кода.

eval $(echo "sed -i '$(eval echo '17i$sed17line')' $file") 

где sed17lineто, что я хочу добавить в строке 17 file. Это зависит от того, для чего я хочу использовать скрипт, поэтому я использую его как переменную и, следовательно, почему я использую комбинацию echoи eval.

Опять же, я просто попробовал все, что мог придумать, чтобы это имело смысл, пока результат не достиг того, чего я хотел.

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

2
Bash имеет конструкцию массива http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_10_02.html Как правило, простая обработка списка должна быть тем, что вам нужно. Также достаточно одного eval на строку. Eval просто обрабатывает расширенную строку, как если бы она была в скрипте. T Nierath 5 лет назад 0
Вы правы! Необходим только один eval. Спасибо! M.O. 5 лет назад 0

1 ответ на вопрос

1
Kamil Maciorowski

Хорошо знать, что есть проблемы с eval( этим и этим ) и echo( здесь ). Вы должны избегать eval, это легко злоупотреблять.

Даже если эти команды абсолютно безопасны в ваших конкретных случаях, я советую вам отказаться eval. Ваш код действительно слишком сложен из-за этого.


Ваш первый пример становится намного чище с массивами. Это работает в GNU bash 4.4.12 в моем Debian:

# preparing variables unset -v list s s1 s2 declare -a list=( foo 'X Y' bar baz ) declare -a s declare -A s1=( [foo]='FOO 1' [bar]='BAR 2' [baz]='BAZ beep; eject /dev/sr0' ) declare -A s2=( [foo]='oof oof' [bar]='rab rab' [baz]='zab zab' [X Y]='9')  # your code rewritten, we don't even need a counter for j in "$" do s+=( "$" "$" ) done  # checking contents of s printf '%s\n' "$" 

Подсказка: исследование «индексированных массивов», «ассоциативных массивов» и их использование в bash.

Обратите внимание, что элемент с пробелом ( X Y) не является чем-то особенным для меня; но это сломало бы ваш код. Я также могу иметь BAZ beep; eject /dev/sr0в моем s1; Смею вас установить s1baz='BAZ beep; eject /dev/sr0', иметь bazв своем listмассиве, выполнить ваш код и посмотреть, что произойдет. Это то, на что evalспособен. Теперь представьте, что я поставил rm -rf ~/вместо eject ….


Второй пример может быть значительно упрощен как:

sed -i "17i$sed17line" "$file" 

Похоже, у вас есть некоторый уклон в сторону eval+, echoтак как вы создали хитрое устройство, которое использует их дважды, когда ничего не нужно. Возможно, это потому, что ваши переменные не всегда расширяются до значений, когда вы этого хотите; если это так, исследуйте разницу между одинарными ( ') и двойными кавычками ( ") в bash.

Слава за то, что сомневался и задавал вопрос.

Спасибо! Я думаю, что вы дали мне слишком много информации для обработки, и я буду осторожен, пытаясь получить все это. Я бы не сказал, что у меня есть предвзятость, я бы сказал, что у меня недостаток знаний. Когда я гуглил специально для того, что я пытался сделать, все ответы, которые я нашел на форумах, вроде этого, заключались в использовании `eval` и` echo`. Может быть, именно так, как я думаю, должны быть шаги кода, которые приведут меня к этим ответам, но, тем не менее, они сделали, они работали, и они имели смысл для меня. Сейчас я пытаюсь улучшить код. M.O. 5 лет назад 0
Код имеет очень специфическое использование, поэтому я не беспокоюсь о неправильном использовании `eval`, хотя, вероятно, мне следует это делать. Вы бы сказали, что Eval является портативным? Я сделаю все возможное, чтобы понять, как вы предложили, хотя. M.O. 5 лет назад 0
Все, что наивно использует пользовательский ввод, а затем выполняет его (даже если оно является частью большой строки), может быть использовано для выполнения произвольного кода. Это не должно иметь большого значения, если скрипт не запускается с правами root. Кроме того, распространенным шаблоном является использование `var = $ () `, который выполняет prog как подпроцесс и присваивает свой вывод переменной. В этом случае не нужно eval. T Nierath 5 лет назад 0