Функции в bash, sh

Linux и UNIX программирование в shell.   <---------PDF (ст. 210)

https://habr.com/ru/

https://losst.ru/funktsii-bash-v-skriptah

https://www.opennet.ru  <-----------

https://ru.stackoverflow.com/

Функции

Интерпретаторы команд sh как и bash, как и прочие позволяют группировать наборы команд или конструкций, создавая повторно используемые блоки, блоки кода, несущие естественно какую то функциональную нагрузку. Подобные блоки называются shell, bash – функциями. Использование "функций" стандартный способ создания и оптимизации кода в програмировании, роль и значение функций более очевидны в языках высокого уровня, однако там в силу "объектно-орентированных" традиций они носят название "методы" (метод (μετά- + ὁδός - путь - алгоритм решения), введенный с целью формализации понятия "объект", то есть это "слова", договоренности, поскольку появилось новое понятие "объект"(у каждого объекта свой не зависимый цикл жизни) то решили, что данные внутри объекта это будут - свойства, а функции будут - методы, на деле все это те же переменные и функции, вообщем — новая парадигма и весьма успешная), и тем не менее смысл везде один, в использовании некого блока кода для выполнения стандартных, часто встречающихся задач и вызове этого блока кода (функции-метода) посредствам короткого символьного значения, имени (интерфейса).

PS: Метод это функция класса, шаблона для создания объектов которые есть экземпляры какого либо класса, метод всегда является функцией, но функция не всегда является методом, разница понимается через историю развития языков и поскольку существует принципиальная разница между "продцедурным" и "объектно-орентированным" подходом к написанию кода, что бы не путать себя функции в ООП будет лучше называть методами.

    Для командных инерпретаторов функцией является подпрограмма - блок кода, который реализует набор операций, некий «чёрный ящик», выполняющий поставленную задачу. Функции принято использовать там, где существует повторяющийся код, когда задача повторяется с незначительными изменениями порядка выполнения действий, проще говоря для того что-бы не писать каждый раз одно и то же, полезно будет пользоваться библиотеками функций, как в отдельном скрипте так и вообще, создав библиотеку функций. При написании скриптов она не только поможет сократить труд, но и позволит одним разом доработать множество скриптов, если вы улучшите какую-либо функцию. Функции широко распространенное определение в программировании, тот же "системный вызов" можно понимать как функцию, функцию в которую передаются аргументы а она возвращает значения, тот же блок кода, те же стандартно выполняемые задачи, так он и называется "системная функция", например fork(). Функция состоит из двух частей:   

[Метка функции] 

[Тело функции]

    В качестве метки выступает имя функции заканчивающееся парными скобками, тело функции образует набор команд. составляющих саму функцию, имя функции должно быть уникальным естественно, поскольку  в случае наличия двух различных функций с одинаковыми именами сценарий просто не сможет вызвать нужную функцию, имя не должно содержать пробела, при написании пробел замещается нижним подчеркиванием. Использование парных круглых скобок (brackets, операторные) обязательно, изначально это взято наверное из математики где они используются для задания приоритета операций, в програмировании это место для параметров если нет параметров все равно должны быть, как дополнение к имени, вместе они и составляют метку функции, или в других языках это вызов функции. В bash или sh параметры внутри парных круглых скобок не используются, зачем они?., скорее всего заимствованы по традиции из С, вообщем это "синтаксис" посредствам которого анализатор (парсер) определяет, что следующий кусок кода это функция, который надо поместить в память и предоставить для него интерфейс  — имя функции.

Формат, применяемый для определения функций (как и в C, открывающая скобка функции может стоять на второй строке):

имя_функции ()

{

Команда1}

Или на первой:

имя_функции () {

команда 1

}


hello () {

echo "Hello there today's date is `date`"

}

Приемлимы оба способа определения функции. Можно также использовать ключевое слово function перед именем функции. Ключевое(зарезервированное) слово function

используется для предотвращения "столкновений" псевдонимов оболочки (alias - псевдоним) с именем функции (с ключевым словом function псевдоним не раскрывается):

function имя_функции ()

{

<тело функции>

}

$ alias foo="echo Function"

$ foo() { true; }

