Разное

Арифметические операции bash: Арифметика и bash . Краткое введение в программирование на Bash

Содержание

Арифметика и bash . Краткое введение в программирование на Bash

Арифметика и bash 

Скриптовой язык bash позволяет выполнять арифметические операции. Как вы уже видели в предыдущей статье, арифметика выполняется с помощью команды expr. Однако, подобно команде true, этот вариант считается медленным. Причина кроется в том, что для использования true и expr оболочка должна предварительно запустить их. Лучше всего использовать встроенную в bash функцию, которая работает быстрее. Аналогично тому, что альтернативой true является команда»:», альтернатива expr— заключение арифметического выражения в конструкцию вида$((…)). Будьте внимательны, она отличается от$(…). Отличие тут в количестве скобок. Так давайте же испробуем это:

#!/bin/bash

x=8 # присваиваем x значение 8

y=4 # присваиваем y значение 4

# результат сложения x и y сохраняем в z:

z=$(($x + $y))

echo "Сумма $x и $y равна $z"

Как обычно, выбор используемого метода вычислений за вами. Если использование expr для вас более комфортно и привычнее, чем $((…)), используйте его.

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

Действие Оператор
Сложение +
Вычитание
Умножение *
Целочисленное деление /
Остаток от деления %

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

#!/bin/bash

x=5 # устанавливаем x равным 5

y=3 # устанавливаем y равным 3

# сохраняем сумму x и y в переменную add

add=$(($x + $y))

# сохраняем разность x и y в переменную sub

sub=$(($x – $y))

# умножаем x на y и сохраняем результат в переменную mul

mul=$(($x * $y))

# в переменную div сохраняем результат деления x на y

div=$(($x / $y))

# получаем остаток от деления x на y и сохраняем его в переменную mod

mod=$(($x % $y))

# печатаем ответы

echo "Сумма равна: $add"

echo "Разность равна $sub"

echo "Произведение равно $mul"

echo "Результат деления $div"

echo "Остаток от деления $mod"

Код, приведенный выше, можно было бы написать с использованием expr. Например, вместо add=$(($x + $y)) мы могли бы использовать add=$(expr $x + $y)илиadd=`expr $x + $y`.

Поделитесь на страничке

Следующая глава >

Сложение, вычитание, умножение, деление, модуль в Bash

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

Существует несколько способов арифметики в сценариях Bash. Мы рассмотрим их для полноты, но рекомендуемый подход — это арифметическое расширение (последнее охватывает).

Let

Let это встроенная функция Bash, которая позволяет нам выполнять простую арифметику. Он следует основному формату:

let <арифметическое выражение>

let <арифметическое выражение>

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

Давайте рассмотрим простой пример:

let_example.sh

#!/bin/bash
# Базовая арифметика, использующая let

let a=5+4
echo $a # 9

let «a = 5 + 4″
echo $a # 9

let a++
echo $a # 10

let «a = 4 * 5″
echo $a # 20

let «a = $1 + 30″
echo $a # 30 + первый аргумент командной строки

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#!/bin/bash

# Базовая арифметика, использующая let

 

let a=5+4

echo $a # 9

 

let «a = 5 + 4»

echo $a # 9

 

let a++

echo $a # 10

 

let «a = 4 * 5»

echo $a # 20

 

let «a = $1 + 30»

echo $a # 30 + первый аргумент командной строки

Давайте разберем это:

  • Строка 4 — это основной формат. Обратите внимание, что если мы не ставим кавычки вокруг выражения, тогда оно должно быть записано без пробелов.
  • Строка 7 — На этот раз мы использовали кавычки, которые позволяют нам выделять выражение, чтобы сделать его более читаемым.
  • Строка 10 — это сокращение для приращения значения переменной a на 1. Это то же самое, что и запись «a = a + 1».
  • Строка 16 — Мы можем также включить в выражение другие переменные.

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

+, -, / *, / Сложение, вычитание, умножение, деление
var ++ Увеличьте переменную var на 1
var— Уменьшить переменную var на 1
% Модуль (возвращает остаток после деления)

Эти операторы могут использоваться и в других механизмах, описанных ниже.

Expr

Expr похож на let, но вместо сохранения результата на переменную вместо этого выводит ответ. В отличие от let вам не нужно заключать выражение в кавычки. Вы также должны иметь пробелы между элементами выражения. Также часто используется выражение expr в подстановке команд для сохранения вывода в переменную.

expr item1 оператор item2

expr item1 оператор item2

Давайте рассмотрим простой пример:

expr_example.sh

#!/bin/bash
# Базовая арифметика с использованием expr

expr 5 + 4

expr «5 + 4″

expr 5+4

expr 5 \* $1

expr 11 % 2

a=$( expr 10 — 3 )
echo $a # 7

#!/bin/bash

# Базовая арифметика с использованием expr

 

expr 5 + 4

 

expr «5 + 4»

 

expr 5+4

 

expr 5 \* $1

 

expr 11 % 2

 

a=$( expr 10 — 3 )

echo $a # 7

Давайте разберем это:

  • Строка 4 — это основной формат. Обратите внимание, что между элементами и пробелами нет пробелов.
  • Строка 6 — Если мы помещаем кавычки вокруг выражения, выражение не будет оцениваться, а печататься.
  • Строка 8 — Если мы не помещаем пробелы между элементами выражения, выражение не будет оцениваться, а печататься.
  • Строка 10 — Некоторые символы имеют особое значение для Bash, поэтому мы должны избегать их (поставить обратную косую черту перед), чтобы удалить их особое значение.
  • Строка 12 — Здесь мы покажем модуль оператора . Модуль — это остаток, когда первый элемент делится на второй элемент.
  • Строка 14 — На этот раз мы используем expr в подстановке команд, чтобы сохранить результат в переменной a.

Двойные скобки

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

Вот пример для иллюстрации:

expansion_example.sh

#!/bin/bash
# Базовая арифметика с использованием двойных скобок

a=$(( 4 + 5 ))
echo $a # 9

a=$((3+5))
echo $a # 8

b=$(( a + 3 ))
echo $b # 11

b=$(( $a + 4 ))
echo $b # 12

(( b++ ))
echo $b # 13

(( b += 3 ))
echo $b # 16

a=$(( 4 * 5 ))
echo $a # 20

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#!/bin/bash

# Базовая арифметика с использованием двойных скобок

 

a=$(( 4 + 5 ))

echo $a # 9

 

a=$((3+5))

echo $a # 8

 

b=$(( a + 3 ))

echo $b # 11

 

b=$(( $a + 4 ))

echo $b # 12

 

(( b++ ))

echo $b # 13

 

(( b += 3 ))

echo $b # 16

 

a=$(( 4 * 5 ))

echo $a # 20

Давайте разберем это:

  • Строка 4 — это основной формат. Как вы можете видеть, мы можем использовать его для удобства чтения без необходимости использования котировок.
  • Строка 7 — Как вы можете видеть, она работает так же, если мы выберем интервал.
  • Строка 10 — Мы можем включать переменные без предшествующего знака $.
  • Строка 13 — Переменные могут быть включены в знак $, если вы предпочитаете.
  • Строка 16 — Это немного другая форма. Здесь значение переменной b увеличивается на 1 (используя тот же механизм, что и в случае let ). Когда мы это делаем, нам не нужен знак $, предшествующий скобкам.
  • Строка 19 — Это немного другая форма предыдущего примера. Здесь значение переменной b увеличивается на 3. Это сокращение для b = b + 3 .
  • Строка 19 — В отличие от других методов, когда мы делаем умножение, нам не нужно выходить из знака * .

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

Длина переменной

Это не арифметика, но она может быть весьма полезна. Если вы хотите узнать длину переменной (сколько символов), вы можете сделать следующее:

Вот пример:

length_example.sh

#!/bin/bash
# Показывать длину переменной.

