bash: передача параметра в функцию

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

storm2005
Сообщения: 136

bash: передача параметра в функцию

Сообщение storm2005 »

Необходимо передать параметр в функцию. Параметр - имя переменной.

Код: Выделить всё

#!/bin/sh

_var=
CHECK_NULL_VARIABLE(){
echo "var = $_var"
if [ -z $_var ]; then
        echo variable is not exists
else
        echo "variable is exists"
fi
}
CHECK_NULL_VARIABLE


Код: Выделить всё

var =
variable is not exists



Код: Выделить всё

#!/bin/sh

_var=111
CHECK_NULL_VARIABLE(){
echo "var = $_var"
if [ -z $_var ]; then
        echo variable is not exists
else
        echo "variable is exists"
fi
}
CHECK_NULL_VARIABLE


Код: Выделить всё

var = 111
variable is exists



Код: Выделить всё

#!/bin/sh

_var=111
CHECK_NULL_VARIABLE(){
echo "var = $_var"
echo parametr = $1

if [ -z $1 ]; then
        echo variable is not exists
else
        echo "variable is exists"
fi
}
CHECK_NULL_VARIABLE '$_var'



Код: Выделить всё

var = 111
parametr = $_var
variable is exists


Код: Выделить всё

#!/bin/sh

_var=
CHECK_NULL_VARIABLE(){
echo "var = $_var"
echo parametr = $1
if [ -z $1 ]; then
        echo variable is not exists
else
        echo "variable is exists"
fi
}
CHECK_NULL_VARIABLE '$_var'



Код: Выделить всё

var =
parametr = $_var
variable is exists


Почему последний скрипт говорит, что переменная существует?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: bash: передача параметра в функцию

Сообщение /dev/random »

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

Для косвенного обращения к переменной воспользуйтесь конструкцией ${!var}
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: bash: передача параметра в функцию

Сообщение sgfault »

/dev/random писал(а):
01.04.2013 23:05
Для косвенного обращения к переменной воспользуйтесь конструкцией ${!var}

или eval для sh (${!} вроде не работает в sh). Как-то так

Код: Выделить всё

$ cat ./t.sh
#!/bin/sh

set -euf

x=''
y='a b'
f()
{
    if eval "[ -z \"\$$1\" ]"; then
        echo "Variable '$1' is null or empty."
    else
        echo "Variable '$1' set."
    fi
}
echo "#### f:"
f 'x'
f 'y'
f '$y'
f '"$y"'

f2()
{
    if eval "[ -z \"$1\" ]"; then
        echo "Variable '$1' is null or empty."
    else
        echo "Variable '$1' set."
    fi
}
echo "#### f2:"
f2 '$x'
f2 'y'
f2 '$y'
f2 '"$y"'

f3()
{
    if eval "[ -z $1 ]"; then
        echo "Variable '$1' is null or empty."
    else
        echo "Variable '$1' set."
    fi
}
echo "#### f3:"
f3 '"$x"'
f3 'y'
f3 '$y'
f3 '"$y"'


И результат будет такой:

Код: Выделить всё