bash:syntax errornearunexpected token `('

$ function foo() { true; }

$ foo

Function

На этом примере хорошо увидеть тот не "примечательный" на первый взгляд факт,что место где появляется имя функции автоматически заменяется на код функции: foo() { true; } будет равно 

foo() { echo Function; },что "возможно" добавляет понимания их работы в сценарии.

Функцию можно представить в виде "выражения" то есть одной строкой.

$ ~ hello () { echo "Hello there today's date is `date`"; }

$ ~ hello

Hello there today's date is Вт июл 11 22:42:38 UTC 2017

$ ~ Не забывая, в этом случае, ставить точку с запятой после последней команды в функции.

Функции выполняются простым упоминанием их имён. Вызов функции равен вызову команды, при условии что она загружена в окружение интерпретатора команд, поскольку следует быть корректным в определениях и терминах функцию нельзя считать "командой" это именно "блок кода", который надо перед выполнением "загрузить" в окружение интерпретатора, от того она и "функция".

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

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

Проверка загруженных функций

    Чтобы удостовериться в том, что функции были загружены интерпретатором команд, воспользуйтесь командой set, которая отображает все загруженные функции, доступные для сценария, равно как и переменные, команда env отобразит "глобальные" переменные доступные "всем".

    В контексте bash переменными (variables) называют параметры, которые могут быть определены по имени. Каждому экземпляру оболочки при запуске передается строковый массив, который называется окружением (environment). Он представляет собой список переменных и их значений, более объще - параметры ( parameters) -- это именованные области памяти (оперативной памяти в случае интерпретаторов команд типа bash, sh и тд), способные хранить некую информацию (значение-value) различного типа. Функции после их объявления так же становятся частью окружения, потому и большое количество функций "затруднит" процесс вычислений в целом ( .... на что при современных вычеслительных мощностях ни кто не обращает внимания, и в этом можно убедится выполнив команду set в современном Linux ..и увидеть их количество). (Стек и Куча)

$ set 

...........

hello () 

    echo "Hello there today's date is `date`"

}

quote () 

    local quoted=${1//\'/\'\\\'\'};

    printf "'%s'" "$quoted"

}

quote_readline () 

    local ret;

    _quote_readline_by_ref "$1" ret;

    printf %s "$ret"

}

..............

$

Использование функций в сценарии


$ cat > func1

#!/bin/sh

# func1

hello ()

{

echo "Hello there today's date ls `date`"

}

echo "now going to the function hello"

hello

echo "back from the function"

C^

$

$ export PATH=$PATH:/home/user

..можно не подходить так  серьезно, а пользоваться командой "точка" (source), так же можно не заморачиваться правами доступа к файлу, например так:

$ cat > func

#!/bin/bash

echo "12345678"

^C

$ func

bash: func: command not found

$ . func

12345678

$

 но не так:

$ ./func

bash: ./func: Permission denied

..то есть если вы написали "путь" до файла (./file), то надо дать ему права на исполнение: chmod +x [имя файла], а в случае source (точка) не обязательно. Можно конечно явно указывать перед именем файла  название интерпретатора команд sh или bash и тд., результатом тоже станет выполнение файла в указанном интерпретаторе.

$ bash func

12345678

$

 


$ chmod +x funс1

$ ./func1

now going to the function hello

Hello there today's date ls Thu Oct 14 12:56:48 PM MSK 2021

back from the function

Сценарий конечно может пользоваться функциями загруженными (имеющимеся в окружении оболочки), предположим, что функция "hello", либо через файл содержащий набор функций, либо руками, но уже там есть, в этом случае в сценарии, нам будет достаточно упомянуть интерфейс(имя) функции:

$  cat > func_1

#!/bin/sh

hello

echo "back from the function"

^C

$ . func_1

now going to the function hello

Hello there today's date ls Thu Oct 14 01:07:38 PM MSK 2021

back from the function

Выгрузим функцию:

$ unset hello

$ . func_1

bash: hello: command not found

back from the function

В предыдущем примере функция была объявлена в начале сценария. Для обращения к функции просто вводится ее имя: "hello". После завершения выполнения функции управление возвращается следующей инструкции, размещенной после вызова функции. В приведенном примере речь идет о инструкции: echo "back from the function".

Передача параметров функции

    Порядок передачи параметров функции аналогичен передаче параметров обычному сценарию. При этом используются специальные переменные $1, $2, … $9 (позиционные параметры). При получении функцией переданных ей аргументов происходит замена аргументов, изначально переданных сценарию интерпретатора shell. В связи с этим будет не лишним  повторно присвоить значения переменным, получаемым функцией и это отдельная и не маловажная тема про локальные и глобальные переменные, как и области видимости функции в сценарии, в любом случае это стоит сделать, поскольку при наличии ошибок в функциях их можно будет легко обнаружить, воспользовавшись именами  переменных. Для вызывающих аргументов (переменных), находящихся внутри функции, имя каждой переменной начинается с символа подчеркивания, например: _FILENAME или _filename, то есть если использовать функцию в качестве аргумента. О видах переменных можно прочесть здесь.

Возврат значения функции

    После естественного завершения выполнения функции либо в том случае, когеда она завершается в результате выполнения какого либо условия, можно выбрать один из двух возможных вариантов:

    При использовании ключевого слова return применяется следующий формат:

return        возвращает значение, используя код завершения последней команды для проверки состояния, вернет либо Ø либо 1 где:

return - Ø     применяется при отсутствии ошибок

return - 1    применяется при наличии ошибок

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

$ hello () { echo "Hello there today's date is `date`"; return 3;}

$ hello

Hello there today's date is Thu Oct 14 04:58:15 PM MSK 2021

$ echo $?

3

$ hello () { echo "Hello there today's date is `date`"; return;}

$ hello

Hello there today's date is Fri Oct 15 05:39:27 PM MSK 2021

$ echo $?

0

$

Резюмируя можно сказать, команда return позволяет задавать возвращаемый функцией целочисленный код завершения, который доступен через переменную $?, при использовании в сценариях надо помнить об ограничениях для команды return, накладываемых областью видимости функций и использование return, скорее всего приведет к тому, что текущая функция выйдет из области видимости, как и постоянно учитывать разницу между локальными и глобальными переменными, объявленными в функции и объявленными в сценарии. 

Области видимости это проблема, проблема не только для "не просвещенного" user-а, но для вполне себе "продвинутого", так и команда return руководствуясь этими тайными пружинами мироздания не всегда появится там где вы хотели бы видеть ее результаты, что бы обойти ограничения для return, есть не хитрый способ заключающийся в записи данных выводимых функцией в переменную при помощи подстановки ($(...) = `...`, read, echo, env ),  переменная объявленная в функции видна всему сценарию, для создания локальных переменных функции есть команда 'local': local funck=value; echo ${funck} ), ***Returning Values from Bash Functions, и того:

$ cat retturn

return_echo () {

res1="example:1024" #global

 local res2="example:2048" #local

    echo $res2

        return 255

}

$ . retturn

$ res=$(return_echo)

$ res3=$?

$ echo $res $res1 $res3

example:2048 ... 255

$ return_echo

example:2048

$ echo $res $res1 $res3

example:2048  example:1024  255

return_echo () {

    read -s -n0 

    echo $(( value ))

}

$ return_echo () { read -s -n0; echo $(( 250 ));}

$ result=$(return_echo)

$ echo $result

250

PS: Кроме целочисленных значений можно вывести из функции что угодно и в любое место сценария. (опции команды read)


$ cat reead

#!/bin/bash

addition(){

read -p "Enter value: " x

read -p "Enter value: " y

   echo $(( $x + $y ))

   return $(( $x + $y + 100 ))

}

res=$(addition)

echo "The result is: " "$? - $res" 

$ . reead

Enter value: 30

Enter value: 40

The result is:  170 - 70

Подстановка команд

$(команда)  или (версия с обратными кавычками): ` команда `


$ echo $(date)

Fri Nov 5 01:12:42 PM MSK 2021

$ echo `date`

Fri Nov 5 01:13:21 PM MSK 2021


Подстановка переменной

$  подстановка переменной 

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

id=${USER}-on-${HOSTNAME} $ var=test.tar.gz

$ echo $id $ NAME=${var%%.*}

user-on-KaliLinux $ echo $NAME

$ test

Арифметическое расширение и его подстановка


"Арифметическое расширение" предоставляет механизм для вычисления

арифметического выражения и подстановки его значения. 

Выглядит как двойные круглые скобки, между которыми, вычисляется целочисленное 

арифметическое выражение,  двойные скобки в том числе позволяют работать с переменными в стиле языка C. 

Формат арифметического расширения  следующии:  

$ (( выражение ))

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

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

Проверка значений, возвращаемых функцией

    Для проверки значения, возвращаемого вызванной функцией, можно воспользоваться кодом возврата последней команды ($?), размешенной непосредственно после функции, которая вызывается из сценария. Например:

$ cat > status

#!/bin/bash

#status

hello ()

{

echo "Hello there today's date ls `date`"

}

hello

if [ $? = 0 ]

then

echo "All OK"

else

echo "Something went wrong!"

fi

^C

$ chmod 744 status

$ ./status

Hello there today's date ls Thu Oct 14 05:22:30 PM MSK 2021

All OK

$

или использовать return в теле функции:

$ cat status

#!/bin/bash

#status

hello ()

{

echo "Hello there today's date ls `date`"

return 255

}

hello

if [ $? = 255 ]

then

echo "All OK"

else

echo "Something went wrong!":

fi 

$ . status

Hello there today's date ls Thu Oct 14 05:22:30 PM MSK 2021

All OK

Если функцию планируется использовать для отображения результатов некоторой проверки, для фиксации результата применяется подстановка. Формат, используемый для выполнения подстановки при вызове функции, будет следующим: <имя_переменной=имя_функции> Выводимый результат функции "имя_функции" присваивается переменной "имя_переменной".


Лучшим методом является использование оператора if то есть проверка некого условия, с помощью которого осуществляется проверка возвращаемого значения (Ø или 1). Встраивание вызова функции в структуру оператора if значительно улучшает читабельность программного кода. Например:

$ cat > status_1

#!/bin/bash

#status_1

hello

if [ $? = 0 ]

then

echo "All OK"

else

echo "Something went wrong!"

fi

^C

$

 Загрузим функцию, и выполним скрипт:

$ hello () { echo "Hello there today's date is `date`";}

$ . status_1

Hello there today's date ls Thu Oct 14 02:46:29 PM MSK 2021

All OK

$

Выгрузим функцию, и выполним скрипт:

$ unset hello

$ . status_1

bash: hello: command not found

Something went wrong!

$

Переделаем скрипт:

$ cat status_1

#!/bin/bash

#status_1

if hello; then

echo "All OK"

else

echo "Something went wrong!"

fi

$ . status_1

Hello there today's date is Thu Oct 14 03:19:29 PM MSK 2021

All OK

$ unset hello

$ . status_1

bash: hello: command not found

Something went wrong!

 


Файл функций

    После того, как будет создано несколько регулярно используемых функций, их можно поместить в файл функций, а затем загружать содержимое этого файла в среду интерпретатора shell. В начале файла функции должна находиться конструкция #!/bin/sh (#!/bin/bash). Этому файлу можно присвоить любое имя, для удобства лучше использовать осмысленное наименование, например: functions.main. Как только файл будет загружен интерпретатором shell, появляется возможность вызова функций из командной строки либо из сценария, если из сценария то прописывается полный путь до файла функций c использованием "source": .  <путь к файлу> c целью не порождать еще один экземпляр интерпретатора, чтобы все функции оставались в текущем, при использовании source следует помнить про "пробел" или писать вместо точки саму команду "source". 

    Чтобы просмотреть все определенные функции, воспользуйтесь командой set. Поток вывода будет содержать все функции, которые были загружены интерпретатором. Для изменения любой из ранее определенных функций сначала примените команду unset (unset [Метка функции] ), после чего функция будет выгружена из интерпретатора. В результате этого данную функцию будет невозможно вызвать из пользовательских сценариев или интерпретатора команд, в файле она конечно останется. Если файл был отредактирован, то  после внесения изменений в файл функций выполните его перезагрузку, при помощи того же "source". Некоторые интерпретаторы команд могут распознавать изменения, и в этом случае применение команды unset вовсе не обязательно. Однако все же в целях безопасности всегда лучше использовать данную команду при модификации функций интерпретатора shell. В случае выше приведенного примера функции <hello> в "нормальной" операционной системе, например Solaris будет так:

>set

.................

UID=100

USER=user

_=unset

hello ()

{

    echo "Hello there today's date is `date`"

}

=========================

>unset hello

>set

.......................

UID=100

USER=user

_=hello

Создание файла функций


Наш файл функций, пока будет содержать одну функцию, функцию "findit".


$ ~ cat > functions.main

#!/bin/sh

# functions.main

# findit: интерфейс для базовой команды find

findit () {

if [ $# -lt 1 ]; then  # $#(количество аргументов) меньше одного

   echo "usage: 'findit' file"

   return 255

fi

find / -name $1 -print

}

^C

$ ~

Этот код лежит в основе интерфейса для базовой команды find

Если функции не передаются аргументы (позиционные параметры командной строки), то возвращается значение 255 (поскольку "find / -name $1 -print" не выполнено), для демонстрации работы кода, загрузим функцию в окружение интерпретатора, проверим ее наличие в памяти и посмотрим ее работу:



$ . functions.main

$ set

findit () 

    if [ $# -lt 1 ]; then

        echo "usage: findit file";

        return 255;

    fi;

    find / -name $1 -print

}

$ findit

usage: 'findit' file

$ echo $?

255

$

Попробуем найти файл "functions.main",вызвав функцию простым упоминанием ее интерфейса и указав в качестве аргумента имя файла functions.main:

$ findit functions.main 2>/dev/null

/home/user/functions.main

$ echo $?

1 #поскольку find, была выполнена с ошибками - вернула 1

$  

Подключение файла функций

    Подключение файла функций заключается в выполнении этого файла т.е в выполнении скрипта, т.е надо загрузить (подключить) его содержимое в окружение интерпретатора команд,  поскольку файл скорее всего находится по пути не перечисленной в переменной PATH, то надо воспользоваться командой source или ее синонимом командой точка или экспортировать путь: 

export PATH=$PATH:....

Итого это будет выглядеть так: . имя_файла

$ . functions.main       (равно: . [пробел] ./functions.main)

Если по какой то причине команда source не была исполнена ('file not found'), пропишите полный путь до файла не забыв присвоить файлу права на выполнение: chmod +x <имя файла> $ ./functions.main

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

     Вообще эта запись: точка, слэш (./) это путь к исполняемуму файлу находящемуся в директории из которой его хотят выполнить, независимо от того включена эта директория в переменную PATH  или нет (главное что бы файл был исполняемым и находился по пути "./"), можно считать что это полный путь до исполняемого файла,  эту запись придумали пришельцы поскольу смысл ее  "трансцендентален",  она работает не только в Linux (это было бы не так загадочно, в конце концов это их операционная система) она работает в BSD, она работает в Solaris  и если вы проведете эксперимент и сделаете переменную PATH например такой: PATH=......  она ВСЕ РАВНО сработает, но поскольку это извесно только пришельцам, то лично вам не о чем беспокоиться.( ..а еще они придумали команду exec ...и это полная "жесть"

PS: ...а "местные" просто пишут название интерпретатора в качестве оператора: $ sh functions.main, не забыв сделать файл исполняемым.  

    В общем и целом надо учитывать, что при использовании source  не создаётся копии bash-процесса, как это происходит при запуске скрипта , что наглядно демонстрирует первая строка скрипта [#!/bin/bash (#! -shebang -   sharp + bang (# + !)]  скрипт выполняется в текущем экземпляре bash, притом что весь контекст процесса и переменные окружения, не исчезают, и наоборот, если скрипт запускается явным образом, то создаётся локальная копия bash, с системным контекстом и отношение к родительскому bash относительное, то есть изменения внесенные в родительском bash будут утеряны, что так же относится и к функциям. Например:

$ cat > sorss

#!/bin/bash

echo "example"

echo $XXX

^C

$ XXX="variable"

$ . sorss

example

variable

$ chmod +x sorss

$ ./sorss

example


$

 В контексте функций наверное не лишним будет упомянуть про использование скобок в конструкциях как "bash" так и "С", что можно заметить в сиснтаксисе написания функции:

(...)  круглые скобки выполняю команду (команды) ... в дочерней оболочке

{...}  фигурные скобки (вложенный блок - функция) выполняют команду (команды) ... в текущей оболочке, и ни каких "subshell"

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

Перенаправление ввода/вывода из вложенного блока:

# cat > zzzzz

#!/bin/bash

file=/etc/passwd

{

read line1 # создаем переменную

read line2 # создаем переменную

} < $file  # считываем строки из файла "passwd"

echo "$line1"

echo "$line2"

exit 0

# chmod +x zzzzz

# ./zzzzz

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

#

Редактирование shell–функций

    А теперь изменим файл fiinctions.main. Добавим в функцию цикл for, в результате чего сценарий сможет считывать более одного параметра из командной строки, в результате будет полезная функция для поиска каких либо файлов, в итоге функция приобретет следующий вид:

$ ~ vim functions.main

#!/bin/sh

 # functions.main

  # findit: интерфейс для базовой команды find

  findit ()

  {

  #findit

  if [ $# -lt 1 ]; then

  echo "usage: findit file"

  return 1

  fi

  for loop

  do

  find / -name $loop -print

  done

  }

$ ~


PS: 

fоr имя_переменной in list

do

команда1

команда...

done

Применение опции in list в конструкции цикла for является опциональным, если не включать эту часть, цикл воспользуется позиционными параметрами командной строки.

Снова загрузим исходный файл:

$ . functions.main

И опять используем команду set, чтобы убедиться, что файл действительно загружен. Если интерпретатор shell корректно интерпретирует цикл for и воспринимает все требуемые параметры, на экране отобразится нечто подобное:

$ ~ set

................................

findit ()

{

    if [ $# -lt 1 ]; then

        echo "usage: findit file";

        return 1;

    fi;

    for loop in "$@";

    do

        find / -name $loop -print;

    done

}

$ ~

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

$ findit passwd path group

$ findit passwd path group 2>/dev/null (что более гуманно, то есть: stderr — стандартный вывод ошибок, дескриптор 2 в /dev/null)

/etc/passwd

/etc/pam.d/passwd

.....................

/usr/lib/ruby/2.7.0/bundler/source/path

/usr/lib/postgresql/12/lib/bitcode/postgres/optimizer/path

.........................

/etc/group

/etc/iproute2/group

................................

$ echo $?

1 # свидетельство наличия ошибок при выполнении команды find

Примеры  функций

Подтверждение  ввода

Рассмотрим  небольшой  сценарий,  который  запрашивает  имя  и  фамилию  пользователя:

$ ~ cat > func_01

#!/bin/bash

# func_01

echo -n "What ls your first name: "

read F_NAME

echo -n "What ls your surname: "

read S_NAME

^C

$ ~ chmod 744 func_01

$ ~ export PATH=$PATH:/home/iarch

$ ~ func_01

What ls your first name: nemo

What ls your surname: paco

$ ~

Для проверки наличия одних лишь символов можно воспользоваться утилитой awk. Ниже приводится функция, которая осуществляет проверку ввода либо только прописных, либо строчных символов.

{

#char_name

#вызов: char_name string

#назначение аргумента новой переменной

_LETTERS_ONLY=$1

#использование awk для проверки на наличие символов!

_LETTERS_ONLY=`echo $1|awk '{if ($0~/[^a-z A-Z]/) print "1"}'`

if [ "$_LETTERS_ONLY" != "" ] 

then

  # ошибки

  return 1

else

  # содержит только символы

  return 0

fi 

}

Сначала переменной $1 будет присвоено более осмысленное имя. Затем применяется утилита awk, осуществляющая проверку, состоит ли переданная строка из одних литер. В результате выполнения возвращается код, включающий 1 (для символов, не являющихся литерами) и 0 — для символов–литер. Этот код присваивается переменной _LETTERS_ONLY. Затем выполняется проверка значения переменной. Если переменной присвоено какое либо значение, то это свидетельствует о наличии ошибки; в случае отсутствия присвоенного значения ошибки нет. На основании результатов этой проверки формируется код возврата. Использование кода возврата позволяет сценарию фиксировать момент завершения проверки, выполняемой функцией в вызывающей части сценария.

Для проверки вывода функции можно использовать формат, применяемый для оператора if:

if char_name $F_NAME; then

  echo "OK" 

else

  echo "ERRORS"

fi

 Если происходит ошибка, можно создать другую функцию, отображающую сообщение об ошибке:

name_error ()

# name_error

# отображение сообщения об ошибке

{

echo " $@ contains errors, it must contain only letters"

Функция name_error будет отображать сообщения об ошибках, игнорируя при этом все некорректные записи. Применение специальной переменной $@ позволяет отображать на экране значения всех аргументов. В рассматриваемом случае будет отображено либо значение F_NAME, либо значение S_NAME.  И в итоге завершенный сценарий, созданный с применением функций:

$ ~ cat > func_02

#!/bin/bash

#func_02

#================================

char_name ()

# char_name

# вызов: char_name string

# проверка на предмет того, действительно ли $1 содержит только символы a-z,A-Z

{

# присвоение аргумента новой переменной

_LETTERS_ONLY=$1

_LETTERS_ONLY=`echo $1|awk  '{if($0~/[^a-z A-Z]/) print "1"}'`

if [ "$_LETTERS_ONLY" != "" ]

then

   return 1 # ошибки

  else

   return 0 # содержит только символы

fi

}

#===============================

name_error()

# отображение сообщения об ошибке

{

echo " $@ contains errors, it must contain only letters"

}

while :

do

  echo -n "What ls your first name :"

  read F_NAME

  if char_name $F_NAME

  then

    break # все OK, завершение выполнения

  else

    name_error $F_NAME

  fi

done

#===============================

while :

do

  echo -n "What ls your surname :"

  read S_NAME

  if char_name $S_NAME

  then

    break # все OK, завершение выполнения

else

    name_error $S_NAME

fi

done

echo "  Your first name: $F_NAME"

echo "  Your surename:   $S_NAME"


^C

$ ~

Для обработки результатов ввода применяется цикл while. Благодаря этому на экране отображается запрос до тех пор, пока пользователь не укажет верное значение. После ввода нужного значения выполнение цикла прерывается, конечно, при реализации работающего сценария, пользователю надо предоставить возможность прервать выполнение цикла, при этом надо предусмотреть соответствующую конструкцию, как и  при проверке наличия полей с нулевой длиной. Ниже приведены результаты выполнения описанного сценария:

$ ~ func_02

What ls your first name :nemo2b

 nemo2b contains errors, it must contain only letters

What ls your first name :Nemo

What ls your surname :paco32

 paco32 contains errors, it must contain only letters

What ls your surname :Paco

  Your first name: Nemo

  Your surename:   Paco

$ ~

Чтение одиночного символа

При создании меню одной из самых неприятных задач является необходимость нажимать клавишу [Return] после выбора каждого пункта меню либо в ответ на сообщение "нажмите любую клавишу для продолжения". В этом случае приходит на помощь команда dd, избавляющая пользователя от необходимости нажимать клавишу [Return] для отсылки ключевой последовательности.

Команда dd обычно применяется для выполнения различных преобразований и устранения проблем, связанных с хранением данных на лентах, либо при выполнении обычных задач резервирования. Данная команда также может применяться для создания файлов фиксированного размера. В следующем примере с ее помощью создается файл myfile, размер которого составляет 1 мегабайт.

dd if=/dev/zero of=myfile count=512 bs=2048

Команда dd также может интерпретировать результаты ввода с клавиатуры и использоваться для чтения символов. В данном случае ожидается появление лишь одного символа. Команда dd должна завершать выполнение после нахождения символа новой строки; этот управляющий символ появляется после нажатия пользователем клавиши [Return]. Команда dd в данном случае также посылает один символ. Перед тем как произойдет одна из описанных ситуаций, необходимо установить терминал в исходный режим. Для этого применяется команда stty (1 , 2 , 3). Настройки в приведенном ниже коде сохраняются перед вызовом команды dd и затем восстанавливаются после завершения выполнения команды dd.

read_a_char()

#read_a_char 

{

#сохранение настроек 

SAVEDSTTY=`stty -g`

#задание параметра терминала 

stty cbreak

#чтение и вывод лишь одного символа

dd if=/dev/tty bs=l count=l 2> /dev/null

# восстановление параметра терминала и настроек

stty -cbreak

stty $SAVEDSTTY 

}

Для вызова функции и возврата введенного символа используется подстановка команд. Вот соответствующий пример.

echo -n "Hit Any Key To Continue"

character=`read_a_char`

echo " In case you are wondering you pressed $character"

 

Проверка наличия каталога

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

is_it_a_directory()

{

# is_it_a_directorу

# вызов: is_it_a_directory имя_каталога

if [ $# -lt 1 ]; then

echo "is_it_a_directory: I need an argument"

return 1

fi

# это каталог ?

_DIRECTORY_NAME=$1

if [ ! -d $_DIRECTORY_NAME ]; then

return 1 # нет

else

return 0 # да

fi

}


PS: Проверка условий

$ if [ -d Mail ]; then echo OK; else echo NO; fi

OK

$ if [ -r conkyrc ]; then echo OK; else echo NO; fi

OK

$ if [ ! -d Mail ]; then echo OK; else echo NO; fi

NO

$ if [ -d conkyrc ]; then echo OK; else echo NO; fi

NO

$ помня про пробелы внутри скобок, или так:

$ if test -d Mail; then echo OK; else echo NO; fi

OK

$ if test -d concyrc; then echo OK; else echo NO; fi

NO

как и: [ "$a" -eq "$b" ] [ "$a" -ne "$b" ] [ "$a" -lt "$b" ] и тд

Для вызова функции и проверки результата можно воспользоваться кодом:

echo -n "enter destination directory :"

 read DIREC

if is_it_a_directory $DIREC;

then :

else

echo "$DIREC does not exist, create it now? [y..n]"

# здесь должны находится команды для создания каталога или для выхода

................

................

fi

Объеденим эти два кода в файл:

$ cat  > direc_check

#!/bin/sh

#==============================

is_it_a_directory()

{

# is_it_a_directorу

# вызов: is_it_a_directory имя_каталога

if [ $# -lt 1 ]; then

echo "from \"is_it_a_directory\": I need an argument, repeat again!"

return 0

fi

# это каталог ?

_DIRECTORY_NAME=$1

if [ ! -d $_DIRECTORY_NAME ]; then

return 1 # нет

else

echo extracting to dir: \"$DIREC\"

return 0 # да

fi

}

#============================

echo -n "enter destination directory : "

read DIREC

if is_it_a_directory $DIREC

then :

else

echo -n "Dir:\"$DIREC\" does not exist, creat it now? [y or n]: "

read ANS

if [ "$ANS" != "" ]; then 

case $ANS in

y) mkdir $DIREC >/dev/null 2>&1; echo \Created direct: \"$DIREC\"

;;

n) echo \"Not touch\"

;;

esac

fi

fi

^C

$ . direc_check

enter destination directory : # отказался вводить

from "is_it_a_directory": I need an argument, repeat again!

$ . direc_check

enter destination directory : dirtest

Dir:"dirtest" does not exist, creat it now? [y or n]: y

Created direct: "dirtest"

$ ls -al dirtest

total 8.0K

drwxr-xr-x  2 user user 4.0K Oct 19 13:06 ./

drwxr-xr-x 62 user user 4.0K Oct 19 13:06 ../

$ . direc_check

enter destination directory : dirtest

extracting to dir: "dirtest"

$ . direc_check

enter destination directory : dirtest1

Dir:"dirtest1" does not exist, creat it now? [y or n]: n

"Not touch"


PS: Скрипт прямо скажем бесполезный, приведенный лишь с целью демонстрации функции: "is_it_a_directory()"....., что он и делает.

Еще не много практики, наводящей на "размышления", изменим скрипт, добавив функцию: "error_msg()", которая добавит сигнал терминала и сообщение для пользователя: echo $@

конструкцию echo, по необходимости следует использовать с ключом подавления новой строки "-n" , что бы сделать вывод удобным для чтения.

$ cat > direc_check1

#!/bin/sh

#==============================================

is_it_a_directory()

{

_DIRECTORY_NAME=$1

if [ $# -lt 1 ]; then # если $#-количество аргументов(позиционных папаметров) меньше 1

echo "from:\"is_it_a_directory\": I need a directory name to check"

beep -f 4400 -r 3 -l 100 -d 50     # можно добавить "beep", если стоит: ($ type beep #beep is hashed (/usr/bin/beep))

return 1 

fi

if [ ! -d $_DIRECTORY_NAME ];then # это каталог?

return 1 # нет

else

echo "extracting to dir: $1"

return 0 # да 

fi

}

#==== сигнал терминала + сообщение =====

error_msg()

{

echo -en "\007" # beep

echo -n $@ # то что называется "all command line arguments", встроенная переменная на ряду с '$#''$@''$?'

echo -e "\007"

return 0

}

#==============================================

echo -n "enter destination directory: "

read DIREC

if is_it_a_directory $DIREC

then :

else

error_msg "dir:\"$DIREC\" does not exist...creating it now"

mkdir $DIREC >/dev/null 2>&1

if [ $? != 0 ]

then

error_msg "could not creat directory: repeat again!"

#exit 1

else :

echo "extracting files..."

fi

fi

^C

$ . direc_check1

enter destination directory: # отказался вводить

from:"is_it_a_directory": I need a directory name to check

dir:"" does not exist...creating it now

could not creat directory: repeat again!

$ . direc_check1

enter destination directory: dirtest2

dir:"dirtest2" does not exist...creating it now

extracting files...

$ . direc_check1

enter destination directory: dirtest2

extracting to dir: dirtest2

$ ls -al dirtest2

total 8.0K

drwxr-xr-x  2 user user 4.0K Oct 19 11:51 ./

drwxr-xr-x 62 user user 4.0K Oct 19 11:51 ../

Запрос на ввод Y или N

Многие сценарии выдают запрос на ввод подтверждения перед выполнением дальнейшей обработки. Запрос может выглядеть следующим образом:

Create a directory; Do you wish to delete this file; Run the backup now; Confirm to save a record, и этот перечень может быть достаточно длинным.

Следующая функция реализует обобщенный запрос. Пользователь указывает отображаемое сообщение, а также ответ, выбираемый по умолчанию. Ответ, выбираемый по умолчанию, используется в том случае, если пользователь просто нажал клавишу [Return]. Конструкция case применяется для перехвата ответов.

continue_prompt ()

#continue_prompt

#вызов: continue_prompt "отображаемая_строка" ответ_по_умолчанию

{

_STR=$1 

_DEFAULT=$2

# проверка на предмет указания правильных параметров

if [ $# -lt 1 ]; then

echo "continue_prompt: I need a string to display" 

return 1 

fi

# бесконечный цикл

while :

do

echo -n "$_STR [Y..N] [$_DEFAULT]:" 

read _ANS

#если пользователь нажал [Return], устанавливаются настройки по умолчанию и определяется возвращаемое значение,

#ниже находится пробел, а затем символ $ 

: ${_ANS:=S_DEFAULT}

if [ "$_ANS" = "" ]; then

case $_ANS in

Y) return 0 ;;

N) return 1 ;;

esac 

fi

# пользователь что-то выбрал

case $_ANS in

y|Y|Yes|YES)

return 0

;;

n|N|No|NO)

return 1

;;

*) echo "Answer either Y or N, default is $_DEFAULT"

;;

esac

echo $_ANS

done 

}

Для вызова функции можно указать отображаемое сообщение в двойных кавычках либо вызвать ее вместе с аргументом $1, либо, в крайнем случае, использовать переменную, содержащую строку. Также может передаваться ответ, заданный по умолчанию, в виде 'Y' или 'N'.

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

if continue_prompt "Do you want to delete the var filesytem" "N"; then

echo "Are you nuts!!" 

else

echo "Phew, what a good answer!"

fi

При использовании этого кода можно указывать следующий ввод:

Do you really want to delete the var filesystem [Y..N] [N] : 

Phew, what a good answer!

Do you really want to delete the var filesystem [Y..N] [N] :y 

Are you nuts!!

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

Ниже приводится другой способ вызова функции:

if continue_prompt "Do you really want to print this report" "Y"; then

lpr report 

else :

fi

Функцию можно также вызвать с использованием переменной $1, содержащей строку:

if continue_prompt $1 "Y"; then

lpr report 

else :

fi

PS: Символ двоеточия можно посчитать за ошибку написания кода, но это не так:

Исторически сложилось, что у "sh" не было true и false как встроенных команд, true вместо этого использовал псевдоним ":", и false что-то "...?",.

И вот например:

if command; then :; else ...; fi

Поскольку if требуется не пустое "then предложение", двоеточие : служит неактивным "заменителем" его. В настоящее время  мы можем использовать как ":" так и true. Оба прописаны в 

POSIX, и очевидно что, true легче читается. Однако есть одна интересная разница ":" двоеточие  это так называемый в POSIX "специально встроенный" , а true "обычно встроенный".

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

$ ( x=hi :; echo "$x" ); unset x

...........................

$ ( x=hi true; echo "$x" ); unset x

...........................

$ ( x=hi; echo "$x" ); unset x

hi

Другое отличие состоит в том, что обычные встроенные модули должны быть совместимы с exec, (будем пользоваться Bash):

$ ( exec : )

bash: exec: :: not found

$ ( exec true )

$

POSIX явно отмечает, что двоеточие ":" может быть быстрее, чем true, хотя, это детали реализации. 

В общем и целом двоеточие можно считать синонимом true, команды которая "ни чего не делает", но при этом успешно завершается, возвращая  "0" в качестве кода возврата, пишется через пробел. (SHELL.pdf ст.9)


while команда 

do

команды1

команды2

...................

done

После оператора while, руководствуясь синтаксисом, должна следовать команда, но при организации нижеследующего цикла нам она не нужна, по этому используется true:

$ while true; do echo Ctrl + c: прервать цикл; done

Ctrl + c: прервать цикл

Ctrl + c: прервать цикл

Ctrl + c: прервать цикл

^C

$ while :; do echo Ctrl + c: прервать цикл; done 

Ctrl + c: прервать цикл

Ctrl + c: прервать цикл

Ctrl + c: прервать цикл

^C

$

А вообще вот так:

$ COUN=2

$ while [ $COUN -lt 5 ]; do COUN=`expr $COUN + 1`; echo $COUN; done

3

4

5

Получение сведений об идентификаторе регистрации

При работе в составе большой системы может возникнуть необходимость связаться с одним из зарегистрированных пользователей. Что делать в том случае, если вы не помните имя пользователя? Часто системные администраторы наблюдают идентификаторы пользователей, блокирующих какие либо процессы. Для того чтобы увидеть полное имя пользователя, они должны просмотреть файл passwd с помощью команды grep. И только после этого можно связаться с пользователем, чтобы сделать ему справедливый выговор.

Рассмотрим функцию, которая позволит избежать просмотра файла /etc/passwd с помощью команды grep.

В тестовой системе полное имя пользователя хранится в пятом поле файла passwd; в вашей системе все может быть по–другому, поэтому, возможно, придется изменить номер поля, чтобы обеспечить соответствие с файлом passwd.

Функции передается один либо множество идентификаторов пользователей, а функция имитирует действие команды grep по отношению к файлу passwd.

Программный код функции:

whois ()

#whois

#вызов: whois идентификатор_пользователя

{

# проверка на наличие корректных параметров

if [ $# -lt 1 ]; then

echo "whois : need user id's please" 

return 1 

fi

for loop 

do

_USER_NAME=`grep $LOOP /etc/passwd | awk -F: '(print $4}'` 

if [ "$_USER_NAME"="" ]; then

echo "whois: Sorry cannot find $LOOP"

else

echo "$LOOP is $_USER_NAME" 

fi 

done 

}

Функция whois может быть вызвана следующим образом:

$ whois davs peters superman

dave ls David Tansley — admin accts

peter ls Peter Stromer -customer services

whois: Sorry cannot find superman

Использование нумерации в текстовом файле

При использовании редактора vi/vim появляется возможность нумерации строк. Это полезно в целях отладки, но при выводе на печать некоторых файлов с номерами строк потребуется команда nl. Ниже приведена функция, имитирующая действие команды nl (выполняет нумерацию строк файла  (nl -для нумерации непустых строк: nl [file] ,всех строк:nl -ba [file])). Исходный файл при этом не перезаписывается. Вот программный код функции.

number_file ()

#number_file

#вызов: number_file имя_файла 

{

_FILENAME=$1

# проверка наличия корректных параметров

if [ $# -ne 1 ]; then

echo "number_flie: I need a filename to number" 

return 1 

fi

loop=1

while read LINE do

echo "$LOOP: $LINE" loop=`expr $LOOP + 1` 

done < $_FILENAME 

}

Для вызова функции number_file просто укажите имя файла, подлежащего нумерации, в качестве аргумента функции. Вызов функции может также осуществляться из среды интерпретатора shell путем указания имени файла. Например:

$ number_file myfile

Кроме того, функцию можно вызвать из сценария, воспользовавшись с этой целью предыдущим примером. Или вы можете задать оператор:

$ number_file $1

Результат выполнения функции может выглядеть следующим образом:

$ number_file /home/dave/file_listing

1: total 105

2: -rw-r—r—- 1 dave admin 0 Jun 6 20:03:DT

3: -rw-r--r-- 1 dave admin 306 May 23 16:00 LPSO. AKS

4: -rw-r--r-- 1 dave admin 306 May 23 16:00 LPSO. AKS. UC

5: -rw-r--r-- 1 dave admin 324 May 23 16:00 LPSO. MBB

6: -rw-r--r-- 1 dave admin 324 May 23 16:00 LPSO. MBB. UC

7: -rw-r--r-- 1 dave admin 315 May 23 16:00 LPSO. MKQ

Преобразование символов в прописные

Иногда возникает потребность в преобразовании строчных символов в прописные. Например, для создания каталогов в файловой системе используются прописные символы. Кроме того, при вводе данных в поля может выполняться проверка, являются ли все символы прописными. Ниже приводится соответствующая функция. Эта функция имитирует действие команды tr:

str_to_upper () 

#str_to_upper

# вызов: str_to_upper $1

{

STR=$1

# проверка на наличие корректных параметров

if [ $# -ne 1 ]; then

echo "number_file: I need a string to convert please"

return 1

fi

echo $@ |tr '[a?z]' '[A?Z]'

Переменной upper присваивается строка, символы которой преобразованы в прописные символы. Обратите внимание, что снова применяется специальный символ $@ для передачи всех аргументов. Функция str_to_upper может вызываться двумя способами. Можно указать строку в сценарии следующим образом:

UPPER=`str_to_upper "documents.live"` 

echo $UPPER

либо указать аргумент функции вместо строки:

UPPER=`str_to_upper $1` 

echo $UPPER

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

is_upper

Функция str_to_upper осуществляет преобразование регистра символов. Но иногда перед выполнением дальнейшей обработки необходимо только знать, содержатся ли в строке прописные символы. Это может потребоваться для записи информации в текстовое поле файла. Функция i supper выполняет именно эту задачу. Применение оператора if В сценарии позволит определить, будет ли передаваемая строка включать прописные символы. Программный код функции:

is_upper ()

#is_upper

#вызов: is_upper $1

{

# проверка на наличие корректных параметров

if [ $# -ne 1 ]; then

echo "is_upper: I need a string to test OK"

return 1 

fi

# применение awk для проверки на наличие прописных символов

_IS_UPPER=`echo $1 | awk '{if($0~/[^A?Z]/) print "1"}`

