Здравствуйте.
Помогите пожалуйста.
У меня опыт программирования ноль. Hо в связи с желанием перейти на Linux около двух месяцев назад занялся изучением bash по книге David Tansley "Linux и Unix программирование в Shell. Руководство разработчика" 2001 года издания.
Так вот, суть проблемы такова (выполняю все примеры, описанные в книге у себя в Ubuntu):
1. создал файл функции.
2. Загрузил эту функцию в текущий интерпретатор shell.
3. Проверил с помощью команды set, что эта функция появилась в интерпретаторе.
Далее начинается проблема.
4. ИЗ ЭТОГО ЖЕ терминала (консоли) запускаю сценарий, который обращается к этой функции (по описанию в книге сценарий должен без проблем отработать, используя функцию).
5. Строка сценария, содержащая обращение к функции отрабатывается с ошибкой (имя_сценария: номер_строки_сценария: имя_сценария: имя_функции: not found).
Если слепить вкучу сценарий и функцию, то все отрабатывается без проблем. В чем же дело? Сценарий не видит функцию (хотя команда set показывает, что функция установлена) будто они запускаются в каких-то разных оболочках (интерпретаторах)???
Что я не учел и как решается эта проблема?
Заранее благодарен за помощь.
Обращение к функции из сценария
1. создал файл функции.
2. Загрузил эту функцию в текущий интерпретатор shell.
Вы считаете, что этой информации достаточно? Какой файл, какая функция - показывайте.
5. Строка сценария, содержащая обращение к функции отрабатывается с ошибкой (имя_сценария: номер_строки_сценария: имя_сценария: имя_функции: not found).
Не нужно в красках рассказывать об ошибках, просто копируйте текст ошибки сюда.
Файл функции (называется func1) выглядит так:
#! /bin/sh
# simple function
# объявляем функцию:
hello ()
{
echo "Привет. Сегодняшняя дата `date`."
}
Сценарий (называется run_func1), который обращается к этой функции выглядит так:
#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."
Сообщение об ошибке выглядит так:
./run_func1: 5: ./run_func1: hello: not found
Полный результат выполнения сценария выглядит так:
mix@mix-VirtualBox:~/work/functions/error$ ./run_func1
сейчас будет выполняться функция hello.
./run_func1: 5: ./run_func1: hello: not found
Все. Функция hello выполнена.В run_func1 нужно «прочитать» скрипт с функцией, т.е.
#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
. func1 # Читаем файл функций, между точкой и именем файла пробел.
# Можно прочитать и так (# убрать)
# source func1
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."
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, как у меня, всё сделать, но это не Ъ... как это всё корректно провернуть пока не придумал...
ИРЛ в любом случае каждый скрипт должен сам сорсить файл с функциями...
Большое спасибо за оперативные ответы. Я понял как можно обойти эту проблемму, но есть некоторые возражения-рассуждения.
Если я правильно понял, то вся фишка во взависимостях между процессами и подпроцессами.
Но смущают два факта.
1. Автор вышеупомянутой книги приводит многочисленные примеры сценариев, которые обращаются к функциям. И ни водном из них он предварительно не указывает где находится файл функции. Пишет, что достаточно:
а) добавить функцию в интерпретатор shell с помощью команды: . имя_файла_содержащего_функцию или . /имя_файла_содержащего_функцию;
б) проверить с помощью команды set, что функция добавилась;
в) можно обращаться к функции из сценария просто указывая её имя, как непосредственно из командной строки (у меня работает), так и в сценарии (у меня не работает).
Лично у меня такие объяснения сим фактам:
1) информация в книге устарела (издана в 2001);
2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?
Буду благодарен всем, кто поможет мне развеять этот туман догадок и все четко разложить по полочкам.
1) информация в книге устарела (издана в 2001);
Основные принципы актуальны.
а) добавить функцию в интерпретатор 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
Так сделайте это.Спасибо за замечание, но я, естественно, перед тем как запускать сценарий добавлял функцию в shell и проверял, что она добавилась с помощью команды set. В самом-самом первом своем обращении я описал порядок выполняемых действий.
За ссылки спасибо, особенно на русском.
Спасибо за замечание, но я, естественно, перед тем как запускать сценарий добавлял функцию в shell и проверял, что она добавилась с помощью команды set.
Честно говоря, не до конца понимаю, что именно вас смущает?
Честно говоря, не до конца понимаю, что именно вас смущает?Смущает то, что есть два файла:
1 файл функции
2 файл сценари, который обращается к этой функции.
Загружаю функцию в среду интерпретатора shell.
При обращении к функции из командной строки все работает как надо, к функции есть доступ.
При запуске сценария, который должен обратиться к этой функции, получаю ошибку. Нет доступа к функции.
Ват такой вот ребус.
С Вашим (Lupo Alberto) и советом Fat-Zer пока разбираюсь, т. к. получаю разные результаты при работе с разными файлами функций и сценариями. Определюсь с закономерностями получения результатов и обязательно отпишусь.
А пока спасибо за внимание :D
Определение всех вызываемых функций можете просто добавить в начало (перед их вызовом) скрипта.
Короче делаю следующие выводы:
1. (самый важный вывод) Ларчик открывался очень просто! *JOKINGLY*
2. Пока самое элегантное решение, кажется, у Fat-Zer:
alexander@goblin /tmp $ . 2.sh
То есть, когда есть два файла:
а) файл функции
б) файл сценари, который обращается к этой функции
Файл сценария нужно запускать так же как и добавлять функцию в интерпретатор shell, а именно:
<точка><пробел><имя_сценария>. Это и была моя ошибка.
3. Решения Lupo Alberto:
#! /bin/sh
# simple function
# применяем объявленную функцию в сценарии:
. func1 # Читаем файл функций, между точкой и именем файла пробел.
# Можно прочитать и так (# убрать)
# source func1
echo "сейчас будет выполняться функция hello."
hello
echo "Все. Функция hello выполнена."
В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).
На этом считаю указанную проблему решенной. Всем принимавшим участие большое спасибо.
Есть у меня еще один вопрос по проверку условий. Но об этом со следующей недели.
В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).
Что-то вы путаете (или я вас не понимаю) — http://shelr.tv/records/511518a896608005490000d8
2. Пока самое элегантное решение, кажется, у Fat-Zer:
это ни сколь не изящное решение, ибо весь мусор переменных попадёт в среды вызывающего шела...
болей-менее корректно будет вызывать в сабшеле: (. 2.sh)
но это скорее костыль, нежели решение...
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он.
1) информация в книге устарела (издана в 2001);
или так, или автор просто не компетентен... я больше склоняюсь ко второму... в любом случае вряд ли на форуме вообще найдётся пара дедушек, которые помнят такие детали тех прекрных времён...
2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?
да, это сработает... но это малость из другой оперы... только это не папки а файлы... и точку в начале имени второга файла забыл...
В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1. А, значит, эти строки в сценарии просто лишние (значит автор книженции, о которой я упоминал выше прав не писав таких строк в своих сценариях).
воистину, что-то тут не так...
Как я вижу тема оказалась намного интереснее и запутаннее чем я думал. *JOKINGLY*
1)Fat-Zer, если можно поясните что за зверь такой этот "сабшеле" (дочерний процесс shell?) или ссылку на научный труд по этому поводу...
По этой записи:
. 2.sh
можно определить "саб" этот шелл или "мэйн"? :D
2)
это ни сколь не изящное решение, ибо весь мусор переменных попадёт в среды вызывающего шела...
Но ведь можно в конце сценария после обращения к функции (когда она будет больше ненужна) написать unset имя_функции и убрать функцию? Правда вы, наверное, имели ввиду не саму функцию, а придуманные в сценарии переменные? Ну, а даже если и попадут переменные, то чем это плохо? В крайнем случае при перезагрузке консоли/среды shell/системы (нужное подчеркнуть) все очистится. Я правильно рассуждаю?
3) На счет этого:
OMIXO пишет:2) возможно файлы функций должны располагаться в какой-то специальной папке наподобие /etc/profile $HOME/profile ?да, это сработает... но это малость из другой оперы... только это не папки а файлы... и точку в начале имени второга файла забыл...
пожалуй, полностью и безоговорочно согласен. Если всякая фигня будет загружаться каждый раз при загрузке любого профиля, то это не есть хорошо.
4)
или так, или автор просто не компетентен... я больше склоняюсь ко второму...
Все-таки в компетентности автора я не склонен сомниваться, т. к. предидущие 3/5 этой книги не вызвали у меня ни одного вопроса. Все предельно просто и понятно (напомню, что мои знания в программировании до этой книги равнялись нулю).
5)И напоследок на счет
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он.
Если вы наставиете, что это наиболее часто применяемый способ обращения к файлу функции из сценария, то я, пожалуй, еще раз внимательнее его проверю. Может я что-то делал не так.
Спасибо за внимание. *CRAZY*
или автор просто не компетентен... я больше склоняюсь ко второму...
Ни в коем случае! Книга — в своём роде классика жанра.
1)Fat-Zer, если можно поясните что за зверь такой этот "сабшеле" (дочерний процесс shell?) или ссылку на научный труд по этому поводу...
man bash, что значат скобки... ну и там про среду исполнения шела... своими словами мне это сложно описать...
Но ведь можно в конце сценария после обращения к функции (когда она будет больше ненужна) написать 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]
когда это ещё произойдёт... а т.к. десктоп, то терминалы я не закрываю...
+ потенциальная дыра в безопасности и простой способ прострелить себе ногу...
Ни в коем случае! Книга — в своём роде классика жанра.
чего-то я пропустил, что за книга то?
чего-то я пропустил, что за книга то?
1. То, что я писал ранее:
В моём случае не помогли. Так как, если не запускать файл сценария как я написал в п.2, то не имеет значения ссылаюсь ли я в сценарии на файл функцию . func1 или source func1.[/quote]3. Решения Lupo Alberto:[quote="Lupo Alberto"]#! /bin/sh# simple function# применяем объявленную функцию в сценарии:. func1 # Читаем файл функций, между точкой и именем файла пробел.# Можно прочитать и так (# убрать)# source func1echo "сейчас будет выполняться функция hello."helloecho "Все. Функция hello выполнена."
полностью подтвердилось.
2.
я тоже настаиваю на варианте от Lupo Alberto... в реальных скриптах применяется именно он
Вы имеете ввиду, что функция указывается непосредственно в сценарии? Или же этот способ используется для обращения к файлу функции из сценария?