$ sh ./t.sh
#### f:
Variable 'x' is null or empty.
Variable 'y' set.
Variable '$y' set.
./t.sh: 1: [: $a: unexpected operator
Variable '"$y"' set.
#### f2:
Variable '$x' is null or empty.
Variable 'y' set.
Variable '$y' set.
./t.sh: 1: [: a: unexpected operator
Variable '"$y"' set.
#### f3:
Variable '"$x"' is null or empty.
Variable 'y' set.
./t.sh: 1: [: a: unexpected operator
Variable '$y' set.
Variable '"$y"' set.


Как видите, каждый из 3-х вариантов срабатывает (кроме правильного) хотя бы на одном неправильном аргументе. Поэтому, из этих 3-х вариантов функции f я бы выбрал первый, потому что, мне кажется, в нем проще всего добавить проверку для аргумента (что он содержит только допустимые в имени переменной символы).
Спасибо сказали:
storm2005
Сообщения: 136

Re: bash: передача параметра в функцию

Сообщение storm2005 »

А подскажите как переданному аргументу задать значение в функции?

Код: Выделить всё

#!/bin/bash

f() {
var=`date`
    if [ -n "$1" ] ; then
        echo "value of [${1}] is: [${!1}]"
    else
        echo "Null parameter passed to this function"
    fi
}
f var


Вот хочу такой вывод

Код: Выделить всё

./_script-test.sh
value of [var] is: [Wed Apr  3 13:59:06 EEST 2013]


Код: Выделить всё

#!/bin/bash

f() {
$1=`date`
#eval $1=`date`
#\"$1\"=`date`
#eval \"$1\"=`date`
    if [ -n "$1" ] ; then
        echo "value of [${1}] is: [${!1}]"
    else
        echo "Null parameter passed to this function"
    fi
}
f var


Получаем такой вывод

Код: Выделить всё

./_script-test.sh: line 5: var=Wed: command not found
value of [var] is: []

Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: bash: передача параметра в функцию

Сообщение /dev/random »

storm2005 писал(а):
03.04.2013 15:06
$1=`date`

declare "$1=`date`"
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: bash: передача параметра в функцию

Сообщение sgfault »

/dev/random писал(а):
03.04.2013 15:20
storm2005 писал(а):
03.04.2013 15:06
$1=`date`

declare "$1=`date`"

или опять же через eval, тк declare, во-первых, тоже кажется нету в sh, и, во-вторых, он может работать как local, и тогда значение переменной будет изменено только внутри функции (а, насколько я понимаю, смысл передачи функции имен переменных именно в том, чтобы предоставить ей возможность изменить глобальные переменные). Как-то так:

Код: Выделить всё

$ sh -euf -c 'v="a"; f() { eval "$1=\$(date)"; }; f v; echo $v'
2013年 4月 3日 水曜日 15:47:28 MSK


Обратите внимание, что _только_ имя переменной подставляется вместо $1 в основном скрипте, а значение команды подставляется уже во-время второго прохода shell expansion-а, который осуществляет eval. Как вы можете легко проверить, это различие принципиальное:

Код: Выделить всё

$ sh -euf -c 'v="a"; f() { eval "$1=$(date)"; }; f v; echo $v'
sh: 1: eval: 4月: not found


Также можно подобрать значение (вместо вывода `date`), чтобы его подстановка в основном скрипте в конструкции с eval-ом привела не к ошибке, а к выполнению произвольной (или, наоборот, нужной для кого-то) команды (типа rm -rf). Пример есть тут Variable assignment in bash `eval` .

А также вот еще весьма запутанные рассуждения на похожую тему Return values from bash function (честно говоря, сам уже не помню, что я там написал :huh: ).


Upd.
Упс, забыл кавычки. Первый пример должен выглядеть так (хотя, вроде бы, в конструкциях вида v=$() кавычки подразумеваются всегда):

Код: Выделить всё

$ sh -euf -c 'v="a"; f() { eval "$1=\"\$(date)\""; }; f v; echo $v'


А вот второй пример добавление кавычек исправит:

Код: Выделить всё

$ sh -euf -c 'v="a"; f() { eval "$1=\"$(date)\""; }; f v; echo $v'
2013年 4月 3日 水曜日 16:13:26 MSK


но это не значит, что кавычки решают эту проблему (подстановка значения в основном скрипте в конструкции с eval-ом): если значение на месте $(date) будет _тоже_ содержать кавычки, то все будет по прежнему. По первой ссылке как раз такой пример (с ls).
Спасибо сказали:
storm2005
Сообщения: 136

Re: bash: передача параметра в функцию

Сообщение storm2005 »

sgfault, спасибо Вам за развернутые ответы.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: bash: передача параметра в функцию

Сообщение /dev/random »

sgfault писал(а):
03.04.2013 16:04
/dev/random писал(а):
03.04.2013 15:20
declare "$1=`date`"

или опять же через eval, тк declare, во-первых, тоже кажется нету в sh, и, во-вторых, он может работать как local, и тогда значение переменной будет изменено только внутри функции (а, насколько я понимаю, смысл передачи функции имен переменных именно в том, чтобы предоставить ей возможность изменить глобальные переменные).

Тогда можно использовать, например, export вместо declare.

С eval нужно обращаться очень и очень осторожно. В выводе date, скорее всего, никаких гадостей не будет, но привычку лучше не вырабатывать. В другой ситуации могло бы быть так:

a=foo
b='$('
c='rm -rf /*)'
eval "$a=\"$b$c\""

и - ой! Вроде и кавычки ставили, а rm -rf /* сработал!

Лучше взять за правило: eval использовать только тогда, когда нет другого выхода.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: bash: передача параметра в функцию

Сообщение sgfault »

/dev/random писал(а):
03.04.2013 16:41
В другой ситуации могло бы быть так:

a=foo
b='$('
c='rm -rf /*)'
eval "$a=\"$b$c\""

и - ой! Вроде и кавычки ставили, а rm -rf /* сработал!

Лучше взять за правило: eval использовать только тогда, когда нет другого выхода.

Действительно, с eval может получиться "ой", но данный пример у вас сработал только потому, что вы использовали eval не так, как я написал в предыдущем посте. Далее я буду называть ваш скрипт t.sh. Так вот, вы подставили значение, которое нужно присвоить переменной foo, в _основном_ скрипте (другими словами, $b$c заменяются на $(rm -rf /*) во время shell expansion, выполняемого при разборе скрипта t.sh). А я писал, что подставлять значение, которое вы хотите присвоить переменной foo, нужно во время _второго_ shell expansion, выполняемого самим eval. И тогда $(rm -rf /*) просто станет значением переменной foo. Вот, смотрите:

Код: Выделить всё

$ cat ./t.sh
#!/bin/sh

set -euf

a=foo
b='$('
c='rm /)'
eval "$a=\"\$b\$c\""
echo "foo='$foo'"

и результат:

Код: Выделить всё

$ sh ./t.sh
foo='$(rm /)'

Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: bash: передача параметра в функцию

Сообщение /dev/random »

sgfault писал(а):
03.04.2013 17:42
...только потому, что вы использовали eval не так, как я написал в предыдущем посте.

Да, действительно, невнимательно прочитал ваш пост. У вас из команды ничто не просочится, даже если заменить команду на "опасную". И вы, как оказалось, даже акцентировали этот момент. Но даже у вас, чтобы eval из безопасного превратился в разрушительный, достаточно одной маленькой опечатки. А экранирование - это всегда такой забор символов, в котором опечатку пропустить очень легко. Так что я по-прежнему настаиваю: когда без eval можно обойтись, без eval нужно обойтись.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: bash: передача параметра в функцию

Сообщение drBatty »

/dev/random писал(а):
03.04.2013 16:41
Лучше взять за правило: eval использовать только тогда, когда нет другого выхода.

+1

а ещё, ИМХО, сама постановка вопроса неправильная. Почему автор не хочет применить тут ассоциативный массив (в сабже упомянут bash, в sh не работает). Это позволит избавится от потенциально опасного eval. Ну и к тому-же, eval это ещё и дополнительные тормоза. А bash - и так не самый быстрый ЯП.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
storm2005
Сообщения: 136

Re: bash: передача параметра в функцию

Сообщение storm2005 »

drBatty писал(а):
04.04.2013 12:37
/dev/random писал(а):
03.04.2013 16:41
Лучше взять за правило: eval использовать только тогда, когда нет другого выхода.

+1

а ещё, ИМХО, сама постановка вопроса неправильная. Почему автор не хочет применить тут ассоциативный массив (в сабже упомянут bash, в sh не работает). Это позволит избавится от потенциально опасного eval. Ну и к тому-же, eval это ещё и дополнительные тормоза. А bash - и так не самый быстрый ЯП.


Для автора главное передать имя переменной в функцию, в функции задать значение переменной и из фуккции передать обратно имя переменной и значение переменной. В качестве ОС у меня opensuse. Как в большинстве линуксов sh - симлинк на bash. Возможные тормоза eval меня не волнуют. Он работает мгновенно в сравнении с задачами которые решаются в основном скрипте.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: bash: передача параметра в функцию

Сообщение drBatty »

storm2005 писал(а):
05.04.2013 20:10
Для автора главное передать имя переменной в функцию, в функции задать значение переменной и из фуккции передать обратно имя переменной и значение переменной.

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

storm2005 писал(а):
05.04.2013 20:10
В качестве ОС у меня opensuse. Как в большинстве линуксов sh - симлинк на bash. Возможные тормоза eval меня не волнуют.

с eval вероятны ошибки, которые ведут к глюкам, тормозам, и дырам. Сама по себе eval работает быстро, дело не в ней.

Решать вам.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: