LinuxForum.Fans
Тема

Обращение к функции из сценария

Автор: OMIXO 21 сообщений 5580 просмотров
#301417

Здравствуйте.
Помогите пожалуйста.
У меня опыт программирования ноль. Hо в связи с желанием перейти на Linux около двух месяцев назад занялся изучением bash по книге David Tansley "Linux и Unix программирование в Shell. Руководство разработчика" 2001 года издания.

Так вот, суть проблемы такова (выполняю все примеры, описанные в книге у себя в Ubuntu):
1. создал файл функции.
2. Загрузил эту функцию в текущий интерпретатор shell.
3. Проверил с помощью команды set, что эта функция появилась в интерпретаторе.
Далее начинается проблема.
4. ИЗ ЭТОГО ЖЕ терминала (консоли) запускаю сценарий, который обращается к этой функции (по описанию в книге сценарий должен без проблем отработать, используя функцию).
5. Строка сценария, содержащая обращение к функции отрабатывается с ошибкой (имя_сценария: номер_строки_сценария: имя_сценария: имя_функции: not found).

Если слепить вкучу сценарий и функцию, то все отрабатывается без проблем. В чем же дело? Сценарий не видит функцию (хотя команда set показывает, что функция установлена) будто они запускаются в каких-то разных оболочках (интерпретаторах)???
Что я не учел и как решается эта проблема?

Заранее благодарен за помощь.

#301419
"OMIXO" написал:
1. создал файл функции.
2. Загрузил эту функцию в текущий интерпретатор shell.

Вы считаете, что этой информации достаточно? Какой файл, какая функция - показывайте.

"OMIXO" написал:
5. Строка сценария, содержащая обращение к функции отрабатывается с ошибкой (имя_сценария: номер_строки_сценария: имя_сценария: имя_функции: not found).

Не нужно в красках рассказывать об ошибках, просто копируйте текст ошибки сюда.

#301422

Файл функции (называется func1) выглядит так:

text
#! /bin/sh
# simple function
# объявляем функцию:
hello ()
{
echo "Привет. Сегодняшняя дата `date`."
}

Сценарий (называется run_func1), который обращается к этой функции выглядит так:

text
#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."

Сообщение об ошибке выглядит так:

./run_func1: 5: ./run_func1: hello: not found

#301424

Полный результат выполнения сценария выглядит так:

text
mix@mix-VirtualBox:~/work/functions/error$ ./run_func1
сейчас будет выполняться функция hello.
./run_func1: 5: ./run_func1: hello: not found
Все. Функция hello выполнена.
#301425

В run_func1 нужно «прочитать» скрипт с функцией, т.е.

text

#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
. func1 # Читаем файл функций, между точкой и именем файла пробел.
# Можно прочитать и так (# убрать)
# source func1
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."
#301427
text
alexander@goblin /tmp $ cat >1.sh <<EOF
> #!/bin/bash
> foo() {
> echo "This is foo()"
> }
> EOF
alexander@goblin /tmp $ cat >2.sh <<EOF
> #!/bin/bash
> foo
> EOF
alexander@goblin /tmp $ . 1.sh
alexander@goblin /tmp $ bash 2.sh
2.sh: line 2: foo: команда не найдена
alexander@goblin /tmp $ . 2.sh
This is foo()

OMIXO, пользуйся тегом code.

поставь set внутрь второго скрипта и увидишь, что новые процессы наследуют только переменные, но не функции...
соответственно можно и через source, как у меня, всё сделать, но это не Ъ... как это всё корректно провернуть пока не придумал...
ИРЛ в любом случае каждый скрипт должен сам сорсить файл с функциями...

#301447

Большое спасибо за оперативные ответы. Я понял как можно обойти эту проблемму, но есть некоторые возражения-рассуждения.
Если я правильно понял, то вся фишка во взависимостях между процессами и подпроцессами.
Но смущают два факта.
1. Автор вышеупомянутой книги приводит многочисленные примеры сценариев, которые обращаются к функциям. И ни водном из них он предварительно не указывает где находится файл функции. Пишет, что достаточно:
а) добавить функцию в интерпретатор shell с помощью команды: . имя_файла_содержащего_функцию или . /имя_файла_содержащего_функцию;
б) проверить с помощью команды set, что функция добавилась;
в) можно обращаться к функции из сценария просто указывая её имя, как непосредственно из командной строки (у меня работает), так и в сценарии (у меня не работает).

