• Главная
  • Контакты
Подписаться:
  • Twitter
  • Facebook
  • RSS
  • VK
  • PushAll

logo

  • Все
    • Положительные
    • Отрицательные
  • За сегодня
    • Положительные
    • Отрицательные
  • За вчера
    • Положительные
    • Отрицательные
  • За 3 дня
    • Положительные
    • Отрицательные
  • За неделю
    • Положительные
    • Отрицательные
  • За месяц
    • Положительные
    • Отрицательные
  • За год
    • Положительные
    • Отрицательные
  • Сортировка
    • По дате (возр)
    • По дате (убыв)
    • По рейтингу (возр)
    • По рейтингу (убыв)
    • По комментам (возр)
    • По комментам (убыв)
    • По просмотрам (возр)
    • По просмотрам (убыв)
Главная
  • Все
    • Положительные
    • Отрицательные
  • За сегодня
    • Положительные
    • Отрицательные
  • За вчера
    • Положительные
    • Отрицательные
  • За 3 дня
    • Положительные
    • Отрицательные
  • За неделю
    • Положительные
    • Отрицательные
  • За месяц
    • Положительные
    • Отрицательные
  • Главная
  • Bash-скрипты, часть 6: функции и разработка библиотек

Bash-скрипты, часть 6: функции и разработка библиотек +44

24.04.2017 13:10
ru_vds 33 9200 Источник
Серверное администрирование*, Настройка Linux*, Блог компании RUVDS.com
Bash-скрипты: начало
Bash-скрипты, часть 2: циклы
Bash-скрипты, часть 3: параметры и ключи командной строки
Bash-скрипты, часть 4: ввод и вывод
Bash-скрипты, часть 5: сигналы, фоновые задачи, управление сценариями
Bash-скрипты, часть 6: функции и разработка библиотек
Bash-скрипты, часть 7: sed и обработка текстов
Bash-скрипты, часть 8: язык обработки данных awk
Bash-скрипты, часть 9: регулярные выражения

Занимаясь разработкой bash-скриптов, вы рано или поздно столкнётесь с тем, что вам периодически приходится использовать одни и те же фрагменты кода. Постоянно набирать их вручную скучно, а копирование и вставка — не наш метод. Как быть? Хорошо бы найти средство, которое позволяет один раз написать блок кода и, когда он понадобится снова, просто сослаться на него в скрипте.



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



Объявление функций


Функцию можно объявить так:

functionName {
}

Или так:

functionName() {
}

Функцию можно вызвать без аргументов и с аргументами.

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


Напишем скрипт, содержащий объявление функции и использующий её:

#!/bin/bash
function myfunc {
echo "This is an example of using a function"
}
count=1
while [ $count -le 3 ]
do
myfunc
count=$(( $count + 1 ))
done
echo "This is the end of the loop"
myfunc
echo "End of the script"

Здесь создана функция с именем myfunc. Для вызова функции достаточно указать её имя.


Результаты вызова функции

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

#!/bin/bash
count=1
while [ $count -le 3 ]
do
myfunc
count=$(( $count + 1 ))
done
echo "This is the end of the loop"
function myfunc {
echo "This is an example of using a function"
}
echo "End of the script"

Как и ожидается, ничего хорошего после его запуска не произошло.


Попытка воспользоваться функцией до её объявления

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

#!/bin/bash
function myfunc {
echo "The first function definition"
}
myfunc
function myfunc {
echo "The second function definition"
}
myfunc
echo "End of the script"

Как видно, новая функция преспокойно затёрла старую.


Переопределение функции

Использование команды return


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

#!/bin/bash
function myfunc {
read -p "Enter a value: " value
echo "adding value"
return $(( $value + 10 ))
}
myfunc
echo "The new value is $?"

Команда echo вывела сумму введённого числа и числа 10.


Вывод значения, возвращаемого функцией

Функция myfunc добавляет 10 к числу, которое содержится в переменной $value, значение которой задаёт пользователь во время работы сценария. Затем она возвращает результат, используя команду return. То, что возвратила функция, выводится командой echo с использованием переменной $?.
Если вы выполните любую другую команду до извлечения из переменной $? значения, возвращённого функцией, это значение будет утеряно. Дело в том, что данная переменная хранит код возврата последней выполненной команды.

Учтите, что максимальное число, которое может вернуть команда return — 255. Если функция должна возвращать большее число или строку, понадобится другой подход.

Запись вывода функции в переменную


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

#!/bin/bash
function myfunc {
read -p "Enter a value: " value
echo $(( $value + 10 ))
}
result=$( myfunc)
echo "The value is $result"

Вот что получится после вызова данного скрипта.


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

Аргументы функций


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

Функции могут использовать стандартные позиционные параметры, в которые записывается то, что передаётся им при вызове. Например, имя функции хранится в параметре $0, первый переданный ей аргумент — в $1, второй — в $2, и так далее. Количество переданных функции аргументов можно узнать, обратившись к переменной $#. Если вы знакомы с третьей частью этого цикла материалов, вы не можете не заметить, что всё это очень похоже на то, как скрипты обрабатывают переданные им параметры командной строки.

Аргументы передают функции, записывая их после её имени:

myfunc $val1 10 20

Вот пример, в котором функция вызывается с аргументами и занимается их обработкой:

#!/bin/bash
function addnum {
if [ $# -eq 0 ] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $(( $1 + $1 ))
else
echo $(( $1 + $2 ))
fi
}
echo -n "Adding 10 and 15: "
value=$(addnum 10 15)
echo $value
echo -n "Adding one number: "
value=$(addnum 10)
echo $value
echo -n "Adding no numbers: "
value=$(addnum)
echo $value
echo -n "Adding three numbers: "
value=$(addnum 10 15 20)
echo $value

Запустим скрипт.


Вызов функции с аргументами

Функция addnum проверяет число переданных ей при вызове из скрипта аргументов. Если их нет, или их больше двух, функция возвращает значение -1. Если параметр всего один, она прибавляет его к нему самому и возвращает результат. Если параметров два, функция складывает их.

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

#!/bin/bash
function myfunc {
echo $(( $1 + $2 ))
}
if [ $# -eq 2 ]
then
value=$( myfunc)
echo "The result is $value"
else
echo "Usage: myfunc  a b"
fi

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


Функция не может напрямую использовать параметры, переданные сценарию

Вместо этого, если в функции планируется использовать параметры, переданные скрипту при вызове из командной строки, надо передать их ей при вызове:

#!/bin/bash
function myfunc {
echo $(( $1 + $2 ))
}
if [ $# -eq 2 ]
then
value=$(myfunc $1 $2)
echo "The result is $value"
else
echo "Usage: myfunc a b"
fi

Теперь всё работает правильно.


Передача функции параметров, с которыми запущен скрипт

Работа с переменными в функциях


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

Существуют два вида переменных:

  • Глобальные переменные.
  • Локальные переменные.

?Глобальные переменные


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

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

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

#!/bin/bash
function myfunc {
value=$(( $value + 10 ))
}
read -p "Enter a value: " value
myfunc
echo "The new value is: $value"

Вот что выведет этот сценарий.


Обращение к глобальной переменной из функции

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

Что если такое поведение нас не устраивает? Ответ прост — надо использовать локальные переменные.

?Локальные переменные


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

local temp=$(( $value + 5 ))

Если за пределами функции есть переменная с таким же именем, это на неё не повлияет. Ключевое слово local позволяет отделить переменные, используемые внутри функции, от остальных переменных. Рассмотрим пример:

#!/bin/bash
function myfunc {
local temp=$[ $value + 5 ]
echo "The Temp from inside function is $temp"
}
temp=4
myfunc
echo "The temp from outside is $temp"

Запустим скрипт.


Локальная переменная в функции

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

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


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

#!/bin/bash
function myfunc {
echo "The parameters are: $@"
arr=$1
echo "The received array is ${arr[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
myfunc $myarray


Неправильный подход к передаче функциям массивов

Как видно из примера, при передаче функции массива, она получит доступ лишь к его первому элементу.

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

#!/bin/bash
function myfunc {
local newarray
newarray=("$@")
echo "The new array value is: ${newarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is ${myarray[*]}"
myfunc ${myarray[*]}

Запустим сценарий.


Сборка массива внутри функции

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

Рекурсивные функции


Рекурсия — это когда функция сама себя вызывает. Классический пример рекурсии — функция для вычисления факториала. Факториал числа — это произведение всех натуральных чисел от 1 до этого числа. Например, факториал 5 можно найти так:

5! = 1 * 2 * 3 * 4 * 5

Если формулу вычисления факториала написать в рекурсивном виде, получится следующее:

x! = x * (x-1)!

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

#!/bin/bash
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$(( $1 - 1 ))
local result=$(factorial $temp)
echo $(( $result * $1 ))
fi
}
read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"

Проверим, верно ли работает этот скрипт.


Вычисление факториала

Как видите, всё работает как надо.

Создание и использование библиотек


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

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

Ключ к использованию библиотек — в команде source. Эта команда используется для подключения библиотек к скриптам. В результате функции, объявленные в библиотеке, становятся доступными в скрипте, в противном же случае функции из библиотек не будут доступны в области видимости других скриптов.

У команды source есть псевдоним — оператор «точка». Для того, чтобы подключить файл в скрипте, в скрипт надо добавить конструкцию такого вида:

. ./myscript

Предположим, что у нас имеется файл myfuncs, который содержит следующее:

function addnum {
echo $(( $1 + $2 ))
}

Это — библиотека. Воспользуемся ей в сценарии:

#!/bin/bash
. ./myfuncs
result=$(addnum 10 20)
echo "The result is: $result"

Вызовем его.


Использование библиотек

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

Вызов bash-функций из командной строки


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

Отредактируйте .bashrc, добавив в него такую строку (путь к файлу библиотеки в вашей системе, естественно, будет другим):

. /home/likegeeks/Desktop/myfuncs

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

$ addnum 10 20


Вызов функции из командной строки

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

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

Итоги


Функции в bash-скриптах позволяют оформлять блоки кода и вызывать их в скриптах. А наиболее часто используемые функции стоит выделить в библиотеки, которые можно подключать к скриптам, используя оператор source. Если же среди ваших функций найдутся такие, без которых вы прямо таки жить не можете — библиотеки с ними можно подключить в файле .bashrc. Это позволит удобно пользоваться ими в командной строке или в других скриптах. Главное — чтобы имена ваших функций не совпадали с именами встроенных команд.

На сегодня это всё. В следующий раз поговорим об утилите sed — мощном средстве обработки строк.



Уважаемые читатели! А вы пользуетесь функциями собственной разработки для решения повседневных задач?
Поделиться с друзьями
-->

Комментарии (33)


  1. cccco
    24.04.2017 17:38
    #10188962
    -2

    Спасибо!


    1. cccco
      25.04.2017 17:10
      #10190716

      Автор написал свой пост в 16:10. Через полтора часа никакой реакции от сообщества не было. Я решил поддержать автора и написал ему слова благодарности. Тем более нашёл в его публикации что-то полезное для себя.

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

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


      1. grossws
        25.04.2017 19:20
        #10190882

        Вы читали комментарии к прошлым "статьям" (точнее переводам)? Я читал. Включая комментарии.


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


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


        1. cccco
          26.04.2017 17:48
          #10192554
          -1

          Кроме лирики конкретика какая-нибудь будет?

          Я, например, не считаю ЭТУ статью плохой. И по комментариям к ЭТОЙ статье я это тоже вижу. Идёт здоровая дискуссия, аналогичная дискуссиям в комментариях к другим статьях на Хабре.

          Я не знаю, может у Вас что-то этакое есть, позволяющие Вам безапелляционно навешивать всякие ярлыки («Тут всё плохо!» и далее «Я всех спасу!»). Вы, уж, предъявите тогда это, чтобы всем было понятно, что Вы за фрукт. Какую-нибудь ссылку на свою шикарную статью по данной тематике, например, или, может быть, даже книгу.

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

          Как-то неубедительно Вы звучите пока.


          1. grossws
            26.04.2017 17:55
            #10192568
            +1

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


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


            1. cccco
              26.04.2017 21:14
              #10192902
              -3

              Не согласен, абсолютно. Доводы — никакие совсем.

              Во-первых, как-то малова-то т.н. «недочётов» для такой обширной статьи, чтобы называть её плохой.

              Во-вторых, про массивы. В том контексте, в котором упоминается работа с массивами, я, например, не вижу ничего неправильного. Скрипт отработает так, как нужно.

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

              Я, например, хотел бы, чтобы эта дискуссия про Bash на Хабре продолжилась. Поэтому, спасибо автору и комментаторам, что они тратят своё личное время на это!

              В-третьих, про точку в скриптах. Я не понял, что тут неправильного? Поясните, пожалуйста. Если открыть наугад, идущий в стандартной установки Linux, скрипт в /etc/init.d или /etc/rc.d (или что-то ещё похожее, не знаю, с чем Вы работаете), наверняка Вы там встретите использование точки. Я точку встречаю во многих скриптах.

              Кроме того, автор не призывает использовать или не использовать точку в скриптах. Автор поделился вполне конкретной информацией о том, что source имеет псевдоним — точку. Разве это неправильная информация?


              1. grossws
                26.04.2017 21:30
                #10192950
                +1

                Во-вторых, про массивы. В том контексте, в котором упоминается работа с массивами, я, например, не вижу ничего неправильного. Скрипт отработает так, как нужно.

                В некоторых частных случаях. А учить писать на баше так, что обычно работает, но может сломаться в самый удачный момент, на мой взгляд, в корне неверно. Баш — минное поле и очень неприятное legacy.


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

                Часть комментаторов уже сдалась, т. к. в этой серии ошибки кочуют из статьи в статью.


                В-третьих, про точку в скриптах. Я не понял, что тут неправильного? Поясните, пожалуйста. Если открыть наугад, идущий в стандартной установки Linux, скрипт в /etc/init.d или /etc/rc.d (или что-то ещё похожее, не знаю, с чем Вы работаете), наверняка Вы там встретите использование точки. Я точку встречаю во многих скриптах.

                Использование точки, равно как и коротких опций в скриптах — code smell. Это ухудшает поддерживаемость скрипта. Насчёт же init.d/rc.d на моей системе оно выглядит так:


                -> % ls /etc/init.d /etc/rc.d
                ls: cannot access '/etc/rc.d': No such file or directory
                /etc/init.d:
                vmware

                На centos7 похуже, там больше всякого legacy-барахла. Вообще поддерживать старые добрые init-скрипты на баше даже под пару версий дистрибутива уже не очень приятно. А уж ориентироваться на них, как на образец написания программ на баше так вообще не стоит. Говнокода там хватает.


                Я понял, что вам понравилась эта серия статей. Не буду мешать вам оставаться при своём мнении. Предлагаю завершить дискуссию.


              1. ghostinushanka
                26.04.2017 23:21
                #10193074
                +3

                Автор поделился вполне конкретной информацией о том, что source имеет псевдоним — точку.

                Вот только нихр это не верное утверждение. Если сильно притянуть за уши — то это source псевдоним синоним «точки», поскольку точка перекочевала из оригинального борн шела а source — нововведение (причём я не рискну сказать баша или ksh).
                Но если посмотреть мануал, а ещё лучше вообще исходники 23:52, то выяснится что это две абсолютно равнозначных встроенных команды (built-in) вызывающих одну и ту же функцию source_builtin

                Я точку встречаю во многих скриптах.

                А вы вообще знаете почему вы встречаете точку-то? Нет? А эта «статья» почему-то этот весьма важный момент опустила, не смотря на то, что об этих встроенных командах обмолвилась.
                В качестве повышения квалификации предлагаю вам эту информацию нарыть и поделиться с другими читателями. Ключевое слово — POSIX. В догонку можете поискать на что ресолвится /bin/sh в современных линуксовых дистрах (для упрощения давайте возьмём debian, ubuntu, centos, opensuse, arch), и что будет если скрипт с шебангом #!/bin/sh этому делу скормить и в чём будет разница между source и точкой.

                И о такого рода недочётах, которые рано или поздно начинающих приведут к «выстрели себе в ногу рикошетом в голову», я могу к каждой из этих публикаций писать полотна, но, зачем?! Ниже iig написал про absg. Этот материал я упоминал в комментариях к предыдущим статьям как минимум трижды.
                Мой добрый совет — читайте мной ранее упомянутые вещи, а не это.


                1. cccco
                  28.04.2017 11:27
                  #10195488
                  -3

                  Спасибо огромное за совет! У меня он тоже есть для Вас.

                  Учитесь слышать людей.

                  Ваш опус в контексте статьи — ненужная шелуха, информация, чтобы блеснуть умом перед девочками. К чему Вы его написали-то? (Подумайте над этим вопросом и дайте себе ответ, только правдивый.)

                  Он доказывает, что точку в скриптах использовать неправильно? Нет. Мимо.

                  Он как-то показывает, что, если я буду использовать точку вместо source, я получу другой результат? Опять нет. «Молоко».

                  Автор статьи всего лишь пытался донести, что вместо source с таким же успехом можно использовать точку. Не больше, не меньше. А Вы эту простую мысль-то и не услышали! (И давай обнажать свой «ум».)

                  А так да, Вы написали много правильных слов. Но, как-то не туда, понимаете. Мимо. Может Вам книгу лучше написать, с таким умищем-то? И девочкам это нравится ещё больше.

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


                  1. grossws
                    28.04.2017 13:45
                    #10195894
                    +1

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

                    Хамство вас не красит, успокойтесь


                    1. cccco
                      02.05.2017 14:27
                      #10199968
                      -2

                      Успокойтесь, пожалуйста! Нам с ghostinushanka суфлёр не нужен. Мы сами разберёмся.

                      Кроме того нашу с Вами дискуссию мы уже прекратили (кстати, по Вашей же инициативе).

                      Не тратьте, пожалуйста, своё личное время на меня. Я своё точно уже на Вас тратить не собираюсь. Если хотите как-то отреагировать, то просто продолжайте меня минусовать, это точно не отнимет у Вас много Вашего личного времени.

                      Услышьте меня, пожалуйста, наконец!


                  1. ghostinushanka
                    28.04.2017 13:57
                    #10195926
                    +2

                    Иными словами вы не стали ничего узнавать про POSIX.
                    В контекте вот этой вашей фразы, это, к великому моему сожалению, весьма печально:

                    Он как-то показывает, что, если я буду использовать точку вместо source, я получу другой результат?

                    Да получите, причём в самый неожиданный момент. Или вы серьёзно считаете, что я со злым умыслом и от нечего делать вас направил что-то поискать почитать?

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

                    #irony #rhetorical
                    А где мне спасибо на прямые ссылки на «Advanced bash scripting guide», которые я приводил комментариями к предыдущим статьям?

                    P.S. Прошу прощения у хабрапублики. Я надеюсь что эти комментарии всё же помогут начинающим и не очень писателям шелл скриптов.
                    Подписываюсь под этим абсолютно верным комментарием к следующей «статье из цикла».


                    1. cccco
                      02.05.2017 16:33
                      #10200252
                      -3

                      Очень жаль, что Вы даже и не попробовали научиться слышать людей!

                      Да получите, причём в самый неожиданный момент.

                      Вы уж расскажите, пожалуйста, не томите.

                      Вы обиделись, а зря! Вы что, серьёзно считаете, что я со злым умыслом и от нечего делать Вас попытался направить научиться хоть немного слышать людей? Отнюдь.

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

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

                      Вот, Вы всё зачем-то вставляете в своих комментариях «POSIX, POSIX...». Поймите Вы, наконец, что очки — это ещё не признак ума. А, вот, умение слышать собеседника, по крайней мере, даёт надежду на его наличие.

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

                      К великой моей Радости, я бы очень хотел, чтобы Вы научились слышать людей. Но я не могу Вас заставить! Вы должны сами этого захотеть. Иначе — не получится. Я лишь могу только выдавать Вам информацию для размышления.

                      Например.
                      Иными словами вы не стали ничего узнавать про POSIX.

                      Разве Вы слышали от меня, что я ничего не знаю про POSIX? Как я могу, например, писать многопоточные сервера и не знать про POSIX? Я POSIX уже хорошо знал ещё в 90-х. Но я не вижу в этом ничего экстраординарного — знать POSIX. С таким же успехом Вы могли бы мне в также назидательном тоне посоветовать изучать, например, Linux. Моё восприятие Ваших слов совершенно бы не изменилось. Ваш совет меня искренне улыбнул. :)

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

                      Ещё, например.

                      Я совершенно не сомневался, что Вы обязательно напишите мне что-то типа этого:
                      А где мне спасибо на прямые ссылки на «Advanced bash scripting guide», которые я приводил комментариями к предыдущим статьям?


                      Вы умудрились обидеться (хотя и прикрылись якобы иронией) на комментарий, который предназначался не для Вас. Я, конечно, оброщался к iig, но для Вас этот комментарий тоже предназначался, но, только в качестве эксперимента. Мне же надо было как-то получить от Вас косвенные подтверждения, Вашей обидчивости. Спасибо, тест сдан, Вы это подтвердили! Поразмышляйте над этим тоже.

                      Продолжим.

                      P.S. Прошу прощения у хабрапублики. Я надеюсь что эти комментарии всё же помогут начинающим и не очень писателям шелл скриптов.
                      Подписываюсь под этим абсолютно верным комментарием к следующей «статье из цикла».


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

                      Тут на Хабре есть реальные ребята, делящиеся своими знаниями в статьях и комментариях и делающих Хабр тем, что он есть, а есть закомплексованные критики, как правило, без публикаций и без конкретики в комментариях — одна лишь пустая неподкреплённая ничем критика (именно они активно минусуют любого, потому что никого не слышат) и лирика (активно стремяться всем «помочь», при этом ничем не помогая, и «спасти» — не спасая).

                      Хотите перейти на сторону реальных ребят? — научитесь для начала слышать людей.

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


          1. iig
            26.04.2017 21:14
            #10192904

            Канонический Advanced bash scripting guide не намного больше по размеру, я бы его рекомендовал.


            1. cccco
              28.04.2017 11:41
              #10195510
              -1

              Спасибо, добрый человек!

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


        1. malinichev
          04.05.2017 10:16
          #10202776
          -1

          Без обид, но если уж на то пошло — соберитесь вместе с умными людьми, и напишите свою серию статей!
          И 100% найдётся люди умнее и также будут комментировать…

          Вот честно, вы так высказываетесь, как будто тут выложили совершенно не работающий код. Главное — что он работает, а подточить — уже дело каждого.

          Я, например, пол года назад совершенно не знал об администрировании серверов, а сейчас приходится содержать 2 сервера, и для меня хоть какие-то примеры — это послание от бога! Но я согласен, что примеры не ахти моментами, но что поделать…


          1. grossws
            04.05.2017 10:44
            #10202842
            +1

            Не беспокойтесь, без ваших мудрых советов от активного автора разберусь чему посвятить своё свободное время. И тут мои и не только мои open source проекты куда в большем приоритете, чем статьи на хабре.


  1. CaptainFlint
    24.04.2017 19:56
    #10189118

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

    Кроме того, обратите внимание на то, что если имя функции из библиотеки совпадёт с именем какой-нибудь стандартной команды, вместо этой команды будет вызываться функция.
    И зачастую это очень удобно. Подменяем grep на функцию, которая запускает «настоящий» grep, динамически выбирая для него разные опции в зависимости от того, запущен ли в терминале (а не, скажем, в pipe-цепочке команд):
    function grep {
            if [ -t 1 ] ; then
                    /bin/grep --color -n "$@"
            else
                    /bin/grep "$@"
            fi
    }
    


  1. iig
    24.04.2017 20:16
    #10189150

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


  1. khim
    24.04.2017 22:04
    #10189316
    +5

    И опять у нас статья, которая учит пользователей писать неправильные скрипты на bash'е. Давайте немного модифицируем пример с передачей массивов:

    #!/bin/bash
    function myfunc {
    local newarray
    newarray=("$@")
    echo "The new array value is:"
    for value in "${newarray[@]}" ; do
      echo "  $value"
    done
    }
    myarray=(1 "2 3" "4 5")
    echo "The original array is:"
    for value in "${myarray[@]}" ; do
      echo "  $value"
    done
    myfunc ${myarray[*]}
    

    Запустим, и…
    
    The original array is:
      1
      2 3
      4 5
    The new array value is:
      1
      2
      3
      4
      5
    
    Таки у нас проблема.

    А как надо? А вот так:
    #!/bin/bash
    function myfunc {
    local newarray
    newarray=("$@")
    echo "The new array value is:"
    for value in "${newarray[@]}" ; do
      echo "  $value"
    done
    }
    myarray=(1 "2 3" "4 5")
    echo "The original array is:"
    for value in "${myarray[@]}" ; do
      echo "  $value"
    done
    myfunc "${myarray[@]}"
    Теперь — порядок:
    
    The original array is:
      1
      2 3
      4 5
    The new array value is:
      1
      2 3
      4 5
    
    Собственно я вообще не могу припомнить ни одного учебника по bash, где не было бы каких-либо ошибок (в bash есть много разных способов «выстрелить себе в ногу).

    И вот это вот — «простой» язык? Да ни в жизнь. Иначе бы „гуру“, пишущие учебники, уж наверное, не совершали бы „детских“ ошибок.

    При этом — всё ведь есть! Давайте например, распечатаем не весь массив в функции, а подмассив:
    #!/bin/bash
    function myfunc {
    local newarray
    newarray=("$@")
    echo "The new array value is:"
    for value in "${newarray[@]:1:2}" ; do
      echo "  $value"
    done
    }
    myarray=(1 "2 3" "4 5" 6 7)
    echo "The original array is:"
    for value in "${myarray[@]}" ; do
      echo "  $value"
    done
    myfunc "${myarray[@]}"
    Работает отлично:
    
    The original array is:
      1
      2 3
      4 5
      6
      7
    The new array value is:
      2 3
      4 5
    
    А теперь попробуем „отрезать кусочек“ в момент его создания:
    #!/bin/bash
    function myfunc {
    local newarray
    newarray=("${@:1:2}")
    echo "The new array value is:"
    for value in "${newarray[@]}" ; do
      echo "  $value"
    done
    }
    myarray=(1 "2 3" "4 5" 6 7)
    echo "The original array is:"
    for value in "${myarray[@]}" ; do
      echo "  $value"
    done
    myfunc "${myarray[@]}"
    Всё сьехало:
    The original array is:
      1
      2 3
      4 5
      6
      7
    The new array value is:
      1
      2 3
    Довайте поэкспериментерием:
    #!/bin/bash
    function myfunc {
    local newarray
    newarray=("${@:0}")
    echo "The new array value is:"
    for value in "${newarray[@]}" ; do
      echo "  $value"
    done
    }
    myarray=(1 "2 3" "4 5" 6 7)
    echo "The original array is:"
    for value in "${myarray[@]}" ; do
      echo "  $value"
    done
    myfunc "${myarray[@]}"
    И:
    The original array is:
      1
      2 3
      4 5
      6
      7
    The new array value is:
      test.sh
      1
      2 3
      4 5
      6
      7
    
    Ага. Теперь понятно: $0 — ведь это название скрипта (скрипта, а не функции, заметьте!) и когда мы „массив агументов“ обрабатываем — про это нужно помнить… Но „для удобства“ когда мы работает с "$@" нулевой элемент выкидывается автоматически!

    Ну что за прелесть этот bash! PHP — это ужас, как всем известно, но bash… bash — это ужас-ужас-ужас-ужас-ужас!


    1. RPG
      25.04.2017 00:20
      #10189462
      +3

      И это вы ещё поверхность не поцарапали...


      cd $dir
      rm -fr *

      Спойлер: представим, что $dir не существует или пустой.


      file=/etc/passwd
      foo() {
        # local file
        for file in /*; do # file теперь глобально видна всем
          :
        done
      }
      foo
      # ой!
      echo $file

      copy_file_to_tmp() {
        cp "$1" /tmp # работает ровно до момента появления файла с названием "-f"
      }

      Тысячи их.


      А ещё bash -ue script.sh.


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


      P.S.


      count=$(( $count + 1 ))
      # так тоже работает
      ((count++))

      P.P.S. В systemd поняли ошибку и переписали всё с шелл-портянок на Си. Но в последний момент всё равно что-то пошло не так...


      1. khim
        25.04.2017 01:17
        #10189508
        +1

        Ну дык. Решение первой проблемы «всем известно»:

        #!/bin/bash
        set -eu
        dir=oops
        cd "$dir"
        rm -rf ./*
        Получаем:
        $ bash test.sh 
        test.sh: строка 4: cd: oops: Нет такого файла или каталога
        
        Писать скрипты на bash'е без set -eu — нарываться на неприятности.

        Для второй проблемы существует директива local.

        Для cp — тоже есть решение, даже два:
        1. Можно использовать cp -- "$1" /tmp
        2. Можно сделать функцию примерно такого вида:
        function make_safe {
          if [[ "${1::1}" != "/" && "${1::2}" != "./" ]]; then
            echo -n "./$1"
          else
            echo -n "$1"
          fi
        }
        После чего имея переменную unsafe_name вы можете «легко» сделать её безопасной:
        IFS= read -rd '' safe_name < <(make_safe "$unsafe_name")
        В общем если принять «как данность», что написание скриптов на bash'е — это скорее разгадывание ребусов, то всё можно сделать. Но на нормальное программирование это ни разу не похоже.

        Если же скрипты пишутся для себя, то часто можно обойтись более простыми средствами. Если имена файлов, с которыми вам приходится работать не заканчиваются на возврат каретки и не начинаются со знака минус, то ведь и просто cp "$1" /tmp сработает!


        1. iig
          25.04.2017 10:45
          #10189828

          cd $dir
          rm -fr *
          


          Выстрелить в ногу и жаловаться, что теперь больно.

          cd "$dir" && rm -fr *
          


          И тут оказывается, что rm -fr * не удаляет скрытые файлы (имена которых начинаются с точки)…


          1. khim
            25.04.2017 20:44
            #10190966

            И тут оказывается, что rm -fr * не удаляет скрытые файлы (имена которых начинаются с точки)…
            Я так понимаю, что на это и был рассчёт. Хотя фиг его знает. Целиком скрипта мы не видим, так что…

            А вообще — set -eu надёжнее, чем
            cd "$dir" && rm -fr *
            Потому что просто тупо игнорировать тот факт, что перейти куда-то не удалось — нехорошо. Нужно либо вывалиться, либо if cd "$dir" сделать и потом как-то обработать ошибку…


            1. iig
              25.04.2017 21:14
              #10191008

              У каждого свой набор шаблонов чтобы подпирать особенности программ на bash ;)
              Ошибки желательно обрабатывать, кто ж против.


    1. ghostinushanka
      25.04.2017 12:46
      #10190106
      +3

      И опять у нас статья, которая учит пользователей писать неправильные скрипты на bash'е.

      После того как все мои замечания к предыдущим «статьям» остались без внимания, я просто забил их комментировать.
      Было бы неплохо, еслиб НЛО вывесило баннер над этими статьями в стиле «Бородатые комментаторы советуют к статьям относиться со скепсисом»


      1. Termux
        25.04.2017 15:58
        #10190504

        Бородатые комментаторы весь баш выкинули уже 3 года как
        и увольняют за попытку его использования

        Ansible проще поддерживать и развивать


        1. neumeika
          26.04.2017 00:19
          #10191180

          ну-ну, если б они пореже функционал меняли. Обновился, а переменные уже локальные для include и переопределить их можно только через set_fact. Или with_item синтаксис поменяли, или loop_var. Я уже заколебался переписывать. В баше такого нет :)


  1. Lelik13a
    25.04.2017 05:22
    #10189550

    :(){ :|:& };:
    

    ;)


    1. khim
      25.04.2017 20:46
      #10190972

      Зачем людей плохому-то учить?


      1. Lelik13a
        26.04.2017 05:07
        #10191238

        Это краш-тест начинающих и любопытных башо-писателей, к тому же в рамках статьи :).


    1. iig
      26.04.2017 21:24
      #10192932

      Все зависло!!!


      1. grossws
        26.04.2017 21:31
        #10192952

        Толсто. У кого в современном миру не настроены ulimits и cgroups?

МЕТКИ

  • Хабы
  • Теги

Серверное администрирование

Настройка Linux

Блог компании RUVDS.com

linux

bash

сценарий командной строки

bash-скрипт

функция

библиотека

СЕРВИСЫ
  • logo

    CloudLogs.ru - Облачное логирование

    • Храните логи вашего сервиса или приложения в облаке. Удобно просматривайте и анализируйте их.
Все публикации автора
  • Как создавались вокальные эффекты Daft Punk +6

    • 12.05.2025 13:01

    Отладка приложения, которое не хочет, чтобы его отлаживали +51

    • 19.02.2025 13:01

    Могут ли LLM писать более качественный код, если их об этом просто попросить? +77

    • 17.02.2025 13:01

    Зачем нужен VPS? Telegram-боты, биржи, игры и ещё 7 популярных сценариев +21

    • 17.02.2025 09:01

    Ни одна реализация элементарных функций не соответствует стандарту IEEE 754 +83

    • 12.02.2025 13:01

    Ад — это чересчур уверенные в себе разработчики, пишущие собственную криптографию +48

    • 10.02.2025 13:01

    Все знают, где ты находишься +155

    • 05.02.2025 13:01

    Хакаем любую Субару с доступом к Интернету +42

    • 03.02.2025 13:01

    Компилятор WebAssembly, который помещается в один твит +38

    • 29.01.2025 13:01

    FizzBuzz, который не помог мне найти работу +80

    • 27.01.2025 13:01

Подписка


ЛУЧШЕЕ

  • Сегодня
  • Вчера
  • Позавчера
14:22

Ещё 10 ошибок авторов Хабра +42

08:01

Трамплин в интернет: как мы ускорили запуск Яндекс Браузера +32

07:43

Больше нет входа в IT. Только выход +28

05:16

Дело о Транзитроне — или Ламповый тьюториал для любопытных +27

03:22

Как за один вечер создать репутацию вашего стартапа в поисковой выдаче: 20 бесплатных площадок для быстрого буста +24

13:06

Введение в Angie: краткая история и отличия от Nginx +23

10:09

Как настраивать сети: готовые решения Selectel для максимальной отказоустойчивости +21

08:35

Распределённый инференс и шардирование LLM. Часть 1: настройка GPU, проброс в Proxmox и настройка Kubernetes +21

06:53

Важное обновление BatteryTest 2 +21

09:01

Почему из технологий делают культы +19

08:57

Разбор полётов: что умеет отечественная СХД Аэродиск AQ440 +19

10:09

Последний звонок: прощаемся со Skype +17

04:53

Баффет наконец накопил достаточно для выхода на пенсию, а в OpenAI выкатили новый хитрый план +16

09:31

Как ESLint помогает управлять архитектурой проекта +15

13:01

Как создавались вокальные эффекты Daft Punk +14

10:26

От релиз-менеджера до разработчика: почему я ушел из QA и не жалею +14

13:05

Топ 5 бесплатных нейросетей для анимации картинок +13

11:34

Как избавиться от зацикливания обработчиков событий в Битриксе +13

07:59

Стелс-изобретения, возможно, сделают невидимыми людей, самолёты и даже города +13

07:00

DevOps без боли: 8 инструментов для мониторинга, автоматизации и стабильной работы команд +13

19:36

ООП не мертво. Вы просто пользуетесь им как молотком по клавиатуре +122

08:00

Электробус из 1907 года от мошенников-стартаперов. И да, он возил пассажиров +45

13:01

Как serverless-архитектура влияет на модернизацию инфраструктуры +43

09:01

Google Maps не знают, как работает адресация улиц +34

06:30

Дискретные тригонометрические функции, машинный эпсилон и автоматическое дифференцирование +33

09:15

Wizordum — пример правильной ностальгии +32

10:05

Разговоры с мамой, остросюжетный роман и дофаминовые ловушки. Что и зачем читать продакту в 2025 году +30

10:00

Multi-GPU Rendering для игр жив? +29

16:08

Как отключить слежку на умном ТВ +28

15:16

Заговор разработчиков против корпораций: работа с командой +24

07:00

От песка в глазах к панораме: как 49-дюймовый монитор заменил два 27-дюймовых и сделал жизнь и работу комфортнее +24

17:21

CTO: рынок, стратегия и инженерная культура +20

05:47

Убить героя: почему героизм — это выбор легкого пути, который вредит не только вам, но и окружающим +18

14:46

Что открыть в 2025, если ты не Илон Маск и не хочешь продавать курсы? +16

12:28

Как устроен arXiv — самая преобразующая платформа во всей науке +16

17:01

PTTJS — формат текстового хранения комплексных таблиц +14

16:24

Корутины в C++20: архитектура и практическое применение +14

14:00

Корпоративное ЕГЭ или как обучение сотрудников НЕ влияет на рост и эффективность +14

18:20

Подмена E-EDID на Windows +11

18:33

Пишем (и используем) ИИ-агент на Gradle и Ollama +10

19:18

Конституция против цензуры: история одного иска в суд +155

14:05

Пишем один «exe», который работает на 3-х разных ОС без перекомпиляции +142

09:01

Спидометр для электромопеда на микроконтроллере PIC16F628A +62

08:00

Архитекторы чипов: как Китай строит инфраструктуру по производству современных процессоров +60

14:12

Оцифровка показаний стрелочного манометра в Home Assistant +55

11:02

Низкоуровневое программирование под 8086 для любопытных, часть 2 +54

16:46

Творческая утилизация клавиатур +38

13:01

Про человека и свободу — реально главный вопрос жизни, вселенной и всего такого +38

11:52

Python, Java, C++ и Go — как появились популярные языки программирования +29

09:49

Не смотрите наверх +28

13:01

Промпт-инжиниринг на основе здравого смысла: как понимать LLM и получать от них предсказуемый результат +26

06:47

Размышления об интервью +24

08:24

Huawei и HarmonyOS PC: китайский десктоп с собственной ОС появится уже в этом месяце. Что это будет? +21

19:18

Проводим слепой тест переводов прямо на Хабре +20

08:02

Задачи на собеседованиях. Денежные переводы в SQL. Обновление счетов и уровни изоляций +20

09:00

Фронтенд — новый легаси: Как мы проспали event-driven революцию +19

17:24

Инженерия — не наука +18

15:14

Почему нужно знать историю фронтенда, даже если просто пишешь на React +15

13:28

Немое кино: как инженеры превратили тени в магию экрана: «бегущие» картинки, фоторужья и 24 кадра в секунду +12

11:19

Аркадий Стругацкий против Deepseek и ChatGPT: как ИИ повлияет на художественный перевод +10

ОБСУЖДАЕМОЕ

  • От песка в глазах к панораме: как 49-дюймовый монитор заменил два 27-дюймовых и сделал жизнь и работу комфортнее +24

    • 303   48000

    Конституция против цензуры: история одного иска в суд +155

    • 268   12000

    ООП не мертво. Вы просто пользуетесь им как молотком по клавиатуре +122

    • 218   29000

    Больше нет входа в IT. Только выход +28

    • 198   41000

    Задачи на собеседованиях. Денежные переводы в SQL. Обновление счетов и уровни изоляций +20

    • 99   17000

    Аркадий Стругацкий против Deepseek и ChatGPT: как ИИ повлияет на художественный перевод +10

    • 95   7000

    Проводим слепой тест переводов прямо на Хабре +20

    • 87   2900

    Фронтенд — новый легаси: Как мы проспали event-driven революцию +19

    • 86   27000

    «Накопитель риска» в команде: как одиночные эксперты тормозят развитие +3

    • 68   7100

    Про человека и свободу — реально главный вопрос жизни, вселенной и всего такого +38

    • 65   6500

    Инженерия — не наука +18

    • 62   3300

    Google Maps не знают, как работает адресация улиц +34

    • 60   8200

    «640 кбайт хватит для всего» +7

    • 60   18000

    Не смотрите наверх +28

    • 55   14000

    Как отключить слежку на умном ТВ +28

    • 48   13000
  • Главная
  • Контакты
© 2025. Все публикации принадлежат авторам.