if [ "$_IS_UPPER" != "" ] 

then

# нет, не все символы являются прописными

return 1

else

# да, все символы являются прописными

return 0

fi 

}

При вызове функции is_upper укажите строковый аргумент. На примере показано, как вызывается функция.

echo -n "Enter the filename :"

read FILENAME

if ls_upper $FILENAME; then

echo "Great it's upper case" 

else

echo "Sorry it's not upper case" 

fi

Для проверки наличия в строке строчных символов просто замените существующую конструкцию awk а функции is_upper и измените имя функции на is_lower.

_IS_LOWER=`echo $1 |awk '{ if ($0~/[^a?z] /) print "1"}`

Преобразование символов строки в строчные символы

В предыдущем разделе мы рассмотрели функцию str_to_upper, а теперь речь пойдет о функции str_to_lower. Вот код самой функции:

str_to_lower ()

#str_to_lower

#вызов: str_to_lower $1 

{

#проверка на наличие корректных параметров 

if [ $# -ne 1 ]; then

echo "str_to_lower: I need a string to convert please"

return 1 

fi

echo $@ | tr '[A?Z]' '[a~z]' 

}

Переменная lower хранит возвращенное значение строки, содержащей строчные символы. Обратите внимание на повторное использование специального параметра $@ для передачи всех аргументов. Функция str_to_lower может быть вызвана двумя способами. Во–neрвых, можно указать строку в сценарии:

LOWER=`str_to_lower "documents.live"` 

echo $LOWER

Альтернативный вариант — указать аргумент для функции вместо задания строки:

LOWER=`str_to_lower $1`

echo $LOWER

Определение длины строки

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

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

check_length()

#check_length

#вызов: check_length строка максимальная_длина_строки 

{

_STR=$1 

_МАХ=$2

# проверка на наличие корректных параметров

if [ $# -ne 2 ]; then

echo "check_length: I need a string and max length the string should be" 

return 1 

fi

# проверка длины строки

_LENGTH=`echo $_STR |awk '{print length ($0)}'` 

if [ "$_LENGTH" -gt "$_MAX" ]; then

# длина строки слишком велика

return 1

else

# строка имеет обычную длину

return О

fi 

}

Функция check length может быть вызвана следующим образом:

while : 

do

echo -n "Enter your FIRST name :" 

read NAME

if check_length $NAME 10 

then 

break

# ничего не происходит, если все условия выполнены 

else

echo "The name field ls too long 10 characters max" 

fi 

done

Цикл продолжает выполняться до тех пор, пока данные, вводимые для переменной NAME, меньше, чем значение переменной MAX (эта переменная содержит количество разрешенных символов; в данном случае речь идет о 10 символах). Команда break позволяет завершить выполнение цикла.

При использовании приведенного выше фрагмента кода, вывод будет следующим:

$ cat > test_name

#!/bin/sh

# check_lengh

#=====================

check_length()

#check_length

#вызов: check_length строка максимальная_длина_строки

{

_STR=$1

_MAX=$2

# проверка на наличие корректных параметров

if [ $# -ne 2 ]; then

    echo "check_length: I need a string and max length the string should be"

    return 1

fi

# проверка длины строки

_LENGTH=`echo $_STR | awk '{print length($0)}'`

if [ "$_LENGTH" -gt "$_MAX" ]; then

    return 1  #длина строки слишком велика

else

    return 0  #строка имеет приемлимую длину

fi

}

#=====================

# test_name

while :

do

    echo -n "Enter your FIRST name: "

    read NAME

    if check_length $NAME 10

    then

        echo "Your name $NAME"; break

        #break

        #или просто break, ничего не происходит, если все условия выполнены

    else

        echo "The name field is too long 10 characters max"

    fi

done

$ . test_name

Enter your FIRST name:  #отказался вводить 

check_length: I need a string and max length the string should be

The name field is too long 10 characters max

Enter your FIRST name: Nemoooooooooo #...перебор

The name field is too long 10 characters max

Enter your FIRST name: Nemo

Your name Nemo

Команда wc также может применяться для определения длины строки, но имейте в виду следующий факт. При использовании команды wc для обработки результатов ввода с клавиатуры могут появиться проблемы. Если после ввода имени несколько раз нажать клавишу пробела, то, как правило, некоторые пробелы будут учитываться в качестве части строки. По этой причине будет определяться некорректная длина строки. Утилита awk "обрезает" конечные пробелы в строке при осуществлении ввода с клавиатуры (эта функция задана по умолчанию). Ниже приведен пример, иллюстрирующий сказанное:

echo -n "name :"

read NAME

echo $NAME | wc -c

Результат выполнения описанного фрагмента сценария (здесь [ ] является пробелом):

name : Peter[][]

Функция chop

Функция chop удаляет символы в начале строки. Этой функции передается строка; пользователь указывает, сколько символов необходимо "обрезать", начиная с первого символа. Предположим, что имеется строка mydocument.doc и требуется "обрезать" часть mydocument, в результате чего функция будет возвращать только часть .doc. При этом функции chop могут быть переданы следующие параметры: MYDOCUMENT.DOC 10

Код функции chop:

chop () 

# chop

# вызов: chop строка количество_обрезаемых_символов

{

_STR=$1 

_CHOP=$2

# подстрока awk, начинается с 0, нам потребуется прирастить ее на единицу 

# для отображения того, что если пользователь задал обрезание 2 символов, 2 символа будут удалены #+ а не 1 

CHOP=`expr $_CHOP + 1`

#проверка на корректность параметров 

if [ $# -ne 2 ]; then

echo "check_length: I need a string and how many characters to chop"

return 1 

fi 

# первоначальная длина строки

_LENGTH=`echo $_STR | awk '{print length ($0)}'`

if [ "$_LENGTH" — lt "$_CHOP" ]; then

# мы не можем обрезать больше символов, чем содержится в строке!!

echo "Sorry you have asked to chop more characters than there are in the string"

return 1 

fi

echo $_STR | awk '(print substr ($1, '$_CHOP')}' 

}

Возвращаемая строка, которая была "обрезана", присваивается переменной chopped. Для вызова функции chop используется следующая последовательность:

CHOPPED=`chop "Honeysuckle" 5`

echo $CHOPPED

suckle

Вызов также можно осуществить другим способом:

echo -n "Enter the Filename :"

read FILENAME

CHOPPED=`chop $FILENAME 1`

# первый символ будет обрезан !

Функция months

При создании отчетов либо при отображении информации на экране часто удобным для программистов является использовании быстрого метода отображения полных наименований месяцев. Функция months в качестве аргумента использует номер месяца либо его аббревиатуру и затем возвращает полное наименование месяца.

Например, использование в качестве аргумента значения 3 либо 03 приведет к возврату значения "March". Вот описание самой функции:

months () 

{

# months

_MONTH=$1

# проверка на наличие корректных параметров

if [ $# -ne 1 ]; then

echo "months: I need a number 1 to 12 " 

return 1 

fi

case $_MONTH in 

1|01|Jan)_FULL="January";; 

2|02|Feb)_FULL="February";; 

3|03|Mar)_FULL="March";; 

4|04|Apr)_FULL="April";; 

5|05|May)_FULL="May";; 

6|06|Jun)_FULL="June";;