a=’Hello World’
echo ${#a} # 11

b=4953
echo ${#b} # 4

#!/bin/bash

# Показывать длину переменной.

 

a=’Hello World’

echo ${#a} # 11

 

b=4953

echo ${#b} # 4

Часть 3. Пользовательский ввод в Bash
Часть 5. If, else, case в Bash

Источник: https://ryanstutorials.net/bash-scripting-tutorial/bash-arithmetic.php

Арифметические операции в консоли UNIX

Как произвести в bash/sh простейшие вычисления? Давайте рассмотрим несколько примеров.

Операции с целыми числами

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

Вот 6 арифметических команд, которые вы можете выполнять:


# сложение
echo 4 + 5 = $((4 + 5))
# вычитание
echo 5 — 4 = $[ 5 — 4 ]
# умножение
echo 4 x 5 = $((4 * 5))
# деление (результат будет целое число без остатка)
echo 6 / 3 = $((6 / 3))
# остаток от деления
echo 5 % 4 = $((5 % 4))
# возведение в степень
echo 2 ^ 4 = $[ 2 ** 4 ]



# сложение

echo 4 + 5 = $((4 + 5))

# вычитание

echo 5 — 4 = $[ 5 — 4 ]

# умножение

echo 4 x 5 = $((4 * 5))

# деление (результат будет целое число без остатка)

echo 6 / 3 = $((6 / 3))

# остаток от деления

echo 5 % 4 = $((5 % 4))

# возведение в степень

echo 2 ^ 4 = $[ 2 ** 4 ]


Как видите, для вычисления используется синтаксис: $(( выражение )) или $[ выражение ].

Результаты вычислений можно сохранить в переменную:


a=2
b=4
result=$(( $a ** $b ))
echo $result



a=2

b=4

result=$(( $a ** $b ))

echo $result


Операции с числами с плавающей запятой в командной строке

Для операций с плавающей запятой нам понадобится внешняя команда. Обычно используют утилиту bc, которая берет на себя роль калькулятора.

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


a=10.5
b=3.2
echo «$a-$b» | bc -l



a=10.5

b=3.2

echo «$a-$b» | bc -l


Для сохранения промежуточного результата:


a=10.5
b=3.2
c=`echo «$a-$b» | bc -l`
echo $c



a=10.5

b=3.2

c=`echo «$a-$b» | bc -l`

echo $c


UNIX

Написать комментарий


Данная запись опубликована в 12.09.2018 18:44 и размещена в Программирование.
Вы можете перейти в конец страницы и оставить ваш комментарий.

Мало букафф? Читайте есчо !

Подсчет времени выполнения скрипта в UNIX

Сентябрь 12, 2018 г.

Для того чтобы подсчитать время выполнения, нам понадобится получать время в текущий момент и вычислять разницу. Обе задачи вполне решаемы в консоли UNIX.



Дату мы получим в виде числа секунд и микросекунд с начала UNIX эпохи
[crayon-5f74cd98719d1470572593/] …

Читать

HTTP авторизация для nginx

Декабрь 3, 2019 г.

Задача возникла в контексте SEO, требовалось предотвратить индексацию тестовых сайтов поисковыми системами. На практике видно, что инструкции файла robots.txt …

Читать

Использование арифметических операторов в сценариях Bash

Давайте займемся математикой в Bash!

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

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

Чтобы освежить вашу память, вот арифметические операторы в bash:

оператор Описание
+ прибавление
субстракция
* умножение
/ целочисленное деление (без десятичных чисел)
% деление модуля (дает только остаток)
** возведение в степень (x в степени y)

Выполнение сложения и вычитания в сценариях bash

Давайте создадим bash-скрипт с именем add.sh , который просто добавит два размера файла (в байтах) и отобразит результат.

К настоящему времени вы должны быть знакомы с аргументами в сценариях bash. Надеюсь, вы также знакомы с командами cut и du.

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

Вот сценарий:

#!/bin/bash

fs1=$(du -b $1 | cut -f1)
fs2=$(du -b $2 | cut -f1)

echo "Размер файла $1 is: $fs1"
echo "Размер файла $2 is: $fs2"

total=$(($fs1 + $fs2))

echo "Общий размер составляет: $total"

 

Обратите внимание, что вы передадите два имени файла в качестве аргументов сценарию. Например, здесь мы запускаем сценарий и передаю два файла /etc/passwd и /etc/group в качестве аргументов:

[email protected]:~/scripts$ ./addition.sh /etc/passwd /etc/group
Размер файла /etc/passwd is: 2795
Размер файла /etc/group is: 1065
Общий размер составляет: 3860

 

Наиболее важное направление в сценарии addition.sh:

total=$(($fs1 + $fs2))

 

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

$((arithmetic-expression))

 

Вы также можете использовать оператор минус (-) для вычитания. Например, значение под-переменной в следующем операторе будет равно семи:

sub=$((10-3))

 

Выполнение умножения и деления в сценариях bash

Давайте создадим сценарий bash с именем giga2mega.sh, который преобразует гигабайты (ГБ) в мегабайты (МБ):

#!/bin/bash

GIGA=$1
MEGA=$(($GIGA * 1024))

echo "$GIGA GB is equal to $MEGA MB"

 

Теперь давайте запустим скрипт, чтобы узнать, сколько мегабайт в четырех гигабайтах:

[email protected]:~/scripts$ ./giga2mega.sh 4
4 GB is equal to 4096 MB

 

Здесь мы использовали оператор умножения (*), чтобы умножить количество гигабайт на 1024, чтобы получить эквивалент в мегабайтах:

MEGA=$(($GIGA * 1024))

 

В этот скрипт легко добавить дополнительные функции для преобразования гигабайт (ГБ) в килобайты (КБ):

KILO=$(($GIGA * 1024 * 1024))

 

Мы позволим вам преобразовать гигабайты в байты в качестве практического упражнения!

Вы также можете использовать оператор деления (/), чтобы разделить два числа. Например, значение переменной div в следующем операторе будет равно пяти:

div=$((20 / 4))

 

Обратите внимание, что это целочисленное деление, поэтому все дроби теряются. Например, если вы разделите 5 на 2, вы получите 2, что, конечно, неверно:

[email protected]:~/scripts$ div=$((5 / 2))
[email protected]:~/scripts$ echo $div
2

 

Чтобы получить десятичный вывод; вы можете использовать команду bc. Например, чтобы разделить 5 на 2 с помощью bc команды, вы можете использовать следующий оператор:

echo "5/2" | bc -l
2.50000000000000000000

 

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

 

Использование power и остатка (по модулю)

Создадим калькулятор мощности! Мы собираемся создать скрипт с именем power.sh, который будет принимать два числа a и b (в качестве аргументов) и будет отображать результат возведения a в степень b:

#!/bin/bash
a=$1
b=$2
result=$((a**b))
echo "$1^$2=$result"

 

Обратите внимание, что мы используем оператор возведения в степень (**) , чтобы вычислить результат a в степени b.

Давайте выполним несколько запусков скрипта, чтобы убедиться, что он дает правильные ответы:

[email protected]:~/scripts$ ./power.sh 2 3
2^3=8
[email protected]:~/scripts$ ./power.sh 3 2
3^2=9
[email protected]:~/scripts$ ./power.sh 5 2
5^2=25
[email protected]:~/scripts$ ./power.sh 4 2
4^2=16

 

Вы также можете использовать оператор по модулю (%) для вычисления целочисленных остатков. Например, значение переменной rem в следующем операторе будет равно 2:

rem=$((17%5))

 

Остаток здесь 2, потому что 5 в 17 три раза, а два остается!

 

Время практики: создание сценария bash для конвертера степеней

Давайте завершим это руководство, создав скрипт с именем c2f.sh , который преобразует градусы Цельсия в градусы Фаренгейта, используя уравнение ниже:

F = C x (9/5) + 32

 

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

Вот решение (может быть несколько способов добиться того же результата):

#!/bin/bash

C=$1
F=$(echo "scale=2; $C * (9/5) + 32" | bc -l)

echo "$C градусов Цельсия приравнивается к $F градусов по Фаренгейту."

 

Мы использовали команду bc, потому что мы имеем дело с десятичными знаками, и мы также использовали “scale = 2” для отображения вывода в двух десятичных точках.

Давайте сделаем несколько запусков скрипта, чтобы убедиться, что он выводит правильные результаты:

[email protected]:~/scripts$ ./c2f.sh 2
2 градусов Цельсия равно 35.60 градусов по Фаренгейту.
[email protected]:~/scripts$ ./c2f.sh -3
-3 градусов Цельсия равно 26.60 градусов по Фаренгейту.
[email protected]:~/scripts$ ./c2f.sh 27
27 градусов Цельсия равно 80.60 градусов по Фаренгейту.

 

Отлично! На этом мы подошли к концу этой статьи. Надеюсь, вам понравилось заниматься математикой с помощью bash.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Вся правда о пингвинах!: Краткое введение в программирование на Bash

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

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

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

Арифметика и bash

bash позволяет выполнять арифметические операции. Как вы уже видели в предыдущей статье, арифметика выполняется с помощью команды expr. Однако, подобно команде true, этот вариант считается медленным. Причина кроется в том, что для использования true и expr оболочка должна предварительно запустить их. Лучше всего использовать встроенную в bash функцию, которая работает быстрее. Аналогично тому, что альтернативой true является команда «:», альтернатива expr — заключение арифметического выражения в конструкцию вида $((…)). Будьте внимательны, она отличается от $(…). Отличие тут в количестве скобок. Так давайте же испробуем это:

#!/bin/bash
x=8 # присваиваем x значение 8
y=4 # присваиваем y значение 4

# результат сложения x и y сохраняем в z:
z=$(($x + $y))
echo «Сумма $x и $y равна $z»

Как обычно, выбор используемого метода вычислений за вами. Если использование expr для вас более комфортно и привычнее, чем $((…)), используйте его.

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

Действие

Оператор

Сложение

+

Вычитание

Умножение

*

Целочисленное деление

/

Остаток от деления

%

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

#!/bin/bash
x=5 # устанавливаем x равным 5
y=3 # устанавливаем y равным 3

# сохраняем сумму x и y в переменную add
add=$(($x + $y))

# сохраняем разность x и y в переменную sub

sub=$(($x – $y))

# умножаем x на y и сохраняем результат в переменную mul
mul=$(($x * $y))

# в переменную div сохраняем результат деления x на y

div=$(($x / $y))

# получаем остаток от деления x на y и сохраняем его в переменную mod
mod=$(($x % $y))

# печатаем ответы
echo «Сумма равна: $add»
echo «Разность равна $sub»
echo «Произведение равно $mul»
echo «Результат деления $div»
echo «Остаток от деления $mod»

Код, приведенный выше, можно было бы написать с использованием expr. Например, вместо add=$(($x + $y)) мы могли бы использовать add=$(expr $x + $y) или add=`expr $x + $y`.

Чтение ввода пользователя

А теперь — самое интересное. Мы напишем свой скрипт так, что он будет взаимодействовать с пользователем, а пользователь с ним. Команда для получения данных от пользователя — read. Это встроенная в bash команда, сохраняющая ввод пользователя в указанной переменной:

#!/bin/bash
# спросить у пользователя его имя и поздороваться с ним
echo -n “Введите свое имя: ”
read user_name
echo “Привет $user_name!”

Переменная здесь — это user_name. Конечно, мы могли бы назвать ее как угодно. read прервет выполнение скрипта и будет ждать, пока пользователь введет что-нибудь и нажмет клавишу ENTER. Если клавиша ENTER была нажата без ввода чего-либо, read запустит следующую строку кода. Попробуйте это сделать. Ниже приведен тот же пример, только на этот раз мы

проверяем, вводит ли пользователь что-либо:

#!/bin/bash
# спрашиваем имя пользователя и выводим приветствие
echo -n «Введите имя: »
read user_name

# проверка ввода пользователя
if [ -z «$user_name» ]; then
echo «Вы не сказали мне свое имя!»
exit
fi
echo «Привет $user_name!»

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

Функции

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

#!/bin/bash
# функция hello() печатает сообщение

hello()
{
echo «Вы находитесь в функции hello()»
}

echo «Вызываем функцию hello()…»
hello

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

hello

Когда запускается эта строка, bash ищет скрипт для строки hello(). Он находит его в начале файла и выполняет его содержимое. Функции всегда вызываются по своему имени, что мы и видели выше. При написании функции вы можете обьявить ее, просто указав имя_функции(), как это сделано выше, или если вы хотите сделать ее объявление более явным, можете объявить ее так: function имя_функции(). Ниже представлен альтернативный способ написания функции hello() :

function hello()
{
echo «Вы находитесь в функции hello()»
}

Функции имеют в имени пустые открывающую и закрывающую скобки: «()», за ними следует пара фигурных скобок: «{…}», содержащих тело функции. Другими словами, весь код функции заключен в эти фигурные скобки. Функции всегда должны быть предварительно объявлены до своего вызова. Давайте попробуем в приведенном выше примере вызвать функцию до ее объявления:

#!/bin/bash
echo «Вызов функции hello() …»
hello
# функция hello() просто выводит сообщение
hello()
{
echo «Вы находитесь в функции привет ()»
}

Вот что мы получим, когда попытаемся запустить этот скрипт:

$ ./hello.sh
Вызов функции привет () …
./hello.sh: hello: command not found

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

#!/bin/bash
# admin.sh – инструмент для администратора

# функция new_user () создает новую учетную запись пользователя
new_user()
{
echo «Подготовка к созданию новых пользователей …»
sleep 2

# запускаем программу adduser
adduser
}

echo «1. Добавить пользователя»
echo «2. Выход»

echo «Укажите, что вы хотите сделать:»
read choice
case $choice in
1) new_user # вызов функции new_user()
;;
*) exit
;;
esac

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

Перехват сигналов

Вы можете использовать встроенную в bash программу trap для перехвата сигналов в своих программах. Это хороший способ изящно завершать работу программы. Например, если пользователь, когда ваша программа работает, нажмет CTRL-C — программе будет отправлен сигнал interrupt (SIGINT, signal (7)), который завершит ее. trap позволит вам перехватить этот сигнал, что даст возможность либо продолжить выполнение программы, либо сообщить пользователю, что программа завершает работу. Синтаксис этой команды такой:

trap action signal

Здесь:

action — то, что вы хотите делать, когда сигнал получен;

signal — сигнал, на который стоит реагировать.

Список сигналов можно посмотреть с помощью команды trap -l . При указании сигналов в своих скриптах можно опустить первые три буквы названия сигнала, т. е. SIG. Например, сигнал прерывания это — SIGINT. В вашем скрипте, в качестве его имени, можно указать просто INT. Вы также можете использовать номер сигнала, указанный рядом с его именем. Например, числовое значение сигнала SIGINT — 2. Попробуйте написать и запустить приведенный ниже пример:

#!/bin/bash
# использование команды trap

# перехватываем нажатие CTRL-C и запускаем функцию sorry()

trap sorry INT

# function sorry() prints a message
sorry()
{
echo «Извини меня, Дэйв. Я не могу этого сделать»
sleep 3
}

# обратный отсчет от 10 до 1:

echo «Подготовка к уничтожению системы»
for i in 10 9 8 7 6 5 4 3 2 1; do
echo «Осталось $i секунд до уничтожения…»
sleep 1
done
echo «Запуск программы уничтожения!»

Наберите и запустите приведенный пример. Когда программа будет работать и вести обратный отсчет, нажмите CTRL-C. Это действие отправит программе сигнал прерывания — SIGINT. Тем не менее сигнал будет перехвачен командой trap, которая, в свою очередь, выполнит функцию sorry(). Вы можете заставить trap игнорировать сигнал, указав символ кавычек вместо указания действия. Также вы можете отключить ловушку с помощью тире: «-«. Например:

# запускать функцию sorry(), если получен сигнал SIGINT
trap sorry INT

# отключение ловушки
trap – INT

# ничего не делать при получении сигнала SIGINT
trap ” INT

Если вы отключаете ловушку, программа работает как обычно — при получении сигнала прерывается ее исполнение и она завершает работу. Когда вы говорите trap ничего не делать при получении сигнала — она делает именно это. Ничего. Программа будет продолжать работать, игнорируя сигнал.

Логические И и ИЛИ

Вы уже видели, что такое управляющие структуры и как их использовать. Для решения тех же задач есть еще два способа. Это логическое И — «&&» и логическое «ИЛИ» — « || ». Логическое И используется следующим образом:

выражение_1 && выражение_2

Сначала выполняется выражение, стоящее слева, если оно истинно, выполняется выражение, стоящее справа. Если выражение_1 возвращает ЛОЖЬ, то выражение_2 не будет выполнено. Если оба выражения возвращают ИСТИНУ, выполняется следующий набор команд. Если какое-либо из выражений не истинно, приведенное выражение считает ложным в целом. Другими словами, все работает так:

если выражение_1 истинно И выражение_2 истинно, тогда выполнять…

Примечание переводчика: При работе с булевыми переменными ИСТИНА и ЛОЖЬ (True и False), bash ведет себя отлично от других языков программирования. В других языках 0 соответствует False (Ложь), а 1 — True (Истина). В bash все наоборот. Связано это с такой вещью, как коды завершения программ (см. ниже).

Об этом следует всегда помнить при написании своих скриптов!

Пример использования:

#!/bin/bash
x=5
y=10
if [ «$x» -eq 5 ] && [ «$y» -eq 10 ]; then
echo «Оба условия верны»
else
echo «Условия не верны»
fi

Здесь мы находим, что переменные х и у содержат именно те значения, которые мы проверям, поэтому проверяемые условия верны. Если вы измените значение с х = 5 на х = 12, а затем снова запустите программу, она выдаст фразу «Условия не верны».

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

выражение_1 || выражение_2

Данное выражение в псевдокоде выглядит так:

если выражение_1 истинно ИЛИ выражение_2 истинно, выполняем …

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

#!/bin/bash
x=3
y=2
if [ «$x» -eq 5 ] || [ «$y» -eq 2 ]; then
echo «Одно из условий истинно»
else
echo «Ни одно из условий не является истинным»
fi

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

Аналогичная реализация условия с помощью оператора if будет большего размера, чем вариант с использованием логического И и ИЛИ, поскольку потребует дополнительного вложенного if. Ниже приведен код, реализующий тот же функционал, но с использованием оператора if:

#!/bin/bash
x=5
y=10
if [ «$x» -eq 5 ]; then
if [ «$y» -eq 10 ]; then
echo «Оба условия верны»
else
echo «Оба условия неверны»
fi
fi

Приведенный код менее нагляден для чтения и требует для своего написания больших усилий. Но у вас остается возможность для избавления себя от всех этих трудностей путем использования операторов логических И и ИЛИ.

Использование аргументов

Возможно, вы уже заметили, что большинство программ в Linux не интерактивны. Вы должны указать им какие-то параметры, в противном случае вы получите сообщение со списком возможных аргументов. Возьмем, к примеру, команду more. Если вы не укажете имя файла, она выдаст краткую справку по использованию программы. Ну и конечно же возможно сделать так, чтобы ваши скрипты также могли принимать аргументы. Для этого вам нужно знать что такое переменная вида $#. В ней содержится общее количество аргументов, переданных программе. Например, если вы запустите программу следующим образом:

$ что-то параметр

то значение переменной $# будет равно единице, потому что программе передан только один аргумент. Для двух аргументов ее значение будет равно двум и так далее. Также стоит знать о том, что каждый параметр командной строки (включая даже имя скрипта!!!) может также сохраняться в соответствующие переменные. Так, имя нашей программы что-то будет сохранено в переменной $0. Аргумент программы параметр сохранится в переменной $1. Вы можете использовать до 9 переменных, начиная с $0 (обозначающего имя скрипта), а затем $1-$9, обозначающие аргументы програмы. Давайте посмотрим, как это работает:

#!/bin/bash
# скрипт, печатающий свои аргументы
# проверяем, переданы ли скрипту аргументы:

if [ «$#» -ne 1 ]; then
echo «корректный запуск программы: $0 <параметр>»
fi

echo «Переданный параметр — $1»

Приведенный скрипт ожидает один и только один аргумент для своего запуска. Если вы не укажете ему аргументов — будет выводиться справочная информация. В противном случае, если при запуске указан какой-то аргумент — он передается в наш скрипт, который выведет его на экран. Напоминаю, что $0 это имя скрипта. Именно поэтому эта переменная используется в справочном сообщении. Последняя строка выводит переданный программе параметр — $1.

Работа с временными файлами

Довольно часто вам будет необходимо создавать временные файлы. Обычно это файл, в котором хранятся какие-то используемые скриптом данные либо что-то еще. Как только работа скрипта будет завершена, этот файл нужно удалить. При создании такого файла вы должны задать его имя. Проблема тут кроется в том, что файл, создаваемый вами, не должен случайно переписать уже существующий в той же директории, если их имена совпадут. Для того чтобы создать временный файл с гарантированно уникальным именем, вам нужно использовать символ «$$» символ, либо как префикс, либо как суффикс к имени создаваемого файла. Предположим, вы хотите создать временный файл с именем hello. Возможно, что у пользователя, который работает с нашим скриптом, уже есть файл с таким именем. Создавая файл с именем hello.$$ или $$hello, вы создадите файл с уникальным именем. Например:

$ touch hello
$ ls
hello

$ touch hello.$$
$ ls
hello hello.689

Примерно так и будет выглядеть имя вашего временного файла.

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

Коды завершения программ

Большинство программ возвращают в операционную систему какое-то число, показывающее, насколько удачно программа завершила свою работу. Например, man-страница grep говорит, что grep вернет 0, если заданный шаблон найден, и 1, если совпадений не найдено. Почему нас так волнуют эти коды завершения? По разным причинам. Допустим, мы хотим проверить — есть ли пользователь с данным именем в системе? Один из способов сделать — использовать команду вида: grep имя_пользователя /etc/passwd . Допустим, имя пользователя — vasya:

$ grep vasya /etc/passwd
$

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

#!/bin/bash
# ищем пользователя vasya в /etc/passwd,

# весь вывод перенаправляем в /dev/null

grep vasya /etc/passwd > /dev/null 2>&1

# смотрим код завершения и действуем по обстоятельствам:
if [ «$? -eq 0 ]; then
echo «Пользователь vasya найден»
exit
else
echo «Пользователь vasya не найден»
fi

Теперь, когда вы запустите скрипт, он будет перехватывать и анализировать код завершения grep. Если он равен 0, значит пользователь найден и мы выводим соответствующее сообщение об ошибке. В противном случае скрипт напечатает, что пользователя найти не получилось. Это очень простой способ использования получаемого кода завершения программы. По мере практики вы сами будете понимать, для решения какой задачи вам нужно использовать эти коды завершения.

Если вас озадачивает конструкция вида 2>&1, тут все довольно просто. В Linux этими числами обозначаются дескрипторы файлов. 0 — стандартный ввод (по умолчанию, клавиатура), 1 стандартный вывод (по умолчанию, монитор) и 2 — вывод стандартных ошибок (по умолчанию, монитор). Весь вывод команды идет в файл с дескриптором 1, любые ошибки отправляются в файл с дескриптором 2. Если вы не хотите, чтобы сообщения об ошибках появлялись на экране, просто перенаправьте его в /dev/null. Но это не прекратит вывод на экран обычной информации. Например, если у вас нет разрешения на чтение домашнего каталого другого пользователя, вы не сможете просмотреть список его содержимого:

$ ls /root
ls: /root: Permission denied

$ ls /root 2> /dev/null
$

Как видите, во второй раз информация об ошибке не была напечатана. Все то же самое относится к другим программам и дескриптору 1. Если вы не хотите видеть нормальный выход из программы, то есть хотите, чтобы она работала молча, вы можете перенаправить в /dev/null и его. Теперь, если вы не хотите видеть вообще никакого вывода программы — добавьте в нее следующее:

$ ls /root > /dev/null 2>&1

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

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

Конструкция вида 2>&1 перенаправляет вывод ошибок (дескриптор 2) на стандартный вывод (дескриптор 1). Знак «загогулины» — & — тут нужен для того, чтобы пояснить bash, что вы имеете в виду не файл с именем 1, а именно файл с дескриптором 1, т. е. стандартный вывод. Если вы укажете что-то вроде:

$ команда 2>1

то стандартный вывод ошибок пойдет в файл с именем 1. Конструкцией 2>&1 мы «сцепляем» вывод команды и вывод ошибок вместе. А первым перенаправлением (первым символом > в коментируемой команде) мы отправляем весь вывод команды в /dev/null. Чтобы дополнительно понять, как все работает, можете поэкспериментировать, убрав 2>&1 из команды и перезапустив ее.

А что если вы хотите, чтобы ваш скрипт тоже возвращал какой-нибудь код завершения при выходе? Команда exit может принимать один аргумент — тот самый код завершения. Обычно число 0 используется для обозначения успешного завершения работы. Число, отличное от нуля означает, что произошла какая-то ошибка. Какое число возвращать — решает сам програмист. Посмотрим приведенный пример:

#!/bin/bash
if [ -f «/etc/passwd» ]; then
echo «Файл passwd существует»
exit 0
else
echo «Нет такого файла»
exit 1
fi

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

Переносимость ваших скриптов на bash

При написании ваших собственных скриптов важно делать это так, чтобы они оставались переносимыми. Термин «переносимость» означает, что если ваш скрипт работает под Linux, то он должен работать в другой Unix-системе с малыми изменениями или вообще без них. Чтобы добиться этого, вы должны быть осторожны при вызове внешних программ. Разработчик должен при этом ответить на вопрос: «Будет ли эта программа доступна на другом варианте Unix?» (и что более важно — будет ли она там работать также, как на Linux — прим. перев.). Допустим, вы используете программу foo, которая на Linux работает аналогично echo, поэтому вместо echo вы используете ее. Но если ваш скрипт будет работать на других системах, где нет программы foo, он начнет выдавать сообщения об ошибках. Кроме того, имейте в виду, что разные версии bash могут иметь разные методы для одних и тех же операций. Например, конструкция VAR = $(ps) делает то же самое, что и VAR = `ps`, но на самом деле старые версии оболочек, например Bourne shell (sh), признают только последний синтаксис. Если вы собираетесь распространять свои скрипты, обязательно включайте текстовый файл README, который будет предупреждать пользователя о любых сюрпризах, в том числе и о том, что скрипт проверялся на такой-то версии bash. Желательно также указать, какие программы и библиотеки (и каких версий) будут нужны скрипту.

Примечание переводчика: Для проверки наличия в скрипте команд и функций специфичных для bash в ALT Linux есть пакет checkbashisms, который взят из пакета devscripts Debian.

Заключение

Пришла пора завершить это краткое введение в написание скриптов на bash. Однако ваше обучение этому умению еще не завершено. В тоже время, написанного вполне достаточно, чтобы вы могли модифицировать имеющиеся скрипты и писать собственные. Если вы действительно хотите стать мастером написания скриптов на bash, я рекомендую приобрести книгу «Learning the bash shell» (Изучение оболочки bash), 2-е издание издательства O’Reilly & Associates, Inc.

Скрипты на bash идеально подходят для повседневной работы по администрированию. Но если вы планируете что-то более серьезное, следует использовать гораздо более мощный язык, такой как C или Perl. Удачи!

Bash в примерах. Часть 2.

Еще больше основ программирования в bash

Обработка аргументов

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

В простом скрипте из предыдущей статьи мы использовали переменную «$1«, которая содержит первый аргумент командной строки при вызове скрипта. Аналогично можно использовать «$2», «$3» и так далее для доступа ко второму, третьему… аргументам командной строки. Вот пример:

#!/bin/bash

echo "Имя скрипта — $0"
echo "Первый аргумент: $1"
echo "Второй аргумент: ${2}"
echo "Семнадцатый аргумент: ${17}"
echo "Количество аргументов: $#"

Обратите внимание, что в переменной «$0» содержится имя самого скрипта, который запущен из командной строки. А переменная «$#» содержит количество переданных скрипту аргументов. Использование фигурных скобок необязательно только для переменных состоящих из одной цифры (с $0 по $9). Попробуйте позапускать этот скрипт с разным числом аргументов и посмотрите как он работает.

Иногда необходимо сослаться сразу на все аргументы командной строки. Для этого в bash есть специальная переменная «[email protected]«, которая содержит все аргументы переданные скрипту разделенные пробелами. Мы будем использовать эту переменную чуть позже при рассказе о циклах со счетчиком (конструкция «for»).

Управляющие конструкции bash

Если вы раньше программировали на процедурных языках, таких как Си, Паскаль, Перл и тому подобных, вам должны быть знакомы управляющие конструкции вроде «if», «for» и другие. В bash тоже есть все эти конструкции. В следующих разделах пособия я познакомлю вас с ними и покажу чем они отличаются от подобных конструкций из других языков программирования. Если вы раньше не программировали — не волнуйтесь. Материал будет изложен подробно и дополнен примерами, так что даже новичок в программировании сможет разобраться.

Оператор условного выбора «if»

Если вы раньше программировали на языке Си, то должны знать сколько требуется усилий чтобы определить какой из двух файлов был создан первым, например. А все из-за того, что в Си нет встроенных средств для такого рода сравнения. Вместо этого приходится использовать системный вызов stat() для каждого файла и затем сравнивать результат вручную. Но в bash есть встроенный механизм сравнения файлов, Поэтому узнать «доступен ли для чтения файл /tmp/myfile» настолько же просто как и узнать «превосходит ли значение переменной ‘myvar’ 4».

Привожу список наиболее часто употребляемых в bash операторов сравнения

Файлы

-a file
истинно если файл существует.

-d file
истинно если файл существует и является директорией.

-f file
истинно если файл существует и является обычным файлом.

-r file
истинно если файл существует и доступен для чтения.

-s file
истинно если файл существует и его размер больше 0.

-w file
истинно если файл существует и доступен для записи.

-x file
истинно если файл существует и является исполняемым.

file1 -nt file2
истинно если файл file1 новее чем file2 или file1 (в соответствии со временем последнего изменения) существует, а file2 нет.

file1 -ot file2
истинно если файл file1 старше чем file2 или file2 существует, а file1 нет.

file1 -ef file2
истинно если оба файла ссылаются на одно и то же устройство или инод.

Строки

-z string
истинно если строка имеет нулевую длину.

-n string
истинно если длина строки не нулевая.

string1 = string2
истинно если строки равны.

string1 != string2
истинно если не равны.

string1 < string2
истинно если строка 1 стоит в алфавитном порядке перед строкой 2.

string1 > string2
истинно если строка 1 стоит в алфавитном порядке после строки 2.

В следующих примерах показано как использовать оператор сравнения в конструкции «if»:

if [ -z "$myvar" ]
then
echo "Переменная 'myvar' не определена."
fi

Квадратные скобки вычисляют условное выражение стоящее в них (это синоним встроенной функции bash — test). Возвращаемый результат — 1 или 0 в зависимости от того выполняется условие или нет. в скобках может стоять несколько выражений, связанных логическими операторами «и» или «или«. Подробнее на странице справки help test.

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

if [ "$myvar" -eq 3 ]
then
echo "myvar равно 3"
fi

if [ "$myvar" = "3" ]
then
echo "myvar равно 3"
fi

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

Тонкости при сравнении строк

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

if [ $myvar = "foo bar oni" ]
then
echo "yes"
fi

В этом примере, если значение переменной «$myvar» будет равно «foo», код будет работать как и ожидается и не печатать ничего. Но если значение переменной «$myvar» будет равно «foo bar oni», скрипт вызовет следующую ошибку:

[: too many arguments

После подстановки значения переменной, bash пытается произвести следующую операцию сравнения:

[ foo bar oni = "foo bar oni" ]

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

if [ "$myvar" = "foo bar oni" ]
then
echo "yes"
fi

Этот код будет работать корректно и не преподнесет нам больше никаких неприятных сюрпризов.

Замечание: Если вы хотите, чтобы подстановка значений переменных продолжала работать, заключайте их в двойные кавычки а не в одинарные. Одинарные кавычки отключают подстановку значения переменных.

Конструкция создания циклов «for»

Хорошо, с условными переходами разобрались, пора перейти к циклическим конструкциям. Начнем с управляющей конструкции «for«. Вот стандартный пример:

#!/bin/bash

for x in one two three four
do
echo "number $x"
done

Результат:
number one
number two
number three
number four

Что же именно произошло? Часть «for x» цикла «for» определяет переменную (называемую итератором) «$x», которая последовательно принимает значения «one», «two», «three», и «four» (по одному за один такт цикла). После присвоения каждого нового значения переменной «$x», выполняется тело цикла (код между словами «do» и «done»). В теле цикла мы выводим на печать значение переменной «$x». Заметим, что после слова «in» в конструкции «for» всегда стоит некий список. В данном примере мы указали четыре слова, но этот список может содержать имена файлов или даже шаблон (wildcard). В следующем примере показано как использовать шаблоны при инициализации итератора цикла:

#!/bin/bash

for myfile in /etc/r*
do
if [ -d "$myfile" ]
then
echo "$myfile (dir)"
else
echo "$myfile"
fi
done

результат:
/etc/rc0.d (dir)
/etc/rc1.d (dir)
/etc/rc2.d (dir)
/etc/rc3.d (dir)
/etc/rc4.d (dir)
/etc/rc5.d (dir)
/etc/rc6.d (dir)
/etc/rc.local
/etc/rcS.d (dir)
/etc/rearj.cfg
/etc/reportbug.conf
/etc/resolvconf (dir)
/etc/resolv.conf
/etc/rmt
/etc/rpc
/etc/rsyslog.conf
/etc/rsyslog.d (dir)

Код этого цикла исполнится для каждого файла из /etc/ имя которого начинается с «r». Сначала bash найдет все такие файлы и заменит шаблон строкой /etc/rc0.d /etc/rc1.d /etc/rc2.d /etc/rc3.d /etc/rc4.d … /etc/rsyslog.d перед тем как приступить к выполнению цикла. В теле цикла для каждого файла из списка проверяется является ли этот файл директорией при помощи оператора «-d«. Если файл оказался директорией, рядом с его называнием печатается «(dir)».

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

for x in /etc/r??? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/*
do
cp $x /mnt/mydira
done

Bash в этом примере подставляет значение переменной и раскрывает шаблоны. А затем копирует все файлы в заданную директорию.

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

for x in ../* mystuff/*
do
echo "$x is a silly file"
done

В этом примере bash раскрывает шаблон относительно текущей рабочей директории (не той в которой находится скрипт, а той которую показывает команда «pwd»). Поиграйтесь с этим скриптом, позапускайте его из разных директорий и посмотрите на результат.

Иногда может потребоваться запустить цикл по списку аргументов из командной строки. Вот как это делается:

#!/bin/bash

for i in "[email protected]"
do
echo "Вы написали: ${i}."
done

результат:
$ ./test.sh hello there you silly
Вы написали: hello.
Вы написали: there.
Вы написали: you.
Вы написали: silly.

В этом примере мы использовали переменную «[email protected]» о которой говорили выше.

Арифметика в shell

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

$ echo $(( 100 / 3 ))
33
$ myvar="56"
$ echo $(( $myvar + 12 ))
68
$ echo $(( $myvar - $myvar ))
0
$ myvar=$(( $myvar + 1 ))
$ echo $myvar
57

Теперь, когда вы познакомились с вычислением арифметических выражений в shell, пришло время рассказать о циклических конструкциях «while» и «until».

Циклические конструкции с условиями («while» и «until»)

«while»–цикл исполняется пока выражение в квадратных скобках истинно. Он имеет следующий формат:

while [ условие ]
do
код
done

В следующем примере тело цикла исполняется ровно 10 раз:

myvar=0
while [ $myvar -ne 10 ]
do
echo "$myvar"
myvar=$(( $myvar + 1 ))
done

После каждого выполнения кода тела цикла переменная «myvar» увеличивается на 1. Когда значение переменной становится равным 10, условие в квадратных скобках не выполняется и цикл прерывается.

«Until»–цикл очень похож на «while»–цикл: он повторяется пока выражение в квадратных скобках ложно. Вот пример «until»–цикла по функциональности идентичного «while»–циклу из предыдущего примера:

myvar=0
until [ $myvar -eq 10 ]
do
echo $myvar
myvar=$(( $myvar + 1 ))
done

Экстренный выход из цикла

Для экстренного выхода из «for», «while» или «until» цикла используется команда break. Для выхода из нескольких вложенных циклов — break N, где N — количество вложенных циклов.

name=0
while :
do
wget http://example.com/gallery/${name}.png
[ $? -ne 0 ] && break
done

В последнем примере: «while :» — бесконечный цикл. Двоеточие — это команда bash которая не делает ничего но всегда завершается успехом. Переменная $? содержит статус с которым завершилась последняя команда (подробнее о специальных переменных смотри man bash). В нашем случае код отличный от 0 обозначает что при скачивании файла произошла ошибка. Как только условие в квадратных скобках выполнено, интерпретатор переходит к исполнению команды стоящей после логического и (&&). Break прерывает выполнение цикла.

Предпоследнюю строку предыдущего примера можно заменить на знакомую нам условную конструкцию «if» (помним, что в bash одно действие можно сделать несколькими разными способами):

[ $? -ne 0 ] && break

то же самое но через условную конструкцию:

if [ $? -ne 0 ]
then
break
fi

Или в одну строку

if [ $? -ne 0 ]; then break; fi

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

Команда–переключатель «case»

Конструкция условного перехода «case» может оказаться очень полезной. Вот пример ее использования:

case "${x##*.}" in
gz) gzunpack ${SROOT}/${x} ;;
bz2) bz2unpack ${SROOT}/${x} ;;
*) echo "Формат архива не определен."
exit
;;
esac

В этом примере сначала происходит обработка строки в переменной «$x» — «${x##*.}». Как мы помним из первой статьи, после этой операции в переменной «$x» остается только расширение файла. Затем bash сравнивает это расширение с вариантами стоящими слева от одинарных скобок «)«. Если совпадение найдено, выполняется соответствующее действие. Если совпадения не найдено, никаких действий не выполняется, но в данном конкретном коде совпадение будет всегда, потому что в последней строке стоит шаблон «*«, совпадающий с любой последовательностью символов.

Функции и пространство имен

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

tarview() {
echo -n "Displaying contents of $1 "
if [ ${1##*.} = tar ]
then
echo "(uncompressed tar)"
tar tvf $1
elif [ ${1##*.} = gz ]
then
echo "(gzip-compressed tar)"
tar tzvf $1
elif [ ${1##*.} = bz2 ]
then
echo "(bzip2-compressed tar)"
cat $1 | bzip2 -d | tar tvf -
fi
}

Эта функция может быть переписана с использованием конструкции «case«. Сможете ли вы проделать это самостоятельно?

Выше мы определили функцию с именем «tarview», которая принимает один аргумент — имя тарбола. Эта функция определяет вид тарбола (без сжатия, сжатый gzip-ом или bzip2) по расширению, затем печатает этот тип и показывает содержимое архива. Если формат определить не удалось, выводится соответствующее сообщение. Вот пример вызова функции:

$ ./tarview.sh shorten.tar.gz
Displaying contents of shorten.tar.gz (gzip-compressed tar)
drwxr-xr-x ajr/abbot 0 1999-02-27 16:17 shorten-2.3a/
-rw-r--r-- ajr/abbot 1143 1997-09-04 04:06 shorten-2.3a/Makefile
-rw-r--r-- ajr/abbot 1199 1996-02-04 12:24 shorten-2.3a/INSTALL
-rw-r--r-- ajr/abbot 839 1996-05-29 00:19 shorten-2.3a/LICENSE
....

Как вы видите, обращение к аргументам внутри функции происходит по тем же именам как и к аргументам командной строки внутри скрипта. Переменная «$#» содержит количество переданных функции аргументов. Единственное что остается по-прежнему — переменная «$0«. Она содержит название скрипта при вызове функции из скрипта или строку «bash» при вызове функции напрямую из командной строки.

Вызвать функцию из командной строки можно следующим образом: сохраняем код функции в файл (например с названием «/myfunc.txt») а затем даем следующую команду:

$ . myfunc.txt

или что тоже самое

$ source myfunc.txt

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

$ tarview shorten.tar.gz

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

Пространство имен

Часто возникает потребность создать переменную окружения внутри функции. В большинстве компилируемых языков (например Си), когда вы создаете переменную внутри функции, она попадает в отдельное пространство имен этой функции. Например, если вы напишите функцию «my function» на C и внутри этой функции создадите переменную «x», то она никак не повлияет на переменную с тем же именем «x», созданную вне функции «myfunction».

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

#!/bin/bash

myvar="hello"

myfunc() {

myvar="one two three"
for x in $myvar
do
echo $x
done
}

myfunc

echo $myvar $x

Результатом исполнения этого кода будет строка «ne two three three«, показывающая что переменная «myvar», созданная внутри функции перезаписала значение глобальной переменной «myvar» и что последнее значение итератора «x» равное «three» продолжило существование даже после завершения функции.

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

#!/bin/bash

myvar="hello"

myfunc() {
local x
local myvar="one two three"
for x in $myvar
do
echo $x
done
}

myfunc

echo $myvar $x

Результатом выполнения этого кода будет строка «hello» — значение глобальной переменной «myvar» (на которую никак не повлияла локальная переменная «myvar», созданная внутри функции), а локальная переменная «x» перестает существовать после завершения функции.

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

Подведение итогов

Вот и все. Теперь вы имеете представление о программировании в bash и можете писать свои скрипты. За более подробной информацией обращайтесь к справке man bash или к руководству Advanced Bash-Scripting Guide

Смотри также

Оригинал статьи— Bash by example, Part 2 (eng)

Основы BASH. Часть 2 [Справочная система PuppyRus Linux]



Эта часть посвящена циклам, математическим операциям и использованию внешних команд.

Оператор for-in предназначен для поочередного обращения к значениям перечисленным в списке. Каждое значение поочередно в списке присваивается переменной. Синтаксис следующий:

for переменная in список_значений
do
  команды
done

Рассмотрим небольшой пример:

#!/bin/bash
for i in 0 1 2 3 4 #переменной $i будем поочередно присваивать значения от 0 до 4 включительно
do
echo "Console number is $i" >> /dev/pts/$i #Пишем в файл /dev/pts/$i(файл виртуального терминала) строку "Console number is $i"
done #цикл окончен
exit 0

После выполнения примера в первых 5 виртуальных консолях (терминалах) появится строка с её номером. В переменную $i поочередно подставляются значения из списка и в цикле идет работа со значением этой переменной.

Цикл while сложнее цикла for-in и используется для повторения команд, пока какое-то выражение истинно( код возврата = 0). Синтаксис оператора следующий:

while выражение или команда возвращающая код возврата
do
  команды
done

Пример работы цикла рассмотрим на следующем примере:

#!/bin/bash
again=yes #присваиваем значение "yes" переменной again
while [ "$again" = "yes" ] #Будем выполнять цикл, пока $again будет равно "yes"
do
echo "Please enter a name:"
read name
echo "The name you entered is $name"
 
echo "Do you wish to continue?"
read again
done
echo "Bye-Bye"

А теперь результат работы скрипта:

[email protected]:~$ ./bash3_primer1.sh
Please enter a name:
ite
The name you entered is ite
Do you wish to continue?
yes
Please enter a name:
mihail
The name you entered is mihail
Do you wish to continue?
no
Bye-Bye

Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле.Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл.

Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор »[» аналог команды test, которая проверяет истинность условия, которое ей передали.

Рассмотрим еще один пример, я взял его из книги Advanced Bash scripting. Уж очень он мне понравился Улыбка, но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO. Эта практически полный аналог цикла WHILE-DO, только выполняется пока какое-то выражение ложно.

Вот пример:

#!/bin/bash
echo "Введите числитель: "
read dividend
echo "Введите знаменатель: "
read divisor
 
dnd=$dividend #мы будем изменять переменные dividend и divisor,
#сохраним их знания в других переменных, т.к. они нам
#понадобятся
dvs=$divisor
remainder=1
 
until [ "$remainder" -eq 0 ]
do
let "remainder = dividend % divisor"
dividend=$divisor 
divisor=$remainder
done 
 
echo "НОД чисел $dnd и $dvs = $dividend"

Результат выполнения скрипта:

[email protected]:~$ ./bash3_primer3.sh
Введите числитель:
100
Введите знаменатель:
90
НОД чисел 100 и 90 = 10

Команда let.

Команда let производит арифметические операции над числами и переменными.

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

#!/bin/bash
echo "Введите a: "
read a
echo "Введите b: "
read b
 
let "c = a + b" #сложение
echo "a+b= $c"
let "c = a / b" #деление
echo "a/b= $c"
let "c <<= 2" #сдвигает c на 2 разряда влево
echo "c после сдвига на 2 разряда: $c"
let "c = a % b" # находит остаток от деления a на b
echo "$a / $b. остаток: $c "

Результат выполнения:

[email protected]:~$ ./bash3_primer2.sh
Введите a:
123
Введите b:
12
a+b= 135
a/b= 10
c после сдвига на 2 разряда: 40
123 / 12. остаток: 3

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

+ — сложение
— — вычитание
* — умножение
/ — деление
** — возведение в степень
% — модуль(деление по модулю), остаток от деления

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

Например: a = a+b эквивалентно a +=b и т.д.

Для начала немного полезной теории.

Перенаправление потоков

В bash (как и многих других оболочках) есть встроенные файловые дескрипторы: 0 (stdin), 1 (stdout), 2 (stderr).

stdout — Стандартный вывод. Сюда попадает все что выводят программы
stdin — Стандартный ввод. Это все что набирает юзер в консоли
stderr — Стандартный вывод ошибок.

Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), < (перенаправление ввода). Оперировать ими не сложно. Например:

cat /dev/random > /dev/null

перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция ) или

ls -la > listing

записать в файл listing содержание текущего каталога (уже полезней)

Если есть необходимость дописывать в файл (при использовании »>» он заменяется), необходимо вместо »>» использовать »>>»

sudo < my_password

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

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

./program_with_error 2> error_file

цифра 2 перед »>» означает что нужно перенаправлять все что попадет в дескриптор 2(stderr).

Если необходимо заставить stderr писать в stdout, то это можно можно след. образом:

./program_with_error 2>&1

символ »&» означает указатель на дескриптор 1(stdout)

(По умолчанию stderr пишет на ту консоль, в которой работает пользователь (вернее пишет на дисплей)).

Конвейер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой:

команда1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2

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

ls -la | grep "hash" |sort > sortilg_list

вывод команды ls -la передается команде grep, которая отбирает все строки, в которых встретится слово hash, и передает команде сортировке sort, которая пишет результат в файл sorting_list. Все довольно понятно и просто.

Чаще всего скрипты на Bash используются в качестве автоматизации каких-то рутинных операций в консоли, отсюда иногда возникает необходимость в обработке stdout одной команды и передача на stdin другой команде, при этом результат выполнения одной команды должен быть неким образом обработан. В этом разделе я постараюсь объяснить основные принципы работы с внешними командами внутри скрипта. Думаю что примеров я привел достаточно и можно теперь писать только основные моменты.

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

a = `echo "qwerty"`
echo $a

Результат работы: qwerty

Однако если вы захотите записать в переменную список директорий, то необходимо, должным образом обработать результат для помещения данных в переменную. Рассмотрим небольшой, пример:

LIST=`find /svn/ -type d 2>/dev/null| awk '{FS="/"} {print $4}'| sort|uniq | tr '\n' ' '`
for ONE_OF_LIST in $LIST
do
svnadmin hotcopy /svn/$ONE_OF_LIST /svn/temp4backup/$ONE_OF_LIST
done

Здесь мы используем цикл for-do-done для архивирование всех директорий в папке /svn/ с помощью команды svnadmin hotcopy(что в нашем случае не имеет никого значения, просто как пример). Наибольшй интерес вызывает строка: LIST=`find /svn/ -type d 2>/dev/null| awk ‘{FS=»/»} {print $4}’| sort|uniq | tr ‘\n’ ‘ ‘` В ней переменной LIST присваивается выполнение команды find, обработанной командами awk, sort, uniq,tr(все эти команды мы рассматривать не будем, ибо это отдельная статья). В переменной LIST будут имена всех каталогов в папке /svn/ пгомещенных в одну строку(для того чтобы её стравить циклу.

Как видно, все не сложно, достаточно понять принцип и написать пару своих скриптов. В заключении статьи хочу пожелать удачи в изучении BASH и Linux в целом. Критика, как водится приветствуется. Следующая статья возможно будет посвящена использованию таких программ как sed, awk.


Автор: Zloy_T

По мотивам форума.

Арифметические операции Bash — Linux Подсказка

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

Пример — 1: Использование команды «expr»

Самая старая команда для выполнения арифметических операций в bash — « expr ».Эта команда может работать только с целочисленными значениями и выводит результат прямо в терминал. Вы должны использовать пробел с каждым операндом, если вы хотите использовать команду « expr» для выполнения каких-либо математических операций. Создайте файл bash и добавьте различные команды ‘expr’ , чтобы проверить, как работает команда ‘expr’ .

#! / Bin / bash

# Работает как строка
expr ’10 + 30 ‘

# Работает как строка
expr 10 + 30

# Выполняет сложение
expr 10 + 30

# Найти остаток
expr 30% 9

# Использование expr с обратным апострофом
myVal1 = `expr 30/10`
echo $ myVal1

# Использование expr внутри команды replace
myVal2 = $ (expr 30-10)
echo $ myVal2

Запустить файл arith2.ш.

Выход:

Выходные данные показывают, что арифметические операторы работают только тогда, когда для каждого числового значения используется пробел, а с командой expr не используются одиночные кавычки. Вы также можете назначить вывод команды expr переменной и распечатать переменную позже, используя обратную кавычку или замену команды . 30/10 вычисляется с использованием обратного апострофа , а 30-10 вычисляется с использованием замены команды .

Пример — 2: Использование команды «let»

«let» — еще одна встроенная команда для выполнения арифметических операций в bash. «let» Команда не может распечатать вывод на терминал без сохранения значения в переменной. Но команду «let» можно использовать для снятия других ограничений команды «expr» . Создайте файл bash и добавьте следующий код, чтобы увидеть, как работает команда ‘let’ .

#! / Bin / bash

# Умножение 9 на 8
let val1 = 9 * 3
echo $ val1

# Деление 8 на 3
let «val2 = 8/3»
echo $ val2

# Вычитание 3 from 9
let val3 = 9-3
echo $ val3

# Применение приращения
let val4 = 7
let val4 ++
echo $ val4

# Использование значения аргумента в арифметической операции
let «val5 = 50 + $ 1»
echo $ val5

Запустить файл arith3.ш.

Выход:

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

Пример — 3: Использование двойных скобок

Вы можете выполнять любые арифметические операции в bash без использования каких-либо команд. Здесь двойные скобки используются для арифметических задач, а использование двойных скобок для выполнения математических выражений более гибкое, чем такие команды, как ‘expr’ или ‘let’ . Создайте файл bash и добавьте следующий код для проверки арифметических операций с использованием двойных скобок.

#! / Bin / bash

# Вычислить математическое выражение
val1 = $ ((10 * 5 + 15))
echo $ val1

# Использование оператора пост или предварительного увеличения / уменьшения
((val1 ++))
echo $ val1
val2 = 41
((—val2))
echo $ val2

# Использование сокращенного оператора
((val2 + = 60))
echo $ val2

# Деление 40 на 6
((val3 = 40 / 6))
echo $ val3

Запустить файл arith4.ш.

Выход:

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

Пример — 4: Использование команды «bc» для чисел с плавающей запятой или двойных чисел

Одно из основных ограничений вышеупомянутых способов выполнения арифметических операций в bash заключается в том, что « expr » или «let» или двойные скобки выражение не могут создавать числа с плавающей запятой или двойные числа.Результатом операций деления в приведенных выше примерах являются целые числа. ‘bc’ Команда может использоваться для решения этой проблемы, и она работает как базовый калькулятор для операционной системы Linux. Создайте файл bash и добавьте следующий код, чтобы проверить использование команды ‘bc’ в арифметических операциях.

#! / Bin / bash

# Деление 55 на 3 с только bc
echo «55/3» | bc

# Деление 55 на 3 с помощью опции bc и -l
echo «55/3» | bc -l

# Деление 55 на 3 с помощью bc и значения шкалы
echo «scale = 2; 55/3» | до н.э.

Запустить файл arith4.ш.

Выход:

Выходные данные показывают, что простая команда « bc » выдает целочисленное значение, как и другие параметры, при выполнении любого выражения деления. ‘ bc -l’ Команда генерирует точный результат деления, и вы можете ограничить дробную часть, используя масштаб значение. Здесь используется масштаб = 2 . Таким образом, вывод показывает 2 цифры после десятичной точки.

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

Для получения дополнительной информации смотрите видео!

.

Выполнение арифметических операций — Учебник по написанию сценариев оболочки Linux

← Получение пользовательского ввода с клавиатуры • Home • Создание целочисленной переменной →

Вы можете выполнять математические операции с переменными оболочки Bash. Оболочка bash имеет встроенную арифметическую опцию. Вы также можете использовать внешние команды, такие как expr и bc Calculator.

Арифметическое расширение в Bash Shell

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

 $ ((выражение))
$ ((n1 + n2))
$ ((n1 / n2))
$ ((n1-n2))
 

Примеры

Сложите два числа на лету с помощью команды echo:

Сложите два числа, используя переменные x и y.Создайте программу оболочки под названием add.sh с помощью текстового редактора:

 #! / Bin / bash
х = 5
у = 10
ans = $ ((х + у))
echo "$ x + $ y = $ ans"
 

Сохраните и закройте файл. Запустите его следующим образом:

Примеры выходных данных:

 5 + 10 = 15 

Создайте интерактивную программу с помощью команды чтения add1.sh в текстовом редакторе:

 #! / Bin / bash
read -p "Введите два числа:" x y
ans = $ ((х + у))
echo "$ x + $ y = $ ans"
 

Сохраните и закройте файл. Запустите его следующим образом:

 chmod + x add1.ш
./add1.sh
 

Примеры выходных данных:

 Введите два числа: 20 30
20 + 30 = 50 
Математические операторы с целыми числами
Оператор Описание Пример оценивает до
+ Дополнение эхо $ ((20 + 5)) 25
Вычитание эхо $ ((20-5)) 15
/ Дивизия эхо $ ((20/5)) 4
* Умножение эхо $ ((20 * 5)) 100
% Модуль эхо $ ((20% 3)) 2
++ постинкремент (добавить значение переменной на 1) x = 5
эхо $ ((x ++))
эхо $ ((x ++))
5
6
постдекремент (вычесть значение переменной на 1) x = 5
эхо $ ((x—))
4
** Возведение в степень x = 2
y = 3
echo $ ((x ** y))
8
Порядок приоритета

Операторы оцениваются в порядке приоритета.Уровни перечислены в порядке убывания приоритета (цитата из справочной страницы bash).

 id ++ id--
              переменный пост-инкремент и пост-декремент
       ++ id --id
              переменный пре-инкремент и пре-декремент
       - + унарный минус и плюс
       ! ~ логическое и побитовое отрицание
       ** возведение в степень
       * /% Умножения, деления, остатка
       + - сложение, вычитание
       << >> побитовые сдвиги влево и вправо
       <=> = <>
              сравнение
       ==! = Равенство и неравенство
       & побитовое И
       ^ побитовое исключающее ИЛИ
       | побитовое ИЛИ
       && логическое И
       || логическое ИЛИ
       expr? expr: expr
              условный оператор
       = * = / =% = + = - = << = >> = & = ^ = | =
              назначение
       expr1, expr2
              запятая
 

← Получение пользовательского ввода с клавиатуры • Home • Создание целочисленной переменной →

.

Арифметика — Учебник по созданию сценариев Bash

Арифметика!

Все складывается.

Введение

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

Есть несколько способов выполнить арифметику в сценариях Bash. Мы рассмотрим их для полноты, но рекомендуемый подход — арифметическое расширение (рассмотрено последним).

Пусть

let — это встроенная функция Bash, которая позволяет нам выполнять простую арифметику. Он соответствует основному формату:

let <арифметическое выражение>

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

Давайте посмотрим на простой пример:

let_example.sh
  1. #! / Bin / bash
  2. пусть a = 5 + 4
  3. эхо
  4. долл. США

  5. пусть «a = 5 + 4»
  6. эхо
  7. долл. США

  8. лет a ++
  9. эхо
  10. долл. США

  11. let «a = 4 * 5»
  12. эхо
  13. долл. США

  14. let «a = 1 $ + 30»
  15. эхо
  16. долл. США

Давайте разберемся:

  • Строка 4 — это основной формат.Обратите внимание: если мы не заключаем выражение в кавычки, оно должно быть написано без пробелов.
  • Строка 7 — На этот раз мы использовали кавычки, которые позволяют нам расставлять выражение, чтобы сделать его более читабельным.
  • Строка 10 — Это сокращение для увеличения значения переменной a на 1. Это то же самое, что и запись «a = a + 1».
  • Строка 16 — Мы также можем включать в выражение другие переменные.
  1. ./let_example.sh 15
  2. 9
  3. 9
  4. 10
  5. 20
  6. 45

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

+, -, \ *, / сложение, вычитание, умножение, деление
var ++ Увеличьте переменную var на 1
var — Уменьшить переменную var на 1
% Модуль (возвращает остаток после деления)

Эти операторы также могут использоваться в других механизмах, описанных ниже.

Expr

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

expr item1 оператор item2

Давайте посмотрим на простой пример:

expr_example.ш
  1. #! / Bin / bash
  2. expr 5 + 4
  3. expr «5 + 4»
  4. expr 5 + 4
  5. expr 5 \ * 1
  6. $

  7. экспр 11% 2
  8. a = $ (выражение 10–3)
  9. эхо
  10. долл. США

Давайте разберемся:

  • Строка 4 — это основной формат.Обратите внимание, что между элементами должны быть пробелы и никаких кавычек.
  • Строка 6 — Если мы заключим выражение в кавычки, выражение не будет вычисляться, а будет напечатано.
  • Строка 8 — Если мы не ставим пробелы между элементами выражения, тогда выражение не будет оцениваться, а будет напечатано.
  • Строка 10 — Некоторые символы имеют особое значение для Bash, поэтому мы должны экранировать их (поставить обратную косую черту перед), чтобы удалить их особое значение.
  • Строка 12 — Здесь мы демонстрируем оператор модуля . Модуль — это остаток от деления первого элемента на второй.
  • Строка 14 — На этот раз мы используем выражение в подстановке команд, чтобы сохранить результат в переменной a .
  1. ./expr_example.sh 12
  2. 9
  3. 5 + 4
  4. 5 + 4
  5. 60
  6. 1
  7. 7

Двойные круглые скобки

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

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

Вот пример для иллюстрации:

extension_example.sh
  1. #! / Bin / bash
  2. а = ((4 + 5))
  3. руб.

  4. эхо
  5. долл. США

  6. а = ((3 + 5))
  7. руб.

  8. эхо
  9. долл. США

  10. б = $ ((а + 3))
  11. эхо
  12. $

  13. б = (($ а + 4))
  14. эхо
  15. $

  16. ((b ++))
  17. эхо $ б
  18. ((b + = 3))
  19. эхо $ б
  20. а = ((4 * 5))
  21. эхо
  22. долл. США

Давайте разберемся:

  • Строка 4 — это основной формат.Как видите, мы можем выделить его для удобства чтения без кавычек.
  • Строка 7 — Как видите, она работает точно так же, если убрать интервал.
  • Строка 10 — Мы можем включать переменные без предшествующего знака $.
  • Строка 13 — При желании переменные могут быть добавлены со знаком $.
  • Строка 16 — это немного другая форма. Здесь значение переменной b увеличивается на 1 (с использованием того же механизма, что и проиллюстрированный под let ).Когда мы это делаем, нам не нужен знак $ перед скобками.
  • Строка 19 — это немного другая форма из предыдущего примера. Здесь значение переменной b увеличивается на 3. Это сокращение для b = b + 3 .
  • Строка 19 — В отличие от других методов, когда мы выполняем умножение, нам не нужно экранировать знак * .
  1. ./expansion_example.sh
  2. 9
  3. 8
  4. 11
  5. 12
  6. 13
  7. 16
  8. 20

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

Длина переменной

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

$ {# переменная}

Вот пример:

length_example.ш
  1. #! / Bin / bash
  2. a = «Привет, мир»
  3. эхо $ {# a}
  4. b = 4953
  5. эхо $ {# b}

Сводка

let выражение
Сделайте переменную равной выражению.
выражение expr
распечатать результат выражения.
$ ((выражение))
Вернуть результат выражения.
$ {# var}
Вернуть длину переменной var.
Арифметика
Существует несколько способов выполнения арифметических операций в сценариях Bash. Двойные круглые скобки — предпочтительный метод.
Форматирование
При выполнении арифметических операций часто важно наличие или отсутствие пробелов (и кавычек).

Мероприятия

Давайте погрузимся в арифметику.

  • Создайте простой сценарий, который примет два аргумента командной строки, а затем умножит их вместе, используя каждый из методов, описанных выше.
  • Напишите сценарий Bash, который будет печатать завтрашнюю дату. (Подсказка: используйте команду date )
  • Помните, когда мы смотрели на переменные, мы обнаружили, что $ RANDOM возвращает случайное число. Это число от 0 до 32767, что не всегда является наиболее полезным. Давайте напишем сценарий, который будет использовать эту переменную и некоторую арифметику (подсказка: играть с модулем), чтобы возвращать случайное число от 0 до 100.
  • А теперь поиграем с предыдущим скриптом. Измените его так, чтобы вы могли указать в качестве аргумента командной строки верхний предел случайного числа. Можете ли вы сделать так, чтобы можно было указать и нижний предел? например. если бы я запустил ./random.sh 10 45, он вернул бы только случайные числа от 10 до 45.

.

Арифметические операторы Bash

Арифметические операторы Bash

Арифметические операторы Bash — Bash Shell поддерживает 11 арифметических операторов.

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

Оператор Описание Примеры / варианты
+ Сложение — Вычисляет сложение двух чисел, представленных в качестве операндов. $ ((15 + 8)) результат `expr 15 + 8`: 23
Вычитание — Вычисляет вычитание второго операнда из первого. $ ((15-8)) `expr 15-8` результат: 7
* Умножение — Вычисляет произведение двух предоставленных операндов. $ ((15 * 8)) `expr 15 * 8` результат: 120
/ Деление — вычисляет деление первого операнда на второй операнд и возвращает частное. $ ((15/8)) `expr 15 / 8` результат: 1
** Возведение в степень — Вычисляет результат второго операнда, возведенного в степень первого операнда. $ ((15 ** 8)) ʻexpr 15 ** 8` результат: 2562890625
% Modulo — вычисляет напоминание, когда первый операнд делится на второй операнд. $ ((15% 8)) ʻexpr 15% 8` результат: 7
+ = Увеличение переменной на константу — Оператор увеличивает значение первого операнда на предоставленную константу.

x = 2

let «x + = 5»

echo $ x

((x + = 5)) результат: 7

— = Уменьшение переменной по константе — Оператор уменьшает значение первого операнда на предоставленную константу.

x = 2

let «x — = 5»

echo $ x

((x — = 5)) результат: -3

* = Умножить переменную на константу — Оператор умножает значение первого операнда на предоставленную константу.

x = 2

let «x * = 5»

echo $ x

((x * = 5)) результат: 10

/ = Разделить переменную на константу — оператор вычисляет (переменную / константу) и сохраняет результат обратно в переменную.

x = 12

let «x / = 5»

echo $ x

((x / = 5)) результат: 2

% = Остаток от деления переменной на константу — оператор вычисляет (переменная% константа) и сохраняет результат обратно в переменную.

x = 13

let «x% = 5»

echo $ x

((x% = 5)) результат: 3

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

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

Двойная скобка

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

bash-arithmetic-operators-example

#! / Bin / bash

x = 10

y = 3

echo $ ((x + y)) # сложение

echo $ (($ x + $ y)) # также действует

echo $ ((x — y)) # вычитание

echo $ (($ x — $ y)) # также действует

echo $ ((x * y)) # умножение

echo $ (($ x * $ y)) # также действительно

echo $ ((x / y)) # деление

echo $ (($ x / $ y)) # также действует

echo $ ((x ** y)) # возведение в степень

echo $ (($ x ** $ y)) # также действует

echo $ (( x% y)) # модульное деление

echo $ (($ x% $ y)) # также действует

((x + = 4)) # инкремент переменной на константу

echo $ x

((X — = 4)) # уменьшение переменной на константу

echo $ x

((x * = 4)) # умножить переменную на константу

echo $ x

((x / = 4)) # разделить переменную на константу

echo $ x

((X% = 4)) # Остаток от деления переменной на константу

echo $ x

let конструкция

Команда let используется для выполнения арифметических операций.Ниже приведен пример:

bash-arithmetic-operators-example

#! / Bin / bash

x = 10

y = 3

z = 0

let «z = $ ((x + y))» # сложение

let z = $ ((x + y)) # также допустимо без двойных кавычек, если в выражении нет пробелов

echo $ z

let «z = $ ((x — y)) «# вычитание

let z = $ ((xy))

echo $ z

let» z = $ ((x * y)) «# умножение

let z = $ ((x * y))

echo $ z

let «z = $ ((x / y))» # деление

let z = $ ((x / y))

echo $ z

let «z = $ ((x ** y))» # возведение в степень

let z = $ ((x ** y))

echo $ z

let «z = $ ((x% y)) «# модульное деление

let z = $ ((x% y))

echo $ z

let «x + = 4» # увеличить переменную на константу

echo $ x

let «x — = 4» # уменьшить переменную на константу

echo $ x

let «x * = 4» # умножить переменная на константу

echo $ x

let «x / = 4» # разделить переменную на константу

echo $ x

let «x% = 4» # Остаток от деления переменной на константу

echo $ x

Обратные кавычки

Арифметическое расширение может быть выполнено с помощью обратных кавычек и expr (универсальный вычислитель выражений).Ниже приведен пример:

a = 5

b = 7

c = ʻexpr $ a + $ b`

echo $ c # 12

Заключение:

В этом руководстве по Bash мы изучили арифметические операторы, поддерживаемые Bash Shell, с примерами для каждого из них.

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

2021 © Все права защищены. Карта сайта