Лично у меня такие объяснения сим фактам:
1) информация в книге устарела (издана в 2001);
2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?

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

#301451
"OMIXO" написал:
1) информация в книге устарела (издана в 2001);

Основные принципы актуальны.

"OMIXO" написал:
а) добавить функцию в интерпретатор shell с помощью команды: . имя_файла_содержащего_функцию или . /имя_файла_содержащего_функцию;

Так сделайте это.
Если собираетесь всерьёз заняться программированием в bash, однозначно стоит читать ABS, в частности по интересуещему вас вопросу — http://tldp.org/LDP/abs/html/functions.html

P.S. http://rus-linux.net/MyLDP/BOOKS/abs-guide/flat/abs-book.html

#301457
text
Так сделайте это.

Спасибо за замечание, но я, естественно, перед тем как запускать сценарий добавлял функцию в shell и проверял, что она добавилась с помощью команды set. В самом-самом первом своем обращении я описал порядок выполняемых действий.

За ссылки спасибо, особенно на русском.

#301500
"OMIXO" написал:
Спасибо за замечание, но я, естественно, перед тем как запускать сценарий добавлял функцию в shell и проверял, что она добавилась с помощью команды set.

Честно говоря, не до конца понимаю, что именно вас смущает?

#301507
text
Честно говоря, не до конца понимаю, что именно вас смущает?

Смущает то, что есть два файла:
1 файл функции
2 файл сценари, который обращается к этой функции.

Загружаю функцию в среду интерпретатора shell.
При обращении к функции из командной строки все работает как надо, к функции есть доступ.
При запуске сценария, который должен обратиться к этой функции, получаю ошибку. Нет доступа к функции.

Ват такой вот ребус.

С Вашим (Lupo Alberto) и советом Fat-Zer пока разбираюсь, т. к. получаю разные результаты при работе с разными файлами функций и сценариями. Определюсь с закономерностями получения результатов и обязательно отпишусь.

А пока спасибо за внимание :D

#301510

Определение всех вызываемых функций можете просто добавить в начало (перед их вызовом) скрипта.

#301525

Короче делаю следующие выводы:

1. (самый важный вывод) Ларчик открывался очень просто! *JOKINGLY*

2. Пока самое элегантное решение, кажется, у Fat-Zer:

"Fat-Zer" написал:
alexander@goblin /tmp $ . 2.sh

То есть, когда есть два файла:
а) файл функции
б) файл сценари, который обращается к этой функции
Файл сценария нужно запускать так же как и добавлять функцию в интерпретатор shell, а именно:
<точка><пробел><имя_сценария>. Это и была моя ошибка.

3. Решения Lupo Alberto:

"Lupo Alberto" написал:
#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
. func1 # Читаем файл функций, между точкой и именем файла пробел.
# Можно прочитать и так (# убрать)
# source func1
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."

В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).

На этом считаю указанную проблему решенной. Всем принимавшим участие большое спасибо.

Есть у меня еще один вопрос по проверку условий. Но об этом со следующей недели.

#301534
"OMIXO" написал:
В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).

Что-то вы путаете (или я вас не понимаю) — http://shelr.tv/records/511518a896608005490000d8

#301578
"OMIXO" написал:
2. Пока самое элегантное решение, кажется, у Fat-Zer:

это ни сколь не изящное решение, ибо весь мусор переменных попадёт в среды вызывающего шела...
болей-менее корректно будет вызывать в сабшеле: (. 2.sh)
но это скорее костыль, нежели решение...
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он.

"OMIXO" написал:
1) информация в книге устарела (издана в 2001);

или так, или автор просто не компетентен... я больше склоняюсь ко второму... в любом случае вряд ли на форуме вообще найдётся пара дедушек, которые помнят такие детали тех прекрных времён...

"OMIXO" написал:
2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?

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