7|07|Jul)_FULL="July";;

8|08|Aug)_FULL="August;; 

9|09|Sep|Sept)_FULL="September";; 

10|Oct)_FULL="October";; 

11|Nov)_FULL="November;; 

12|Dec)_FULL="December";; 

*) echo "months: Unknown month" 

return 1

;;

esac

echo $_FULL

}

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

months 04

В результате отобразится наименование месяца "April". Можно также вызвать функцию из сценария:

MY_MONTH=`months 06`

echo "Generating the Report for Month End $MY_MOMTH"

..........

В результате отобразится название месяца "June".

Подведение итогов, вызов функций, размещенных в сценариях

Программный код функции не обязательно должен быть слишком сложным либо громоздким. Многие из функций выполняют обычные задачи. Они не предназначены для осуществления "прорыва" в деле создания сценариев, а просто экономят ваше время, позволяя не вводить одинаковые фрагменты кода. Только благодаря этому использование функций, несомненно, полезно. Вам может пригодиться следующий совет. Выполняя тестирование функции, проверяйте ее действия в виде сценария, и лишь получив удовлетворительные результаты, оформляйте сценарий в виде функции. При этом вы сэкономите время, затрачиваемое на проверку. Чтобы использовать функцию в сценарии, ее нужно создать, затем убедиться в том, что конструкция, вызывающая эту функцию, находится после программного кода самой функции. Ниже приводится сценарий, из которого вызываются две функции. Сценарий уже рассматривался ранее; здесь осуществляется проверка существования каталога.

$ pg direc_check

#!/bin/sh

# файл функций

is_it_a_directory()

{

#is_it_a_directory(

#вызов: is_it_a_directory имя_каталога 

_DIRECTORY_NAME=$1

if [ $# -lt 1 ]; then

echo "is_it_a_directory: I need a directory name to check"

return 1 

fi

# это каталог?

if [ ! -d $_DIRECTORY_NAME ]; then

return 1 

else

return 0

fi

}

# --------------------------------------------------------------------

error_msg

{

#error_msg

#сигнал; сообщение; повторный сигнал 

echo -e "\007"

echo $@

echo -e "\007"

return 0 

}

### END OF FUNCTIONS

echo -n "enter destination directory :"

read DIREC

if is_it_a_directory $DIREC

then :

else

error_msg "$DIREC does not exist…creating it now"

mkdir $DIREC > /dev/null 2>&1

if [ $? != 0 ]

then

error_msg "Could not create directory: check it out!" 

exit 1

else :

fi 

fi # не каталог 

echo "extracting files…"

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

Вызов функций из файла функций

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

А теперь воспользуемся снова описанной выше функцией, но в этом случае поместим ее в файле функций. Назовем этот файл functions.sh .

$ pg functions.sh

#!/bin/sh

#functions.sh

#основные функции 

is_it_a_directory () 

{

#is_it_a_directory

#вызов: is_it_a_directory имя_каталога 

#

if [ $# -lt 1 ]; then

echo "is_it_a_directory: I need a directory name to check"

return 1 

fi

# это каталог ?

DIRECTORY_NAME=$1

if [ ! -d $DIRECTORY_NAME ]; then

return 1 

else

return 0 

fi

}

#----------------------------------------------------------------------------------

error_msg ()

{

echo -e "\007"

echo $@

echo -e "\007"

return 0

}

Создадим сценарий, вызывающий функции из файла functions.sh. Затем эти функции могут использоваться для выполнения каких либо задач. Обратите внимание, что файл функций загружается при помощи все той же source: .  /<путь к файлу>  Зачем ...?, с важной целью не создавать порожденный интерпретатор, что бы все функции остались в текущем.

$ pg direc_check

#!/bin/sh

# direc_check 

# загрузка файла функций functions.sh 

. /home/dave/bin/functions.sh

# теперь могут использоваться функции

echo -n "enter destination directory :"

read DIREC

if is_it_a_directory $DIREC

then :

else

error_msg "$DIREC does not exist… creating it now"

mkdir $DIREC > /dev/null 2>$1

if [ $? != 0 ]

then

error_msg "Could not create directory: check it out!" 

exit 1

else :

fi 

fi # не является каталогом 

echo "extracting files…"

При выполнении сценария получается тот же вывод, что и при встраивании функции в сценарий:

S direc_check

enter destination directory :AUDIT 

AUDIT does not exist… creating it now 

extracting files…

Загрузка файлов, которые состоят не только из функций

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

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

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

$ cat backfunc

#!/bin/sh

#name: backfunc

#конфигурационный файл содержит настройки по умолчанию для систем архивации 

_CODE="comet"

_FULLBACKUP="yes" 

_LOGFILE="/logs/backup/" 

_DEVICE="/dev/rmt/0n" 

_INFORM="yes" 

_PRINT_STATS="yes"

$

Комментарии разъясняют суть программы. Первое поле, _code, содержит кодовое слово. Для просмотра его содержимого и изменения значений пользователь должен ввести код, соответствующий значению code. В данном случае указывается слово "comet".

Ниже приведен сценарий, который в ответ на ввод пароля отображает конфигурацию, заданную по умолчанию:

$ cat > readfunc

#!/bin/sh

# readfunc

if [ -r backfunc ]; then

    # указание файла с параметрами

    . ~/backfunc 

    else

    echo "$`basename $0` cannot locate backfunc file"

fi


echo -n "Enter the code name: "

read CODE

# соответствует ли код, коду из файла backfunc? 

if [ "${CODE}" != "${_CODE}" ]; then

 echo "Wrong code! i exiting, посмотри пока переменные окружения:"

 echo "LANG variable            :$LANG"

 echo "EDITOR variable          :$EDITOR"

 echo "SHELL variable           :$BASH"

 echo "PWD variable             :$PWD"


else

    echo "The environment config file reports:"

    echo "Full Backup Required                 : $_FULLBACKUP"

    echo "The Logfile is                       : $_LOGFILE"

    echo "The Device To Backup To is           : $_DEVICE" 

    echo "You Are To Be Informed by Mail       : $_INFORM" 

    echo "A Statistic Report To Be Printed     : $_PRINT_STATS"

fi

^C

$

После запуска сценария отобразится запрос на ввод кода. Если введенный код соответствует заданному кодовому слову "comet", скрипт покажет настройки, заданные в файле "backfunc". если нет, текушие настройки окружения shell. Можно добиться что бы "рабочий вариант" сценария предоставлял возможности для редактирования настроек.

$ . readfunc

Enter the code name: xxxxx

Wrong code! i exiting, посмотри пока переменные окружения:

LANG variable            :en_US.UTF-8

EDITOR variable          :vim

SHELL variable           :/bin/bash

PWD variable             :/home/user

$ . readfunc

Enter the code name: comet

The environment config file reports:

Full Backup Required                 : yes

The Logfile is                       : /logs/backup/

The Device To Backup To is           : /dev/rmt/0n

You Are To Be Informed by Mail       : yes

A Statistic Report To Be Printed     : yes

Функция для обмена двух файлов именами

switch()

{

 tmp=$$switch

 mv "$1" $tmp

 mv "$2" "$1"

 mv $tmp "$2"

}

$ switch() { tmp=$$switch; mv "$1" $tmp; mv "$2" "$1"; mv $tmp "$2"; }

$ cat > ccc1

bcbcbcb

bcbcbcb

bcbcbcb

^C

$ cat > ccc2

xzxzxzx

xzxzxzx

xzxzxzzx

^C

$ switch ccc1 ccc2

$ cat ccc2

bcbcbcb

bcbcbcb

bcbcbcb

$ cat ccc1

xzxzxzx

xzxzxzx

xzxzxzzx

Создать каталог и открыть.

mcd () 

{

mkdir -p $1

cd $1

}

$ mcd () { mkdir -p $1; cd $1; }

$ mcd mkkddir

/mkkddir$ pwd

/home/user/mkkddir

/mkkddir$ 


Распаковать

extract () 

{

if [ -z "$1" ]; then   # -z "string" истина, если длина string равна нулю.

# display usage if no parameters given

echo "Usage: extract <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>"

else

if [ -f $1 ] ; then   # -f FILE  истина, если FILE существует 

NAME=${1%.*} Удалить суффикс, удаляет из переменной $1 наименьшую/наибольшую подстроку, совпадающую с шаблоном ".*

          Поиск ведется с конца строки $1.  https://www.opennet.ru:

             (# и ## используются для поиска с начала строки)

             (% и %% используются для поиска с конца строки.)

mkdir $NAME && cd $NAME

выбор: case, case_1, case 2  

case $1 in      

*.tar.bz2) tar xvjf   ../$1 ;; # tar

*.tar.gz) tar xvzf   ../$1 ;;

*.tar.xz)   tar xvJf   ../$1 ;;

*.lzma)        unlzma     ../$1 ;;

*.bz2)        bunzip2    ../$1 ;;

*.rar)        unrar x    ../$1 ;;

*.gz)        gunzip     ../$1 ;;

*.tar)        tar xvf    ../$1 ;;

*.tbz2)        tar xvjf   ../$1 ;;

*.tgz)        tar xvzf   ../$1 ;;

*.zip)        unzip      ../$1 ;;

*.Z)            uncompress ../$1 ;;

*.7z)        7z x       ../$1 ;;

*.xz)        unxz       ../$1 ;;

*.exe)    cabextract ../$1 ;;

*)            echo "extract: '$1' - unknown archive method" ;;

esac

else

echo "$1 - file does not exist"

fi

fi

}

Для наглядности создадим файл сценария:

$ cat > extraction

#!/bin/bash

#extraction

extract () {

    case $N in    

        *.tar.bz2)      `tar -xvjf    $N`;;       

        *.tar.gz)       `tar -xf      $N`;;

        *.tar.xz)       `tar -xvJf    $N`;;

        *.tar)      `tar -xf    $N`;;

        *.lzma)     unlzma      $N ;;

        *.bz2)      bunzip2     $N ;;

        *.rar)      `unrar -x   $N`;;

        *.gz)       `gunzip -k  $N`;;

        *.tbz2)     tar xvjf    $N ;;

        *.tgz)      tar xvzf    $N ;;

        *.zip)      `unzip      $N`;; 

        *.Z)        uncompress  $N ;;

        *.7z)       `7z x       $N`;;

        *.xz)       unxz        $N ;;

        *.exe)      cabextract  $N ;;

        *)          echo "extract_1:  $N - unknown archive method" ;;

    esac

}

#===================================

#extraction:

N=$1 #что бы переменная была видна функции ее надо переназначить

NAME=${1%%.*}_`date +%Y-%m-%d` #идея создавать каталог с оригинальным именем и датой

NAME_1=${1%.*}_`date +%Y-%m-%d` #то же самое

if [ -z "$1" ]; then                            # -z "string" истина, если длина string равна нулю.

echo  "Usage extraction: <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|

|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>" "...script have complet!"

return 1 2>/dev/null

exit 1

fi


if [ "$1" = "*.tar.*" ]; then

mkdir "$NAME"; cp $1 $NAME && cd $NAME #при создании каталога подстановка NAME=${1%%.*} работает "не корректно" ???

extract

ls

elif [ "$1" != "*.tar.*" ]; then

mkdir "$NAME_1"; cp $1 $NAME_1 && cd $NAME_1

extract

echo -n "`pwd`:  "

ls

fi

$

Что бы скрипт стал "рабочий", его надо доделать или переделать, поскольку у архиваторов масса ключей, к каждому надо подойти "индивидуально" исходя из целесообразности, как в случае с "gunzip -k", (ключ "-k" оставляет архив, без ключа удаляет), и так со всеми другими ....., как и запись; cp $1 $NAME && cd $NAME, чтобы не связываться с полными иая относительными путями. Запись "mkdir $NAME", то же от чего то не работает как задумывалось ... .

И тем не менее:

$ chmod +x extraction

$./extraction ccc1.gz

/home/user/ccc1_2020-11-11:  ccc1  ccc1.gz

$./extraction test.tar.gz

/home/user/test.tar_2020-11-11:  archiv_file  test.tar.gz

$./extraction test.tar

/home/user/test_2020-11-11:  tartest  test.tar


==================================== https://devhints.io/bash

Fast command-line directory browsing

cdls() { cd $1; ls; }

To make the command always available, add it to your .bashrc file.

====================================

Fast command-line directory browsing

cdls() { if [[ $1 != "" ]] ; then cd $1; ls; else ls; fi; }

====================================https://www.commandlinefu.com

Как мы говорили выше полезно иметь библиотеку функций, ниже очень "скромный" пример файла функций на рабочей машине, естественно она постоянно пополняется, но до разумных пределов и хотя оперативная память в наше время не проблема все равно не следует забивать ее мусором, поэтому лучше иметь несколько файлов составленных "тематически", Так же не следует забывать, что загрузить файл функций в окружение интерпретатора команд следует с помощью команды "source" или ее псевдонима "точка".

$ cat foonction

#!/bin/bash

############################################

echo -e "Функция калькулятора оболочки с плавающей запятой: \033[1mcalc\033[0m"

echo -e "Функция калькулятора оболочки с плавающей запятой (в чистом виде): \033[1mcalk\033[0m"

echo -e "Функция конвертации байтов в удобочитаемый размер файла: \033[1mhuman_filesize\033[0m"

echo -e "Функция pid процесса, по его имени: \033[1mpidof\033[0m "

echo -e "Функция list добавление восмеричного представления прав для ls -al: \033[1mlist\033[0m "

echo -e "Функция speed: \033[1mspeed\033[0m"

echo -e "Функция найти новый файл в текущей дирректории: \033[1mnf\033[0m"

echo -e "Функция текущий прогноз погоды: \033[1mforecast\033[0m"

echo -e "Функция убивает все процессы принадлежащие Chrome: \033[1mchromekill\033[0m"

echo -e "Функция цветной статус запущенных сервисов: \033[1mservices\033[0m"

############################################

printf "%`tput cols`s"|sed "s/ /_/g"

echo -e ======  "\033[1mLua - Стандартные арифметические операции:\033[0m"  ======

echo "+" - сложение,

echo "-" - вычитание,

echo "/" - деление,

echo "*" - умножение,

echo "%" - "остаток от деления (5%2 == 1)"

############################################

calc() { 

awk 'BEGIN { OFMT="%f"; print "равно: "'"$*"'; exit}'; 

}

############################################

calk(){ 

awk 'BEGIN { OFMT="%f"; print '"$*"'; exit}'; 

}

############################################

human_filesize() { 

awk -v sum="$1" ' BEGIN {hum[1024^3]="Gb"; hum[1024^2]="Mb"; hum[1024]="Kb"; for (x=1024^3; x>=1024; x/=1024) { if (sum>=x) { printf "%.2f %s\n",sum/x,hum[x]; break; } } if (sum<1024) print "1kb"; } ';

}

############################################

pidof() { 

ps acx | egrep -i $@ | awk '{print $1}';

}

############################################

list() {

ls -l | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf("%0o ",k);print}'

}

############################################

speed() {

{ speedtest-cli | egrep 'Download:|Upload:'; date; iw dev | grep ssid; } | sed -e 's/ssid/SSID:/g' -e '$ a === end of report ===' | tee -a speedtest

}

############################################

nf () { 

find . -type f -printf "%T@|%p\n" 2>/dev/null | sort -n | tail -n 1 | ls -l $(awk -F \| '{print $2}'); 

}

############################################