"Lupo Alberto" написал:
В моём случае не помогли. Так как, если не запускать  файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).

воистину, что-то тут не так...

#301604

Как я вижу тема оказалась намного интереснее и запутаннее чем я думал. *JOKINGLY*

1)Fat-Zer, если можно поясните что за зверь такой этот "сабшеле" (дочерний процесс shell?) или ссылку на научный труд по этому поводу...
По этой записи:

"Fat-Zer" написал:
. 2.sh

можно определить "саб" этот шелл или "мэйн"? :D

2)

"Fat-Zer" написал:
это ни сколь не изящное решение, ибо весь мусор переменных попадёт в среды вызывающего шела...

Но ведь можно в конце сценария после обращения к функции (когда она будет больше ненужна) написать unset имя_функции и убрать функцию? Правда вы, наверное, имели ввиду не саму функцию, а придуманные в сценарии переменные? Ну, а даже если и попадут переменные, то чем это плохо? В крайнем случае при перезагрузке консоли/среды shell/системы (нужное подчеркнуть) все очистится. Я правильно рассуждаю?

3) На счет этого:

"Fat-Zer" написал:
OMIXO пишет:2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?да, это сработает... но это малость из другой оперы... только это не папки а файлы... и точку в начале имени второга файла забыл...

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

4)

"Fat-Zer" написал:
или так, или автор просто не компетентен... я больше склоняюсь ко второму...

Все-таки в компетентности автора я не склонен сомниваться, т. к. предидущие 3/5 этой книги не вызвали у меня ни одного вопроса. Все предельно просто и понятно (напомню, что мои знания в программировании до этой книги равнялись нулю).

5)И напоследок на счет

"Fat-Zer" написал:
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он.

Если вы наставиете, что это наиболее часто применяемый способ обращения к файлу функции из сценария, то я, пожалуй, еще раз внимательнее его проверю. Может я что-то делал не так.

Спасибо за внимание. *CRAZY*

#301626
"Fat-Zer" написал:
или автор просто не компетентен... я больше склоняюсь ко второму...

Ни в коем случае! Книга — в своём роде классика жанра.

#302133
"OMIXO" написал:
1)Fat-Zer, если можно поясните что за зверь такой этот "сабшеле" (дочерний процесс shell?) или ссылку на научный труд по этому поводу...

man bash, что значат скобки... ну и там про среду исполнения шела... своими словами мне это сложно описать...

"OMIXO" написал:
Но ведь можно в  конце сценария после обращения к функции (когда она будет больше ненужна) написать unset имя_функции и убрать функцию? Правда вы, наверное, имели ввиду не саму функцию, а придуманные в сценарии переменные? Ну, а даже если и попадут переменные, то чем это плохо? В крайнем случае при перезагрузке консоли/среды shell/системы (нужное подчеркнуть) все очистится. Я правильно рассуждаю?

[console]alexander@goblin /tmp $ uptime
02:19:09 up 68 days, 20:43, 2 users, load average: 0.17, 0.08, 0.06[/console]
когда это ещё произойдёт... а т.к. десктоп, то терминалы я не закрываю...
+ потенциальная дыра в безопасности и простой способ прострелить себе ногу...

"Lupo Alberto" написал:
Ни в коем случае! Книга — в своём роде классика жанра.

чего-то я пропустил, что за книга то?

#302252

1. То, что я писал ранее:

"OMIXO" написал:
3. Решения Lupo Alberto:[quote="Lupo Alberto"]#! /bin/sh# simple function# применяем объявленную функцию в сценарии:. func1 # Читаем файл функций, между точкой и именем файла пробел.# Можно прочитать и так (# убрать)# source func1echo "сейчас будет выполняться функция hello."helloecho "Все. Функция hello выполнена."
В моём случае не помогли. Так как, если не запускать  файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1.[/quote]
полностью подтвердилось.

2.
"Fat-Zer" написал:
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он

Вы имеете ввиду, что функция указывается непосредственно в сценарии? Или же этот способ используется для обращения к файлу функции из сценария?

Войдите или зарегистрируйтесь, чтобы ответить.