forecast () {

curl http://wttr.in | sed '1,7! d' > wheather; clear; date >> wheather; cat wheather; 

############################################

chromekill () {

kill $(ps x | grep '\/chrome *.* --type=renderer ' | awk '{print $1}')

}

############################################

services() { 

printf "$(service --status-all 2>&1|sed -e 's/\[ + \]/\\E\[42m\[ + \]\\E\[0m/g' -e 's/\[ - \]/\\E\[41m\[ - \]\\E\[0m/g' -e 's/\[ ? \]/\\E\[43m\[ ? \]\\E\[0m/g')\n";

############################################

ttime() {

while sleep 1;do tput sc;tput cup 0 $(($(tput cols)-29));date;tput rc;done &

}

#PS: Можно отвязать от терминала, но врятли это стоит делать...disown

# если хочется видеть перед глазами время, самым лучшим будет переделать переменную PS1:

# PS1='\A>'; export PS1 ----> 10:32> и поместить в профильный файл.


$ . foonction

Функция калькулятора оболочки с плавающей запятой: calc

Функция калькулятора оболочки с плавающей запятой (в чистом виде): calk

Функция конвертации байтов в удобочитаемый размер файла: human_filesize

Функция pid процесса, по его имени: pidof 

Функция list добавление восмеричного представления прав для ls -al: list 

Функция speed: speed

Функция найти новый файл в текущей дирректории: nf

Функция текущий прогноз погоды: forecast

Функция убивает все процессы принадлежащие Chrome: chromekill

Функция цветной статус запущенных сервисов: services

Функция ttime 'Часы в терминале': ttime

__________________________________________________________________________

====== Lua - Стандартные арифметические операции: ======

+ - сложение,

- - вычитание,

/ - деление,

* - умножение,

% - остаток от деления (5%2 == 1)





$ calc 2.56478 + 6.6543

равно: 9.21908


$ human_filesize 3895124000

3.63 Gb

$ human_filesize $(calk 2^10)

1.00 Kb

$ human_filesize $(calk 2^20)

1.00 Mb

$ human_filesize $(calk 2^30)

1.00 Gb

$ human_filesize <<< echo $(calk 2^30)

1.00 Gb



$ pidof conky

2549


$ cd /etc; list

total 2.2M

644 -rw-r--r--  1 root     root                3.0K Dec 25  2022 adduser.conf

644 -rw-r--r--  1 root     root                3.0K Nov  9  2017 adduser.conf.update-old

644 -rw-r--r--  1 root     root                  46 Dec  7  2017 adjtime

644 -rw-r--r--  1 root     root                 185 Nov  9  2017 aliases

755 drwxr-xr-x  3 root     root                4.0K Jan  2  2019 alsa/

...............................            ....................................


~$ speed

Download: 8.68 Mbit/s

Upload:   7.14 Mbit/s

Fri Dec  8 11:08:18 PM MSK 2023

    SSID: ROSTELECOM

=== end of report ===



$ nf

-rw------- 1 user user 4194304 Dec  8 23:09 ./.config/google-chrome/BrowserMetrics/BrowserMetrics.pma


$ forecast

Weather report: St Petersburg, Russia


   _`/"".-.     Light snow shower

    ,\_(   ).   -5(-9) °C      

     /(___(__)  ← 11 km/h      

       *  *  *  3 km           

      *  *  *   0.1 mm         

Thu Dec 14 12:53:26 PM MSK 2023


*** многие утилиты выводт информацию в килобайтах(например free без опции -h, поэтому добавьте три ноля, конечно это не совсем соответствует)


$ human_filesize 3895124000

3.63 Gb


$ free

Mem:         3895124 

$ free -h

Mem:           3.7Gi


Или в байтах:

$ free -b

Mem:      3988606976


$ human_filesize 3988606976

3.71 Gb,


PS:...ну и конечно на каждый случай жизни в *nix существует давно написанная утилита, в случае "human filesize" это numfmt :


$ free -b | numfmt --header --field 2-7 --to=iec

               total        used        free      shared  buff/cache   available

Mem:            3.8G        2.3G        167M        207M        1.4G        1.1G

Swap:           2.1G        252M        1.9G


$ sudo df -B1 | numfmt --header --field 2-4 --to=iec

......etc

ИТОГО

===========================

    Интерполяция, интерполирование (от лат. inter–polis — «разглаженный, подновлённый, обновлённый; преобразованный») — в вычислительной математике нахождение неизвестных промежуточных значений некоторой функции, по имеющемуся дискретному набору ее известных значений, определенным способом. 

Термин «интерполяция» впервые употребил Джон Валлис в своём трактате «Арифметика бесконечных» (1656).   (Линейная интерполяция)  (Data-1. Об анализе данных)

    Аппроксимация (от лат. proxima — ближайшая) или приближение — научный метод, состоящий в замене одних объектов другими, в каком-то смысле близкими к исходным, но более простыми.

----------------------------------------------------

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

===========================

Предикат в програмировании (функциональном...а может и не только) это функция, которая возвращает  два значения в зависимости от переданного значения,  может быть "n" местный, или "n" арный, в более общем смысле это утверждение (заявление), например для systemD  — "такой то вот юнит остановлен", то есть имеет или нет место этот факт, в LUA это всего лишь функция проверяющая какое либо условие и возвращающая логическое значение. В обычном языке как глагол "предицировать" это: утверждать, заявлять, наводить на мысль, проповедовать, предсказывать, как существительное это; утверждение, заявление.

Люди помните! ПРОСТРАНСТВО НЕ ПРЕРЫВНО !!!!!

                                                                                                        "Доказательство ослабляет очевидность" (Цицерон. О природе богов)

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

                                                                                    "Не ищи первичные сущности среди вторичных вещей" (Плотин третья Эннеада)

            Знание о познаваемом находится в познающем, а не в познаваемом, знать есть "обладать", всякое незнание есть  лишенность.                                                                                                                                   "..Знание не есть "иное" нежели Тот в ком оно есть" (Платон)


..... и только подлый (подлежащий, ущербный, не совершенный, общее слово "лишенность")  "человеческий рассудок" заставляет делить наше "прекрасное пространство" на конечные части, вводя нас в заблуждение и обман, "рассудок"  — эйдол Ума, сам по себе ни плох ни хорош, однако рассудок инспирируется здесь как атрибут этого мира, в следствии недостаточности Ума и чем глупее человек, тем более многозначен и примитивен его рассудок. Расчет применим от того, что имеет место "недостаток силы которая прежде расчета, расчет и память необходимы существам не совершенным, не достигшим подлинной разумности, таким как мы например"(Enn-VI ст.84) В "Мире (пространстве)" нет ни чего "конечного" и каждая "точка" пространства содержит в себе информацию о ВСЕМ пространстве. "Ничто не отделено и не отсечено от того что прежде" (Человеческое ЭГО — мелкое, недоразвитое эмпирическое "я", "чужой человек" заставляющее мнить себя "Венцом Творенья", так же БЕСКОНЕЧНО, ..., люди опомнитесь какой "венец"?), и вообще "этот мир" создатель одарил двумя волшебно-загадочными сущностями, это пространство и время.   ..... движимые все­гда в последующее и позднейшее, не оставаясь в тож­дестве, но становясь иными и иными, мы  продлева­ем наш путь все далее и далее, производя время как образ вечности. И что есть время?, как не деятелность души отвернувшейся от созерцания, жизнь души в движении. (Плотин) "Подвижный образ Вечности", пребывающий в Едином (Платон, "Тимей")

"Рассудок - рацио(ratio), пытающийся совершить исследование, поскольку он не есть что-то единое, но разделенное, обращается в своем исследовании  к природе тела и берет оттуда начала [для своих построений], а потому считает и [умопостигаемую] сущность делимой, такой же [как телесная], не верит в ее единство, поскольку не исходит в своем исследовании из начал, свойственных [умопостигаемой] сущности. Мы не отделены от сущего, но есть в нем, неотделимо и оно от нас, все сущие суть одно."  (Плотин шестая энниада ст.333 PDF). Рассудок есть "делитель", атрибут нашего нижнего мира, ему нужны пределы, мира разделенного, этот мир не выносит Единого, Единое ему противопаказано, точнее Оно ему "не посильно", врятли вообще мы способны "жить в Уме" будучи здесь, актуализация Ума в нас представлена "моментами" это и есть "озарение", потому что наш мир "во времени", оттого и пользуемся его эйдолом, и перспективы у нас только одни, Платон называл это "бегством из этой тюрьмы", Плотин говорил о восхождении "из рождения в сущьность" ...ну слава Богу что хоть проблема "поставлена", говорит нам рассудок, но есть способ, правда не на долго, отвязаться от времени, потом неизбежно в него впадая, им пользуются все от шаманов до нобелевских лауреатов, зачастую сами того не понимая, называется "созерцание" ... а лучшего слова не придумали. Ум — молния от неба до неба.

Непрерывность это неотъемлимое свойство "Единого" — Истинно сущего. Непрерывность и неоднородность пространства то что всегда будет приводить в замешательство, .....

Математика для блондинок:  http://www.webstaratel.ru/.html

ЗЕНОН Элейский   (ст. 340)    <------ PDF;  fb2     

".....Вселенная — единое, единомногое "живое существо", разумное, одушевленное и мыслящее, пустоты не существует !"  "Эта Вселенная есть вечный продукт истинной и первой Вселенной Ума, пребывающего в единстве и мире с собой, Вселенной существующей в "ничто", и нет ни чего прежде нее, но то что существует после нее, необходимо существует в НЕЙ". Ум — сын бога!. Мышление — явленная в этот мир энергия Ума. (Плотин Третья эннеада ст. 123)   Платон том 3   <--- "Тимей" ст. 571   Диоген Лаэртский, VII. 140 ст. 287

Творческая деятельность Ума и здесь и ВЕЗДЕ совершенно лишена дискурса, осознающая себя непосредственно, напрямую, Огонь всего лишь стихия, но Ум подобен огню, точнее "молнии", потому и Зевс сын Ума, Кроноса...и ни каких рассуждений и переливаний из пустого в порожнее. 

Вселенная есть симпатически связанное единство всех, живое единое, в котором все далекое - близко, и истинная магия есть Любовь и Вражда во Вселенной, сам мир есть первый колдун и целитель; наблюдая за ним, люди научились использовать взаимодействия его зелий и заклинаний. Все перемещаемые силой природы вещи таковы, как если бы их двигали нитками. Как удивительно, что Вселенная обладает силой и порядком! Все вещи идут своим "безмолвным путем", повинуясь справедливости, которая никогда не прейдет.  (Плотин Enn IV 40-45 ст. 197) Неоплатонизм вовсе не так дуалистичен как это может покзаться. Вечная природа Блага возникающая из "неизреченной силы", не может остаться не подвижной но должна вечно идти вперед вплоть до всех вещей, до крайнего возможного предела, движимая из себя, излучающая из себя все вещи, не оставляя ничему возможности быть непричастной ей и каждая вещь этого Космоса получила столько сколько смогла взять, только определенное количество, что касается наших душ мы не отсечены от Единого, которое "здесь, сейчас и везде" ..и если тебе мало, возьми сколько надо и не откладывай поскольку время этого мира, спешащего не опоздать и неизбежно опаздывающего, изменит твои возможности и как знать в какую сторону?. Величайшая красота в чувственном, есть проявление наилучшего в умопостигаемых сущностях, их сил и благостности. (Плотин Enn IV  ст. 386) ....и если столь прекрасна девица Афродита, сколь более красив Ум, потому "совершенный муж" предпочитает "Афродиту - Уранию"  "Афродите - Пандемос".

.

 

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

    А что касается Зенона, то это был просто веселый человек, "душа компании", желанный гость на многочисленных симпозиумах ... алкоголизм и разврат в итоге погубили "греческую цивилизацию". Давно пора понять и перестать тревожить на протяжении столетий "старика Зенона", понять что: математика не тот инструмент, способный описывать пространство, и это, в отличии от нас, прекрасно понимал Зенон и все его "товарищи", предпочитая математике геометрию, именуя Творца - "Великим геометром", греки, Элейские греки, мыслили категориями качества, оставив нам в наследство логику, логику не "символьную" а систему формального оперирования качественными показателями, способ оперировать смыслом, без превращения его в информацию (количество), впрочем как и математика для древних это искуство, искуство созерцания и медитации, наука о числах прежде всего — "искуство умопостигаемых чисел, чисел сущностных" и только потом исследование "колличественных отношений, чисел количественных", что совершенно непостижимо для современного человека с его рваным сознанием шизофреника, его удел превратить живую логику качества в мертвую логику количества, заменить критерий "истинности" на критерий "полезности, эмпиричности" не говоря о том что формальной логики во времена Зенона просто не существовало, предки еще недожили до Канта.

PS: Формализация — "кастрирование" информации и обеднение представления об исследуемом явлении, объекте и тд...в итоге все упрется в "пределы", как и случае "абстракции".

Сущьность — Бытие в действительности.

Число математический символ всякой определенности и разумности, а "вовсе" не "упорядоченная последовательность символов". Пифагор говоря свое; "Мир число", говорил о разумности Мира, его определенности, а то что вовне это не Мир, это ДРУГОЕ.

Предел для этого мира определяющий "прнцип живого", разделяющий и конституирующий центр, что и есть число, математическая точка в которой исчезает "беспредел" то есть "хаос". Можно сказать что "предел" определяющий принцип для Вселенной, но по отношению к нашему миру это более очевидно.

Монада — единственное начало всего, бессмертная гармония;

Единое (Единое-Благо) то без чего НИЧТО не возможно быть (возникнуть),"трансцендентное первоначало", то что по ту сторону человеческого бытия, чистая действительность без примеси какого либо действия, наиболее близкое понятие китайское "Дао" вечное действие, принцип творения, отвечающий за происхождение единственности и двойственности, начало мира и творения, дословно "путь". Единое как и Дао  — то что всегда, везде и "сечас", это "везде" суть Оно само и если "предел" конституирующий центр всего живого, то Единое его не иссякаемый источник. Диадох ст.7


Идея (в состоянии покоя) — граница Ума и Ум есть движение Идеи. Теологумены арифметики. pdf   Числа и величены (4-5) ст.17


PS: Далеко не все были "пифагорейцы" и разделяли их идеи, достаточно вспомнить Гераклита который называл Пифагора всезнайкой и пустозвоном к тому же не понятно был ли вообще такой человек которого мы сейчас именуем Пифагором, но Гераклиту виднее, все таки современник, но дело конечно не в Пифагоре, а в том что первообразы и первоначала не поддаются ясному изложению на словах, потому что их трудно уразуметь и трудно высказать, от того и приходится для ясности прибегать к числам, язык "числа" может научить нас и помочь нам на пути непос­редственного постижения того, к чему мы стремимся, "число" создает в нас некий особенный, специфично-универсальный образ сочетающий умопостигаемое и количественное, непрерывное и дискретное, образ доступный не только памяти и рассудку, что "перспективно", и эта идея многим пришлась по вкусу в том числе платоникам и неоплатоникам, проблема "слова не изреченного, тихое слово" как говорил Платон она стоит и до сих пор, довольно будет вспомнить Гете: "..мы не понимаем что мы делаем и что мы понимаем невозможно", но Гете был язычник, причем убежденный, и имел в виду, по всей видимости, нечто другое, однако разговор все про то же, про невозможность словами выразить то, что ими выразить не возможно.

И конечно хочется задать вопрос гражданину Пифагору:"..а можно ли языком числа говорить о Едином?", Платон утверждал, что Единое "не выразимо", точнее не познаваемо и не изречимо. Диадох ст.14; "..что касается высшего Единого, то пусть Оно будет почтено совершенным молчанием и прежде всего полным неведением, отвергающим всякое знание" Диадох Дамаскин fb2  Свое понимание тождественности Единого дает Плотин в шестой энниаде Enn VI 4.7 ст.288 

Можно добавить, что Платон в отличии от Аристотеля не доверял рукописям, слову "символьному" и был категорически против филосовских трактатов, что можно заметить в его "диалогах" которые полны противоречий, противоречий осознанных, можно только предполагать что бы он сказал о слове "печатном" и про нашу эпоху "копи-паста". Платон Письма,341c7-dl. ст.493  "...Я думаю, что подобная попытка не явилась бы благом для людей, исключая очень немногих, которые и сами при малейшем указании способны все это найти", вот похоже что эти самые "малейшие указания" он и пытался обозначать противоричивостью своих диалогов, гуманный способ заставить шевелить мозгами.


PS: "Все бытие математики полностью основано на созерцании" Шеллинг Фридрих Вильгельм ст 241 «Система трансцендентального идеализма» (1800), хотя под "созерцанием" Шеллинг похоже понимал некую деятельность Ума в отличии от грека "неоплатоника" который знал "созерцание" как отсутствие всякой деятельности, говоря современным языком "созерцание" есть способность прервать "внутренний монолог", "молчание разума", способность "убить Ум", "созерцание" это то что "поверх" Ума — совершенное единство без сознания двойственности, и что есть Любовь как не воля руководимая сожерцанием, логос — суть созерцание, как это не удивительно для современного минталетета.

"Огонь живет смертью земли, воздух живет смертью огня, вода живет смертью воздуха, земля смертью  воды;  Война  — отец, царь и владыка всего.

.....единое расходясь само с собою сходится  .....путь вверх есть путь вниз  .....как ввеху так и внизу" ....."Высшее" не занимается мироустройством, но Вселенная, Космос существует постольку поскольку существует Бог, который "по ту сторону сущности" тот что "стоит за звездами".

А в нас (всегда) одно и то же: жизнь и смерть, бдение и сон, юность и старость. 

Ибо это, изменившись, есть то, а то, изменившись, есть это..., и так до самого дна "становления". Все "составленное" с неизбежностью распадается, вопрос лишь во времени. 

 Гераклид ф 88 ст. 176 Две модели Космогенеза   ст.61  Космогенез Эмпедокла   ст.85     Гераклид ф 76 ст. 173,149,162; Плутарх 48,49 ст. 44


И прав был поэт, хоть и не оригинален;  

"....... жизнь только слово, есть лишь любовь и есть смерть, и внезапно в вечность превращающийся миг"

"........Ткни пальцем в темноту. Невесть куда, туда куда укажет ноготь.

Не в том суть жизни, что в ней есть, но в вере в то, что в ней должно быть"

"........ И картина видимого мира, как мира призраков в пустоте, где эйдолы появляются и исчезают подобно отражениям в несуществующем зеркале, в своем падении они наносят друг другу тяжелые и сильные удары, безсильный  безсильному, не-сущий —  не-сущему, оказываясь по отношению друг к другу сущими и сильными ", вещам "рожденным" не возможно распространиться "в верх" (самим по себе) , но только "вниз", и все более сходить во множественность, эйдос в материи это призрак, зомби, всего лишь глупая игрушка для демонов, эйдол в эйдоле не в состоянии действовать сам, бытие тел есть бытие того что не существует.

"......Мертвый охотник на мертвых поднимет ружье,..в городе мертвых ночью"


"Зло не может погибнуть", .... но вопрос в том что такое зло? (Платон Теэтет 176b  ст.277 ).  И что есть зло?,  не что иное как закономерный, естественный недостаток ("парадигма эманации" в отличие от "парадигмы творения"), в экстремуме — отсутствие Блага, "лишенность", зло есть "несчастное состояние материи" (не имеющее доли, совместного участия), дефицит Единого, высокая энтропия, подлежащее от того и "подлое". Опыт зла есть "более"  ясное познание блага для тех, чьи силы слишком слабы, чтобы знать зло раньше, чем его испытать. Материя — "абсолютное зло"(не вдаваясь в подробности Materia prima/Materia secunda), "разукрашенный труп", жизнь тела — "неизбежное, но не первичное зло", и о каком таком "зле"как и "добре" может вообще идти речь вне этого чувственного космоса, всего лишь отражении в зеркале материи, как и отражении Красоты, почему и трудно, до конца честно, презирать все ничтожество этого мира, однако "тамошнее" есть единственная причина "здешнего", причем такого какое ЕТЬ.

PS: Конечно была славная когорта "гностиков", которые ненавидели ВСЕ, что принадлежит этому миру, и где они сейчас?...разбежались по сектам,... ненависть слишком энергозатратна. Неоплатонизм к счастью так и не смог переступить через "Красоту", наверное Красота это больше чем сущьность.

Куда бы ты не посмотрел оно везде одинаково: подлежащее фигурам, эйдосам, формам, мерам, пределам, украшенное чужим украшением, то есть не проходящая ложь, не имеющее от себя блага, эйдол в сравнении с сущими — такова сущность зла (если у зла вообще может быть какая-то сущность).  Плотин Enn 1.8.3_ст 272. 

Что касается материи, материя есть эйдол, призрак массы и стремление к ипостасийности, Она устойчива не будучи в покое, невидима сама по себе и избегает всякой попытки ее увидеть; Она возникает, когды ты не видишь, Она невидимв, даже если пристально всматриваться, Она противоположна любым представлениям о ней, Она эйдол не пребывающий и не могущий бежать, ибо ни сама не имеет силы, ни от Ума не берет, Она лищенность всякого сущего, Все за что Она себя выдает есть ложь, Она сама ложь. ... Enn III,6,7 ст.300 

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

То немногое что возможно знать а скорее "предпологать" о материи, поскольку "индукция" как и "аналитика" в случае материи бесполезны (то есть они совсем ни причем), над этим размышляет:  Плотин Enn 2.4 ст 183 

PS: Является ли злом "множественность" — как отпавшая или никогда не бывшая Единым, является ли злом беспредельность — как неисчислимая "множественность"?, неоплатонизм отвечает почти однозначно — ДА, но является  в том насколько "вещь" выходит за свои пределы и подвержена энтропии, а является ли "множественность" злом в мире истинном, умрпостигаемом? НЕТ, поскольку она определяется, "объединена" Единым, она "единомножественна" то есть это ограниченная "безпредельность" (не определенность) и поскольку с необходимостью должно существовать то прекрасное, то есть космическое, "единство-во-многообразии Ума" в котором все сущьности пребывают вместе и вечно. "Беспредельность" существует только в том что "определено" от того и"число" — символ определенности и разумности. На первый взгляд не очень логично но только на первый, как и безмерное не в безмерном, а в имеющем меру, то есть любому разделению и отрицанию предшествуют отрицаемое и делимое. И возможно можно сказать? не претендуя на лавры Платона, что один из основных тезисов неоплатонизма звучит как: "нельзя помыслить число которое уже есть, уже посыслено, невозможно помыслить большего чем уже помыслено"...такая вот "Безпредельность".(Enn VI.6.3 ст.12)

PS: Всякий "демон" есть смесь логоса и неопределенности от того он такой неугомонный, о чем размышляет Плотин в своем великолепном трактате Enn III,7 ст.255 

Люди помните! ...Добродетель сильнее Кармы. Добродетель которой НЕТ на Земле господина! она то что позволяет властвовать над материей. Добродетель сила, иманентная сила Космоса,  неприклонности низшему и восхождение к высшему  (Плотин)

Душа бежит выше всех истин, но все равно потеряет всё что знает, чем обладает,.....  Плотин пятая энниада ст.96  Письма,341c7-dl. ст.493  

...разрешение опорий этого юмориста Зенона, языком современной "математики" очевидное тому подтверждение, пространство есть сущность!, ..не разобрать вам его на "запчасти". То что пространство "сущность" это увы очень, очень спорно, например Платон до известной только ему степени отождествлял материю и пространство и "движение" в его пространстве это движение в пространстве "многоугольников" то есть в различных сферах стихий, то есть одно дело стихия "огня", другое дело движение в пространстве "куба" то есть Земли и тд, как предки совмещали все эти пространственные сферы? кто их знает? ни кто, причем в каждом из пространств можно продвинуться только на единицу этого пространства, куб, меногоугольник, треугольник и тд , и нигде толком  не встретишь какую либо внятную "структуру пространств" (при том что очевидно то, что они его структуировали) и движение в этих структурах соответственно различно а кроме того Платон выделял "чуственное" пространство, материя и пространство для Платона это очень близко это "восприемлющее" и каждое отдельное пространство в его понимании это "феномен". 

Рассудок "идеально"   это чистая аналитика, а аналитический метод это познание в основе которого лежит разложение исследуемой системы, процесса или явления на составные части; выявлении влияния отдельных частей на всю систему, процесс или явление, а для "этого, так называемого мира" на практике это линейное мышление, в отличии от мышленя "ассоциативного", и причем здесь пространство?, можно предположить что наша первичная ошиба в том что мы начинаем мыслить пространство как "объем", какой нахрен "объем", треугольники, многоугольники и прочее это совсем не объемы, объемы нужны нашему воображению и рассудку это его инструменты, ....обясните мне что такое "пространство" и я поведаю вам "все тайны мироздания", все "оставшиеся" тайны.

PS: И как тут не поверишь поэту ?:  ....надо жить без самозванства, так жить что бы в конце концов привлечь к себе любовь пространства, услышать будущего зов.


И еще раз!, непрерывное и дискретное неизбежно связаны, можно сказать "онтологически" и разделяются "рассудком"(нами), непрерывное отделено от дискретного посредствам общей "особенной" границы, а потом и в случае числа разделено четом и не четом. Рассудок "отец" всех "парадоксов", то есть не обоснованности(ложности) проведения пределов или не возможности их провести вовсе. Надо иметь в виду, вспоминая древних, что ни "платонизм" ни "неоплатонизм" не видели ни какого онтоганизма между Умом и Рассудком, "Рассудок" — эйдол Ума, "Мышление" — энергия Ума, и то и другое явлено в нашем "не совершенном мире", все сущее, что мы можем постич рассудком ЕСТЬ в Уме, который не постигает, ОН "знает" то есть "обладает".Enn VI.2 ст.148


Аристотель Категории, 6. 5Ь. ст.15, , ...в обоих случаях разговор ведется о количествах, части которых занимаю или не занимают определенного положения и об их отношениях, в итоге гражданин Аристотель делает вывод, что наиболее характерным для количества является обозначаться как равное и не равное

Структура вакуума.mp4
Анизотропный мир.mp4


.... не ищи причин Начала которое полностью тождественно Цели, поскольку Начало и Конец есть все вместе без недостатка.

Аристотель Физика А 5,6 ст.70


Математические основы автоматических вычислений

Машина Тьюринга — абстрактная модель, абстрактная вычислительная машина (исполнитель), предложена в 1936 г. А.Тьюрингом, для формализации понятия "алгоритм", по средствам имитации всех учасников процесса вычисления в котором каждый шаг элементарен. Машина задает правила перехода (последовательность действий, таблицу) между учасниками для каждого шага вычисления, чем и достигается имитация и в итоге предполагается что любой алгоритм может быть реализован с помощью "некоторой" машины Тьюринга, то есть алгоритм это то что может быть выполнено с помощью машины Тьюринга (ни больше, ни меньше).

"Управляющее устройство" (процессор — аппаратная реализация управляющего устройства машины Тьюринга) или головка чтения-записи, может находиться в одном из множества состояний, число возможных состояний управляющего устройства конечно и точно задано.   Реализация машины Тьюринга на практике 

Детерминированная машина Тьюринга  — машина где каждой комбинации состояния и ленточного символа в таблице соответствует не более одного правила. Недетерминированная машина Тьюринга — машина где каждой комбинации состояния и ленточного символа в таблице соответствует более одного правила (команды, инструкции).

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

Неформально машина Тьюринга определяется как "устройство", состоящее из двух частей:

— бесконечной одномерной ленты, разделённой на ячейки,

— головки, которая представляет собой детерминированный конечный автомат. ("машину состояний")

PS: Конечный автомат (КА) в теории алгоритмов — математическая абстракция, модель дискретного устройства, имеющего один вход, один выход и в каждый момент времени находящегося в одном состоянии из множества возможных, может быть как программным так и аппаратным. 

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

Алгоритм — от имени персидского математика Мухаммад ибн Муса аль-Хорезми, термин "алгебра" то же от него.

Алгоритм — конечный набор инструкций, определяющий решение задачи посредством конечного количества операций». (ISO 2382 / 01.05.05)


Вычислительный процесс — выполнение "чего либо" находящихся по адресу "А" над "чем либо" находящимися по адресу "В", по средствам алгоритма точнее "инструкции", можно сказать, что над чем выполнять, или взаимодействие двух потоков, потока команд и потока данных на конечном автомате (операционном устройстве), по средствам локализации объемов памяти тождественно с физико-техническими возможностями этих локализованных областей и данных, с целью достижения нужной тактовой частоты работы (обработки данных)  операционного устройства, процессора, через увеличение скорости потоков, по этому одной из основных характеристик является "единица пересылки информации" между локализованными объемами памяти, как и методы доступа; последовательный, прямой, произвольный и ассоциативный.

PS: Объяснить толком почему уменьшая или скорее соизмеряя какие либо объемы данных и методы доступа, получается увеличение скорости потоков, увы ни кто не способен, и по этому это "иманентное" свойство мышления называют по разному, например кто то ввел в обращение словосочетание "принцип локальности", точнее это определение, залезая в полные дебри "принцип локальности-близкодействия" и хотя это уже чистая физика котроая звучит как: "на объект влияет только его непосредственное окружение", очевидно что  параллели очевидны,..однако разрешение этой проблемы похоже за пределами вычислительной техники.

PS: Как результат, одно из "грандиозных" достижений теоретической информатики, это Ассоциативные массивы АЗУ, как и иерархическая структура памяти в ЭВМ.

PS: С другой стороны здесь нет ни какой "черной магии", то есть вполне естественно что если в конечной точке тракта, той что непосредственно перед процессором стоит какой то, не большой по размеру (поскольку есть время доступа), быстро откликающийся объем памяти, то и производительность процессора будет больше, ...как то так. наверное?, и вообще как учат нас древние: сначала локализация тоесть определение пределов, потом выбор парадигмы (в зависимости от физико-технических свойств локализованного ), а потом результат или его отсутствие.  Управление памятью часть 1 03:50

Лекция 2 Алгоритмы и машина Тьюринга.mkv

Антиномия дуально-противоречивое по смыслу выражение. 

Четыре антиномии по Канту

Математические антиномии: 

1) мир безграничен мир ограничен; 

2) всё в мире состоит из простого нет в мире ничего простого; 

Динамические антиномии: 

3) в мире есть причинность через свободу в мире нет причинности через свободу; 

4) существует первопричина мира (Бог) не существует первопричины мира.

Лекция 9 Способы представления информации в ЭВМ и методы адресации.mp4

31:01  — Адресация

39:50  — Сегментация

48:56  — Дискрипторные таблицы (внутри сегмента  — аналитическая адресация, инкрементно/дикрементный способ, то есть - поступательный, в ту или другую сторону, как наиболее простой и быстрый)

17:37  — Погрешность представления двоичных чисел


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


ПЗУ — https://vr-boom.ru/postoyannoe-zapominayushhee-ustrojstvo 

Система команд — спецификация соответствия микро-команд наборам кодов микро-операций, выполняемых при вызове команды, определяемых микро-архитектурой системы. — https://dfe.petrsu.ru/microcpu/arch3.html 

Организация ЭВМ и систем. Орлов,Цилькер.pdf <----------PDF

Пятибратов: сети и телекоммуникационные системы.pdf <---PDF

Система кодирования команд и способы адресации  <----YouTube

алгоритм fork

входная информация: отсутствует

выходная информация:

для родительского процесса — идентификатор (PID) порожденного процесса

для порожденного процесса — 0


{

проверить доступность ресурсов ядра;

получить свободное место в таблице процессов и уникальный код идентификации (PID);

проверить, не запустил ли пользователь слишком много процессов; 

сделать пометку о том, что порождаемый процесс находится в состоянии «создания»;

скопировать информацию в таблице процессов из записи, соответствующей родительскому процессу, в запись, соответствующую порожденному процессу;

увеличить значения счетчиков ссылок на текущий каталог и на корневой каталог (если он был изменен);

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

поместить в стек фиктивный уровень системного контекста над уровнем системного контекста, соответствующим порожденному процессу; /* фиктивный контекстный уровень содержит информацию, необходимую порожденному процессу для того, чтобы знать все о себе и будучи выбранным для исполнения запускаться с этого места; */

if (в данный момент выполняется родительский процесс) { перевести порожденный процесс в состояние «готовности к выполнению»; return (идентификатор порожденного процесса); /* из системы пользователю */

}

else { /* выполняется порожденный процесс */

записать начальные значения в поля синхронизации адресного пространства процесса;

return (0); /* пользователю */

}

алгоритм ехес 

входная информация: имя файла список параметров список переменных среды

выходная информация: отсутствует


{

получить индекс файла (алгоритм namei);

проверить, является ли файл исполнимым и имеет ли пользователь право на его исполнение;

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

скопировать параметры, переданные функции, из старого адресного пространства в системное пространство;

for (каждой области, присоединенной к процессу) отсоединить все старые области (алгоритм detachreg);

for (каждой области, определенной в загрузочном модуле) { выделить новые области (алгоритм allocreg); присоединить области (алгоритм attachreg);

загрузить область в память по готовности (алгоритм loadreg);

}


скопировать параметры, переданные функции, в новую область стека задачи;

специальная обработка для setuid-программ, трассировка;

проинициализировать область сохранения регистров задачи (в рамках подготовки к возвращению в режим задачи);

освободить индекс файла (алгоритм iput);

}

Теория_алгоритмов.pdf

алгоритм open 

входная информация: имя файла режим открытия права доступа (при создании файла) 

выходная информация: дескриптор файла 


{

превратить имя файла в идентификатор индекса (алгоритм namei); 

if (файл не существует или к нему не разрешен доступ) return (код ошибки); 

выделить для индекса запись в таблице файлов, инициализировать счетчик, смещение;

выделить запись в таблице пользовательских дескрипторов файла, установить указатель на запись в таблице файлов;

if (режим открытия подразумевает усечение файла) освободить все блоки файла (алгоритм free);

снять блокировку (с индекса); /* индекс заблокирован выше, в алгоритме namei */

return (пользовательский дескриптор файла);

}

алгоритм pipe

входная информация: отсутствует

выходная информация: дескриптор файла для чтения дескриптор файла для записи


{

назначить новый индекс из устройства канала (алгоритм ialloc); 

выделить одну запись в таблице файлов для чтения, одну — для переписи; инициализировать записи в таблице файлов таким образом, чтобы они указывали на новый индекс;

выделить один пользовательский дескриптор файла для чтения, один — для записи, проинициализировать их таким образом, чтобы они указывали на соответствующие точки входа в таблице файлов;

установить значение счетчика ссылок в индексе равным 2; установить значение счетчика числа процессов, производящих чтение, и процессов, производящих запись, равным 1;

}

Различие аналогового и цифрового трактов в электротехнике можно определять через понятия "непрерывности" и "дискретности",

Аналоговый тракт, тракт где сигнал имеет непрерывный диапазон значений.

Цифровой тракт, тракт где сигнал имеет дискретное, конечное число состояний, в линиях связи транслируется импульсами или потенциалами, именно так  передаются как компьютерные данные, так и оцифрованные речь и изображение, на практике часто по средствам АЦП (Аналого-цифровой преобразователь Analog-to-digital converter, ADC)

Основная цель создания и использования "Персоональных вычислительных систем" ПК – формализация профессиональных знаний. Вопрос конечно в том, что есть "профессиональное знание" и подлежит ли оно формализации, возможно ли его формализовать?, поскольку можно так "формализовать" профессиональные знания, что они станут совсем не профессиональными и совсем не знаниями, однако существует такое мнение. С другой стороны "профессиональное знание" есть функция в нашем современном понимании, ...остается определить ей интерфейсы.

Лекция 10 Объектно ориентированное программирование.mp4
Настоящие прграммисты не используют Паскаль.pdf

Объектно ориентированное програмирование, общие понятия

07:35 — формализация, объекты, сообщения, методы — код обработки сообщений, условно "функции"

12:00 классы объектов — набор абъектов с одинаковыми методами обработки сообщений.

18:42 инкапсуляция — центральное понятие ООП, локализация свойств, методов и пр. пр объекта, доступ к "капсуле" определяется заданными интерфейсами, как пример сетевая модель OSI, процесс инкапсуляции и декапсуляции.

34:33 Персистентность - возможность долговременного хранения состояния

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

38:53 полиморфизм

53:50 unix

59:45 наследование, создание более сложных обектов из более простых.

01:08:36 агрегирование (com/dcom)


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

В общем случае в разных языках программирования термин «инкапсуляция» относится к одной или обеим одновременно следующим нотациям:

Полиморфизм — позволяет писать более абстрактные программы и повысить коэффициент повторного использования кода. Общие свойства объектов объединяются в систему, которую могут называть по-разному — интерфейс, класс. Общность имеет внешнее и внутреннее выражение:

Техническая реализация ООП в языке программирования

 cs.mipt.ru Тормасов А.А              ООП Функции-Методы 

Лекция 11 Техническая реализация ООП в языке программирования С++.mp4

                        

                 Функциональное програмирование 

F_P.mp4

                                    LUA Функции

                                                                                                     Функции основной механизм абстракции операторов и выражений

Типизация Система типов — совокупность правил в языках программирования, назначающих свойства, именуемые типами, различным конструкциям, составляющим программу — таким как переменные, выражения, функции или модули. 

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

Динамическая типизация — приём, используемый в языках программирования и языках спецификации, при котором переменная связывается с типом в момент присваивания значения, а не в момент объявления переменной. Таким образом, в различных участках программы одна и та же переменная может принимать значения разных типов. Примеры языков с динамической типизацией — Smalltalk, Python, Objective-C, Ruby, PHP, Perl, Lua,.....

Тип значения, сохранённого в переменной, можно выяснить при помощи стандартной функции type:

> t = type (type) print(t) 

function

> t = type ("...ffff") print(t)  

string

> t = type (123) print(t) 

number

> t = type (true) print(t)  

boolean

> t = type (nil) print(t)  

nil

> t = type (_G) print(t)

table

Online Lua Compiler 

https://www.w3big.com/lua

https://ru.wikibooks.org/wiki/LUA

https://coderlessons.com/lua-funktsii

https://archive.kolenka.net

http://lua-users.org/FunctionsTutorial 

The Lua Programming Language <----------------

Programming in Lua  <------------ PDF ст. 66

Lua 5.3 Руководство   <-----------


Lua — это процедурный динамически типизированный модульный язык с автоматическим управлением памятью. Включает базовые элементы для поддержки функционального и объектного стилей программирования (в Lua нет понятия класса; каждый объект определяет свое собственное поведение и состояние, но есть понятие "прототип"). Таким образом, Lua можно называть полимодельным, мультипарадигменным языком, языком расширений для поддержки общего процедурного программирования с возможностью описания данных. 

Sequential Functional Concurrent, models of computation

Как и везде функции служат для оптимизации кода по средствам запуска одного и того же фрагмента кода из нескольких мест без необходимости его дублирования, хотя функции в  Lua имеют более широкое значение это не только "фрагмент кода" это прежде того значения (значения первого класса, тип function). Функции в Lua основной механизм абстракции операторов и выражений. Функции могут выполнять определенное задание (процедуры) или вычислять и возвращать значения. 

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

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

> print(8*9, 9/8)

72 1.125

> a = math.sin(3) + math.cos(10)

> print(a)

-0.69795152101659

> print(os.date()) -- если у вызова функции нет аргументов, то мы все равно должны написать пустой список () для обозначения вызова, однако есть исключения.

Sat Feb 18 21:03:13 202


*** t(_G): print function: 0x5568ce53a630

       type function: 0x5568ce53a310

       string table: 0x5568cf78fbb0

В обоих случаях заключение списка аргументов в круглые скобки обозначает вызов (объектно оринтированный), это обычный вызов функции в Lua. 

То что можно причислить к syntactic sugar: если у функции всего один аргумент и этот аргумент либо строковый литерал, либо конструктор таблицы, то круглые скобки необязательны: 

> print "Hello World"

Hello World

> dofile 'a.lua'

> print [[a multi-line message]]

a multi-line message

> f{x=10, y=20}

> type{}

Все это не привычно после классически-продцедурного (императивного) определения функций, например в оболочках типа sh, но это и есть "объектно-орентированный" взгляд на код, или скорее "функциональный".  (Статья не мальчика, ....). Функцию можно записать и в более привычном для продцедурного программирования виде, о чем ниже.

Функция определение:


Функция с помощью выражения (expression) создается с использованием ключевого слова function следующим образом:

function (args) [тело функции] end

В примере ниже показана простая функция, которая получает один аргумент и возвращает двойное значение:

> foo = function(n) return n*2 end

> = foo(7)

14

равнозначная запись:

> foo = function(n)

return n*2

end

> = foo(7)

14


> foo = function(n) return(n) end

> = foo(5)

5

> foo = function() print(5) end

> = foo()

5

PS: В интерактивном режиме вы можете напечатать значение любого выражения, набрав строку, начинающуюся со знака равенства, за которым следует выражение:

> a = 30

> = a

30

> = math.sin(3) 

0.14112000805987

> = a + 3

33

>


Функция с помощью инструкции (построчного набора команд): 

-- традиционное определение функции


function [имя функции]( arg1, arg2, arg3........,)

[тело функции] 

return [возвращаемые значения через запятую]

end


> function foo(n)

return n*2 

end

> foo(7)

14

> = foo(7)

14


> function foo(n)

return n*2,n*3,n 

end

> foo(7)

14 21 7

  Поскольку функции в Lua это значения, то существуют и выражения которые создают функции, по сути этот так называемы "традиционный" способ написания функции это очередной "syntactic sugar", определение функции — это по сути оператор (если точно присваивание, ниже читай про "множественное присваивание"), который создает значение типа "function" и присваивает его переменной, поэтому ближе к языку будет так:

> sum = function(x,y) return x+y end

> sum(1,2) 

3

*** выражение function f () body end

    транслируется в f = function () body end

В ФП знак равенства означает "связывание" sum будет ссылаться на выражение: function(x,y) return x+y end, точнее его значкние.

В концепции ФП программа это выражение, ее выполнение или "редукция"

есть вычисление этого выражения.

-- складывает элементы последовательности 'a'

function add (a)

local sum = 0

for i = 1, #a do

sum = sum + a[i]

end

return sum

end


#a   # - это "оператор длинны"(возвращает номер последнего ключа в массиве, или длинну последовательности):

> a = "hello" 

> print(#a) 

5

> print(#"good\0bye") 

8


[i] - квадратные скобки используются для индексации

0   —  число (целое)

"0" —  строка  

Попутно вспомним оператор for & for:

for i = iMin, iMax [, <шаг>] do

  [строки_скрипта]

  [break]

  [строки_скрипта]

end 

Где:

i числовая переменная/счётчик

iMin начальное значение отсчета.

iMax конечное значение отсчета (включительно).

шаг шаг цикла (значение, которое при каждом цикле прибавляется к i). Может быть положительным или отрицательным. Если не указан, то равен 1(умолчание).

iMin, iMax, шаг вычисляются только один раз, перед выполнением цикла.

break команда прерывания цикла. Передаёт управление на строку, находящуюся сразу за end. Допустимо использование дробных чисел. Разделитель точка.

Lua хранит переменные (как и прочие данные, в том числе и функции) в таблицах, глобальные переменные содержатся в таблице _G для перебора всех данных таблицы, используется итератор pairs (Общий for ст. 59, pairs (t)) следующим образом: 

> for key,value in pairs(_G) do print(key,value) end

например: 

> summ = function(x,y) return x+y end 

> zumm = 123456789

> for key,value in pairs(_G) do print(key,value) end 

..................................................

summ function: 0x5580c3534ca0

zumm 123456789

Кратко и доходчиво: https://xgm.guru/105934 

PS: Что бы загрузить нужную версию Lua надо ее указать, конечно предварительно загрузив ее из репозитория:

$ ls -la /usr/bin/lua*

Dec 10  2022 /usr/bin/lua -> /lua-interpreter

Dec 10  2022 /usr/bin/lua5.2

Jul 17  2022 /usr/bin/lua5.4

Dec 10  2022 /usr/bin/luac -> /lua-compiler

Dec 10  2022 /usr/bin/luac5.2

Jul 17  2022 /usr/bin/luac5.4


$ lua

Lua 5.2.4  Copyright (C) 1994-2015 Lua.org

> print(_VERSION) 

Lua 5.2

> ^C

$ lua5.4 

Lua 5.4.4  Copyright (C) 1994-2022 Lua.org

> print(_VERSION) 

Lua 5.4

 

$ lua

> print(_VERSION)

Lua 5.3

> function add (a)

local sum = 0

for i = 1, a do

sum = sum + a   

end

return sum

end

> add (5)

25

> add (20)

400

>

> function add (a) local sum = 0 for i = 1, a do sum = sum + a end return sum end 

> add (30)

900

>

*** Lua не нужен разделитель между идущими подряд операторами, как и переводы строк, но для читаемости кода можно использовать точку с запятой, если хочется.

> function add (a) local sum = 0; for i = 1, a do; sum = sum + a; end return sum; end; 

> add(40)

1600

>

В этом примере наверное надо обратить внимание на переменную local sum = 0 кроме того что это начало счетчика итераций, это локальная переменная, хороший стиль программирования заключается в применении локальных переменных везде, везде где это возможно, это способ избежать засорения глобального окружения, к тому же  доступ к локальной переменной быстрее, чем к глобальной. И наконец, локальная переменная перестает существовать, как только заканчивается ее область видимости, позволяя сборщику мусора освободить память, занимаемую ее значением, что и имеется в виду под термином "увтоматическое управление памятью", в отличие от глобальных переменных (которые не требуют объявления), область видимости локальной переменной ограничена блоком, где она была объявлена, и заканчивается на первом "не пустом" операторе блока.

4.2. Локальные переменные и блоки (ст. 53)

PS: Во избежании лишних загадок, следует помнить, что; в интерактивном режиме каждая строка — это самостоятельный кусок chunk (кроме случая, когда команда набрана не полностью, что будет отражено как; >>), например:

> sum = function(x,y) return x+y end

> sum(1,2) 

3

> sum = function(x,y)

>> return x+y

>> end

> sum(1,2) 

3

Устойчивая идиома, пример хорошего кода:

> local sum = sum 

> sum = function(x,y) return x+y end 

> sum(1,2) 

3

3.4.11 – Определения функций

Одним из оригинальных черт языка является определение, что такое функция, функция в Lua  — это значения, что хорошо демонстрирует приведенный выше пример в котором мы фактически не «именовали» функцию, а просто присвоили ее переменной и имя переменной опять таки "фактически" становится именем функции, это не столько пример формализации, сколько пример функции как значения и какую гибкость приобретают функции в Lua, при объектно-ориентированном, функциональном подходе. 

И поскольку функции в Lua являются обычными значениями (числами, строками, таблицами и т. д.), вы можете делать с ними все, все то что вы можете делать с любыми другими значениями. Это выгодно отличается от многих других языков (например, C), где функции имеют постоянные имена, фиксированные во время компиляции, и ими нельзя манипулировать как значениями, что первоначально вызывает некоторую трудность в понимании что такое "функция" в Lua, ну и очевидно что отличается от языков оболочек типа sh, bash  и тд.

Блок function [имя функции]  — это выражение (в том же смысле, что «1 + 2» — это выражение), результатом которого является новое значение функции. Значение функции можно вызвать с помощью оператора двойные скобки, который обязателен не зависимо от того содержит он аргументы или нет и который запускает код функции, —  это вызов функции. Двойные скобки () указываются после функционального выражения и могут содержать или нет, список аргументов, разделенных запятыми, о чем ниже. Lua также предлагает специальный синтаксис для объектно-ориентированных вызовов — операцию двоеточия, то что называется syntactic sugar, альтернативный способ записи уже имеющейся в языке синтаксической конструкции, и при этом являющийся более удобным, "sweeter" for human use" например: о:foo(x) это то же самое что o.foo(o,x)

Все это означает, что функции в Lua  анонимные (без предустановленного имени) и "первоклассные" ("first class value" и это прямая реплика функционального програмирования, важнейшая характеристика, в том смысле что функции не обрабатываются иначе, чем другие значения), с соответствующей "лексической областью видимости". Что для функций означает быть "значениями первого класса"? Это значит, что в Lua функция — это значение, обладающее теми же правами, что и традиционные значения вроде чисел и строк, означает что все значения могут быть сохранены в переменных, переданы как аргументы другим функциям, и возвращены как результаты. Мы можем хранить функции в переменных (локальных и глобальных) и таблицах, мы можем передавать функции как аргументы и возвращать их из других функций. Что для функций означает иметь "лексическую область видимости"? Это значит, что функции могут обращаться к переменным окружающих их функций.

Следует также помнить, что, как и таблицы (фундамент для всех пользовательских типов данных в Lua, удаляются из памяти "сборщиком мусора", когда исчезает последняя ссылка), функции так же передаются  по ссылке. Например, когда вы присваиваете переменной, содержащей функцию, другой переменной, вы просто создаете новый «дескриптор» той же функции. Все стандартные библиотеки в Lua написаны на С. Они включают в себя функции для работы со строками, работы с таблицами, ввод/вывод, доступ к базовым возможностям операционной системы, математические функции и отладку (Built-in function — встроеннные).

Как правило мы прибегаем к функциям С или Bash(или любого другого языка используемого в качестве "основного приложения") для достижения более высокого быстродействия и для доступа к средствам, недоступным непосредственно из Lua, таким как средства операционной системы.

***** Форма Бэкуса-Наура (БНФ) используется для описания контекстно-свободных формальных грамматик: <определяемый символ> ::= <посл.1> | <посл.2> | . . . | <посл.n>

( ::= или ->  читается как "это есть) знаки определения, к Lua имеет отношение "постольку-поскольку"

Аргументы (они же параметры) — указываются внутри скобок ( ), а значения возвращаются из функции с помощью ключевого слова return. Функция всегда должна что то возвращать без return функция не возвращает никаких значений, точнее так: "оператор return возвращает результаты из функции, если они есть, или просто завершает ее. В конце каждой функции присутствует неявный возврат из нее, поэтому нам необязательно его использовать если  функция завершается естественным образом не возвращая никакого значения. Из синтаксических соображений оператор return может быть только последним оператором блока. Иногда, тем не менее, удобно писать return в середине блока; например, вы можете отлаживать функцию и хотите избежать ее выполнения. В подобных случаях вы можете использовать явный блок do вокруг оператора return":

function foo ()

return         -- << СИНТАКСИЧЕСКАЯ ОШИБКА 'return' является последним оператором в следующем куске

do return end -- OK

<другие операторы>

end

При вызове функции , принимается во внимание значение аргумента (параметра, если он есть), список параметров относится к типу, порядку и количеству аргументов метода, аргументы необязательны, то есть метод может не содержать аргументов например так: 

function foo()

PS: В терминологии ООП, не вдаваясь в детали, термины метод и функция можно считать равнозначными.

[имя функции, она же переменная] = function (args) [тело функции] end

Имя функции, как писалось выше — это формальное имя функции (функция сама по себе имени не имеет, как и любое значение, но какая либо переменная может указывать на значение "имя_функции", грубо говоря это ссылка на число, строку как и на любой тип данных)  и опять таки наиболее нагляден первый пример где функция возвращает значение в переменную foo или еще пример, пример базовой (встроенной) функции print говоря об имени функции print, на самом деле мы имеем в виду переменную, которая хранит данную функцию. Имя функции и список параметров вместе составляют сигнатуру или характеристическую часть определения функции то есть исполняемого выражения, значение которого имеет тип function.

Тело функции — или метода, содержит коллекцию операторов, которые определяют, что делает функция.

Область действия функции (не обязательно) — используя ключевое слово local (в теле функции) можно ограничить область действия функции или игнорировать раздел области действия, что сделает ее глобальной функцией.

end — обязательное ключевое слово завершающее код функции или его часть.

Множественные результаты, множественное присваивание

string. find, string.find  функция сопоставления шаблонов, Строковая библиотека предоставляет все свои функции в таблице string 

> for key,value in pairs(string) do print(key,value) end

dump function: 0x556eb05d9690

packsize function: 0x556eb05d9ea0

rep function: 0x556eb05d8720

byte function: 0x556eb05d99d0

gmatch function: 0x556eb05d8b90

find function: 0x556eb05dba30

match function: 0x556eb05dba20

sub function: 0x556eb05d98d0

format function: 0x556eb05d8da0

upper function: 0x556eb05d85c0

lower function: 0x556eb05d88b0

gsub function: 0x556eb05db090

pack function: 0x556eb05d9ff0

unpack function: 0x556eb05da5f0

reverse function: 0x556eb05d8670

char function: 0x556eb05d8c60

len function: 0x556eb05d82b0


> s, e = string.find("hello Lua users", "Lua")

> print(s, e) 

7 9

> s, e = string.find("hello Lua users", "user")

> print(s, e) 

11 14

>

"hello Lua users" - строка

"Lua"             - шаблон

Если успешно, функция возвращает два индекса: 

индекс символа, с которого начинается шаблон, и индекс символа, на котором он заканчивается.

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

Lua всегда приводит количество результатов функции к обстоятельствам ее вызова. Когда мы вызываем функцию как оператор, Lua отбрасывает все результаты функции. Когда мы используем вызов как выражение ("список"), Lua о ставляет только первый результат. Мы получаем все результаты лишь тогда, когда вызов является последним (или единственным) выражением в списке выражений. В Lua эти списки встречаются в четырех конструкциях: 

множественные присваивания

аргументы в вызовах функций 

конструкторы таблиц  

оператор return 

Допустим, что у нас есть такие определения функций:

PS: Что есть "определения функции" это то что определяет действия, которые выполняет функция в процессе исполнения, в свою очередь область определения  — это множество, на котором задаётся функция.

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

> function foo0() end 

> foo0()

> function foo1() return "a" end 

> foo1() 

a

> function foo2() return "a", "b" end 

> foo2() 

a b

> for key,value in pairs(_G) do print(key,value) end

foo0 function: 0x55ca86213790

foo1 function: 0x55ca862174c0

foo2 function: 0x55ca86217bc0


function foo0() end -- возвращает 0 значений

function foo1() return "a" end -- возвращает 1 значение

function foo2() return "a", "b" end -- возвращает 2 значения

— множественные присваивания

При множественном присваивании вызов функции в качестве последнего (или единственного) выражения произведет столько

результатов, сколько у нас переменных, к примеру присвоим функции foo2() такие варианты переменных (значений):

> x,y = foo2() 

> print(x,y)

a b

> x = foo2() 

> print(x)

a  (b отбрасывается)

> x,y,z = 10,foo2() 

> print(x,y,z)

10 a b

Если функция не возвращает значения или возвращает их меньше, чем нужно, то Lua произведет в качестве недостающих значений nil:

> x,y = foo0() 

> print(x,y)

nil nil

> x,y = foo1() 

> print(x,y)

a nil

> x,y,z = foo2() 

> print(x,y,z)

a b nil

Вызов функции, который не является последним элементом в списке, всегда дает один результат:

> x,y = foo2(), 20 

> print(x,y)

a 20

> x,y = foo0(), 20, 30 

> print(x,y)

nil 20    (30 отбрасывается)


— аргументы в вызовах функций 


Когда вызов функции является последним (или единственным) аргументом другого вызова, то все результаты первого вызова

передаются как аргументы для второго.

> print(foo0()) 


> print(foo1()) 

a

> print(foo2()) 

a b

> print(foo2(), 1) 

a 1

> print(foo2() .. "x") 

ax

> Когда вызов функции foo2 происходит внутри выражения, Lua приводит число результатов к одному; поэтому в последней строке конкатенация использует только "а"


PS:Операция .. служит в Lua для конкатенации строк. Когда вы записываете ее сразу после числа, вы должны отделить их друг от друга при помощи пробела; иначе Lua решит, что первая точка — это десятичная точка числа.

— конструкторы таблиц 


Конструктор таблицы тоже собирает все результаты вызова, без каких-либо изменений:

t = {foo0()} -- t = {} (пустая таблица)

t = {foo1()} -- t = {"a"}

t = {foo2()} -- t = {"a", "b"}

t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4

Для перебора всех данных в таблице используется оператор pairs (подробнее тут: https://xgm.guru/105934 )

> t = {foo0()} 

> for key,value in pairs(t) do print(key,value) end 

> пустая таблица

> t = {foo1()} 

> for key,value in pairs(t) do print(key,value) end 

1 a

> t = {foo2()} 

> for key,value in pairs(t) do print(key,value) end 

1 a

2 b

> t = {foo0(), foo2(), 4} 

> for key,value in pairs(t) do print(key,value) end

> пустая таблица

2 a

3 4

> t = {foo0(),foo1(), foo2(), 4} 

> for key,value in pairs(t) do print(key,value) end

> пустая таблица

2 a

3 a

4 4

— оператор return


Оператор типа return f() возвращает все значения, возвращаемые f:

> function foo (i) 

>> if i == 0 then return foo0() 

>> elseif i == 1 then return foo1() 

>> elseif i == 2 then return foo2() 

>> end

>> end


> print(foo(1)) 

a

> print(foo(2)) 

a b

> print(foo(0)) 


> print(foo(3)) 


>

Мы можем заставить вызов вернуть ровно один результат, заключив оператор в дополнительную пару круглых скобок, любая пара круглых скобок, помещенная там, считается дополнительной. Поэтому оператор вроде return(f(х)) всегда возвращает ровно одно значение, вне зависимости от того, сколько значений возвращает функция f. Иногда это именно то, что нам нужно, иногда нет.

> print((foo0())) 

nil

> print((foo1())) 

a

> print((foo2())) 

a


Специальной функцией, возвращающей несколько значений, является table.unpack Она получает массив и возвращает в качестве результатов все элементы этого массива, начиная с индекса 1:

print(table.unpack{10,20,30})

a,b = table.unpack{10,20,30}

--> 10 20 30

-- a=10, b=20, 30 отбрасывается


> print(table.unpack{10,20,30}) 

10 20 30

> a,b = table.unpack{10,20,30} 

> print(a,b) 

10 20

> a,b,c = table.unpack{10,20,30}

> print(a,b,c) 

10 20 30

> a,b,c,d = table.unpack{10,20,30} 

> print(a,b,c,d) 

10 20 30 nil

В Lua, если вы хотите вызвать функцию f с переменным числом аргументов, хранящимся в массиве а, вы просто пишите так f(table.unpack(a)) . Вызов unpack возвращает все значения из а, которые становятся аргументами вызова f. Например, рассмотрим следующий вызов:  ( string.find)

> print(string.find("hello", "ll")) 

3 4


> print(string.find("hello", "lo")) 

4 5

эквивалентный вызов:

> f = string.find 

> a = {"hello", "ll"} 

> print(f(table.unpack(a))) 

3 4

можно задать явные границы:

> print(table.unpack({"Sun", "Mon", "Tue", "Wed"}, 2, 3)) 

Mon Tue

Хотя предопределенная функция unpack написана на С, мы могли бы написать ее на Lua, используя рекурсию:

> f = string.find 

> a = {"hello", "ll"} 

> print(f(table.unpack(a))) 

3 4

>

 

> for key,value in pairs(_G) do print(key,value) end

unppack function: 0x5580cc4989e0

> function unppack (t, i, n)

>> i = i or 1 

>> n = n or #t     -- оператор длинны

>> if i <= n then

>> return t[i], unppack(t, i + 1, n) 

>> end

>> end

> print(f(unppack(a)))

3 4

Первый раз, когда мы вызываем ее с единственным аргументом, i получает 1, а n получает длину последовательно сти. Затем функция

возвращает t[1] вместе со всеми результатами unpack(t,2,n), что, в свою очередь, возвращает t[2] со всеми результаты unpack(t,3,n) и т. д., останавливаясь после n элементов.

variadic function

Функция в Lua может быть вариадической (variadic), т.е. иметь переменное число аргументов. Пример предопределенная функция print вызываемая с одним и более аргументами и хотя print штатно определена в С, мы можем то же самое сделать средствами Lua:

$ lua

Lua 5.3.6  Copyright (C) 1994-2020 Lua.org, PUC-Rio

> function add (...)   -- три точки указывают на то, что функция вариадическая

>> local s = 0 

>> for i, v in ipairs{...} do  -- выражение {...} производит массив со всеми собранными аргументами

>> s = s + v 

>> end

>> return s 

>> end

> print(add(3, 4, 10, 25, 12)) 

54





print 'hello world' -- syntactic sugar for print('hello world')

options { verbose=true, debug=true } -- syntactic sugar for options( { ... } )

t = { surname = 'majumdar' }      -- t.surname is sugar for t['surname']

t.name = 'dibyendu'               -- syntactic sugar for t['name'] = 'dibyendu'

x:foo('hello')                   -- syntactic sugar for foo(x, 'hello')

object:method(arg)              -- is syntactic sugar for method(object, arg)

function foo(n)                         -- is syntactic sugar for foo = function(n)

Programming in Lua  <------------ PDF ст. 35

Тип table представляет ассоциативные массивы — это массив, который может быть индексирован не только числами, но и строками или любым другим значением языка, кроме nil. Lua использует таблицы для представления пакетов и объектов. Когда мы пишем io.read, мы думаем о «функции read из модуля io». Для Lua это выражение означает «индексировать таблицу io, используя строку read в качестве ключа».

Таблицы в Lua не являются ни значениями, ни переменными; это объект, динамически выделяемый объект; наша программа работает только со ссылками (указателями) на них. Таблицы создаются при помощи выражения-конструктора, которое в своей простейшей форме записывается как {}:, таблица всегда анонимна. 

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

и растет по мере добавления новых записей.

a.x = 10   -- syntactic sugar то же, что и a["x"] = 10

print(a.x) -- syntactic sugar то же, что и print(a["x"])

print(a.y) -- syntactic sugar то же, что и print(a["y"])

Для представления записей вы используете имя поля как индекс. Lua поддерживает это представление, предлагая a.name в качестве

синтаксического сахара для a["name"].


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

Типичная ошибка — спутать а.х с а[х]. Первая форма соответствует а["х"], то есть таблица индексирована при помощи строки "х". Вторая форма означает, что таблица индексирована при помощи значения переменной х. Взгляните на разницу:

a = {}

x = "y"

a[x] = 10  -- записывает 10 в поле "y"

Высшая добродетель подобна воде. Вода приносит пользу всем существам и не борется. Она находится там, где люди не желали ли бы быть. Поэтому она похожа на дао.

Я думаю, что подобная попытка не явилась бы благом для людей, исключая очень немногих, которые и сами при малейшем указании способны все это найти;