Как запустить файл bash. Введение в bash. Подробнее о симлинках

Любой начинающий системный администратор Linux рано или поздно сталкивается с таким понятием, как “скрипт ”, будь то один из загрузочных скриптов вроде /etc/rc.d/rc или написанный разработчиком ПО скрипт конфигурирования configure . В данной статье я постараюсь показать, что написание скриптов на shell не является чем-то из ряда вон выходящим и вполне под силу даже новичку в мире Linux.

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

Одной из задач системного администрирования является резервное копирование важной информации. Поэтому давайте рассмотрим пример скрипта, реализующего back-up информации.

Начало начал

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

Echo This is just example
whoami
uname -a

Эти команды объединены в одном файле. Но shell должен знать, что он должен этот файл обработать, а не просто прочесть его содержимое. Для этого служит специальная конструкция: #!

Эта конструкция называется «sha-bang ». Вообще-то, # задает комментарий, но в данном случает sha-bang означает, что после нее пойдет путь к обработчику скрипта. Напрмер:

#!/bin/bash
#!/bin/sh
#!/usr/bin/perl

Мы остановимся на Bash, Bourne-Again shell. Это shell устанавливается по умолчанию практически во всех Linux-системах, и /bin/sh ссылается на него. Об окончании скрипта говорит служебное слово exit.

Вооружившись этими знаниями, напишем наш первый скрипт:

#!/bin/bash
echo Простой скрипт # Команда echo выводит сообщение на экран
echo Вы:
whoami # whoami показывает имя зарегистрированного пользователя
echo Ваша система стартовала
uptime # uptime показывает время включения машины
echo Сегодня
date # date показывает текущую дату и время
echo Пока все
exit

Сохраним этот файл под именем tutor1.sh. Выполним команду чтобы сделать скрипт исполняемым.

Chmod +rx tutor1.sh

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

Voland@superstar:~/Doc/Open Source$ ./tutor1.sh
Простой скрипт
Вы:
voland
Ваша система стартовала
14:38:46 up 1:48, 2 users, load average: 0.47, 0.43, 0.41
Сегодня
Вск Фев 26 14:38:46 MSK 2006
Пока все

Переходим к более серьезному.

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

Перво-наперво, необходимо определить - резервную копию чего мы будем делать. Поэтому наш скрипт должен уметь работать с командной строкой. Аргументы командной строки задаются после имени скрипта через пробел: somescript arg1 arg2 arg3. Скрипт воспринимает аргументы по номерам их следования, поэтому мы будем использовать конструкции вида $номер_аргумента, т.е. $1, $2, $3. $ - это символ подстановки, который нам понадобится и при работе с переменными. Переменные в скрипте задаются в виде имя_переменной=значение. Мы будем использовать переменные MAXPARAMS для определения максимального количества параметров командной строки, BACKUPFILE для задания имени архива, BACKUPDIR для папки, резервную копию которой мы будем делать и ARCHIVEDIR для папки, куды мы поместим архив. Самой главной частью скрипта будут команды поиска и архивации всех найденных файлов и папок в указанной:

Find . -type f -print0 | xargs -0 tar rvf "$archive.tar" > /dev/null
gzip $archive.tar

Давайте разберемся, что же эти команды делают. find ищет в текущем каталоге (об этом говорит первый аргумент ".") все файлы и выдает полный путь к ним (print0). Эти пути перенаправляюся команде tar, которая собирает все файлы в один. Затем командой gzip мы архивируем получившийся tar-файл. Команда > /dev/null удобна, если вы архивируете большое количество файлов. В этом случае их имена и полный путь к ним не выводятся на консоль.

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

Например, эта конструкция

If [ $# -lt "$MAXPARAMS" ];
then
echo

echo
exit 0
fi

подскажет, что пользователь указал недостаточное количество аргументов командной строки. If [условие]...fi задает условную конструкцию. $# -lt "$MAXPARAMS" проверяет введенное количество параметров и если это число окажется меньше MAXPARAMS, то пользователю будет выдано сообщение об ошибочном вводе. Exit 0 заставит скрипт прекратить работу без указания кода ошибки. Аналогично проверяется превышение допустимого числа параметров, только вместо ls (less then - меньше, чем), необходимо указать gt (greater then - больше, чем). Теперь, когда основные моменты скрипта разъяснены, можно переходить к полной его версии:

#!/bin/bash
# Описание:
#+ Делает резервную копию всех файлов в указанной директории
#+ в "tarball" (архив tar.gz).
#+ Использование:
#+ sh backup.sh имя_архива папка-источник папка-назначение
#+

# Максимальное количество параметров командной строки
MAXPARAMS=3

if [ $# -lt "$MAXPARAMS" ];
then
echo
echo "Использование: sh `basename $0` имя_архива папка-источник папка-назначение"
echo
exit 0
fi

if [ $# -gt "$MAXPARAMS" ];
then
echo
echo "Для этого скрипта нужно только $MAXPARAMS аргументов командной строки!"
echo
exit 0
fi

# Переменные, которые мы используем в скрипте
BACKUPFILE=$1-backup-$(date +%m-%d-%Y)
archive=$BACKUPFILE
BACKUPDIR=$2
ARCHIVEDIR=$3

# Проверяем, есть ли папка-источник и папка-назначение
if [ ! -e $BACKUPDIR ];
then
echo
echo "\"$BACKUPDIR\" не существует!"
echo
exit 0
fi

if [ ! -e $ARCHIVEDIR ];
then
echo
echo "\"$ARCHIVEDIR\" не существует, создаем..."
mkdir $ARCHIVEDIR
echo "Готово."
fi

# Проверяем, есть ли архивы в источнике и назначении.
cd $ARCHIVEDIR
if [ -e $archive.tar.gz ];
then rm $archive.tar.gz
fi

cd $BACKUPDIR
if [ -e $archive.tar.gz ];
then rm $archive.tar.gz
fi

# Главная часть скрипта...
echo "Делаем резервную копию \"$BACKUPDIR\" в файл \"$archive.tar.gz\"..."
find . -type f -print0 | xargs -0 tar rvf "$archive.tar" > /dev/null
gzip $archive.tar
echo "\"$BACKUPDIR\" была успешно заархивирована в файл \"$archive.tar.gz\"."

# Перемещаем архив в папку ARCHIVEDIR
echo "Перемещаем архив \"$archive.tar.gz\" в папку \"$ARCHIVEDIR\"."
mv $archive.tar.gz $ARCHIVEDIR/$archive.tar.gz
echo "Готово."

Надеюсь, основные моменты я прокомментировал достаточно подробно. Если у вас возникли какие-либо вопросы, то вы можете связаться со мной по адресу [email protected] Рекомендую также замечательную книгу Advanced Bash-Scripting Guide Менделя Купера (Mendel Cooper), которая очень помогла мне в свое время, когда я только знакомился со скриптами. Удачного программирования.

P.S. Большое спасибо mar за ее замечания и советы.

Общие переменные окружения
PATH - Устанавливает путь поиска для любой исполняемый командой. Аналогично переменной PATH в MSDOS.
HOME - домашний каталог пользователя.
MAIL - Содержит путь к месту хранрения почты пользователя.
IFS - Содержит строку символов, которые используются как разделители в командной строке. Строка, как правило, состоит из пробела, табуляции и символы новой строки. Чтобы увидеть их придется сделать восьмеричный дамп следующим образом:

$ echo $IFS | od -bc

PS1 и PS2 - Основное и вторичное приглашение в bash. PS1 устанавливается $ по умолчанию и PS2 установлен в ">". Чтобы увидеть вторичное, просто запустите команду:

$ $ ls |

И нажмите ввод.

USER - имя пользователя для входа.
TERM - обозначает тип терминала который используется. Должно быть настроены правильно для редакторов типа vi для правильной работаты.
SHELL - определяет тип оболочки, которую видит пользовательпри входе в систему.
Примечание: Чтобы узнать какие значения имеют проведенные выше переменные окружения, выполните команду echo c именем переменной начинающиееся с $. Например:

$ echo $USER
ravi

Получаем значение хранящееся в переменной USER.

Некоторые bash shell scripting правила
1) В первой строке вашего скрипта должено быть

#!/bin/bash

То есть сначала #, затем!, затем путь до оболочки. Эта линия позволяет узнать расположение файла оболочки.

2) Перед выполнением скрипта, вы должны сделать скрипт исполняемым. Делается это следующей командой:

$ chmod ugo+x your_shell_script.sh

3) Обычно скрипт имеет расширение.sh. Это позволяет пользователю понять, что файл является скриптом.

Условные выражения
Выражение "if"


if condition_is_true
then
execute commands
else
execute commands
fi

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


if condition_is_true
then
execute commands
elif another_condition_is_true
then
execute commands
else
execute commands
fi


if grep "linuxhelp" thisfile.html
then
echo "Found the word in the file"
else
echo "Sorry no luck!"
fi

if дополняется - test Тест оценит выражение справа, и возвращает либо верно или неверно. Для этого используется следующие операторы:

Операторы сравнения

-eq Равно
-le Меньше или равно

Тест файлов ж-файл р-файл ж-файл - х файл - д файл ы-файл True если файл существует и имеет размер больше чем ноль.

-f file True если file существует и является обычным файлом
-r file True если file существует и доступен для чтения
-w file True если file существует и доступен на запись
-x file True если file существует и является исполняемым
-d file True если file существует и является каталогом
-s file True если файл существует и имеет размер больше
чем ноль.

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

-n str True, если строка str не равна null
-z str True, если строка str равна null
str1 == str2 True если обе строки равны
str1 != str2 True если строки не равны
str True, если строке str присвлено значение
и не равно null

Тест также позволяет проверять более одного выражения в одной строке.

-a Аналогично AND
-o Аналогично OR

Test $d -eq 25 ; echo $d

Что означает, если значение в переменной d равено 25, в выводим значение.

Test $s -lt 50; do_something if [ $d -eq 25 ]
then
echo $d
fi

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


if [ $str1 == $str2 ]
then
do something
fi

if [ -n "$str1" -a -n "$str2" ]
then
echo "Both $str1 and $str2 are not null"
fi

Если обе строки не являются равными null затем выполняем команду echo. Несколько вещей, которые нужно помнить при использовании test Если вы используете квадратные скобки , вместо test, то необходимо вставить пробел после [ и перед ]. Примечание: test проверяет только целые значения. Дробные просто усекаются. Не используйте маски для тестирования равенства строки.

Выражение case Case является вторым условным выражением поддерживаемым оболочкой. Синтаксис:

Case expression in
pattern1) execute commands ;;
pattern2) execute commands ;;
...
esac

Ключевыми словами здесь являются case и esac. ";;" используется в качестве окончания вариант. Также использует ")", чтобы отделить шаблон от действий. Пример:

...
echo "Enter your option: "
read i;

case $i in
1) ls -l ;;
2) ps -aux ;;
3) date ;;
4) who ;;
5) exit
esac

Примечание: В последнем случае;; не требуется, но если хотите, то можете их поставить. Вот еще один пример:

case `date |cut -d" " -f1` in
Mon) commands ;;
Tue) commands ;;
Wed) commands ;;
...
esac

Case также поддерживает в выражении более чем один шаблон в каждом варианте. Вы также можете использовать wild-cards для сопоставления шаблонов.

...
echo "Do you wish to continue? (y/n)"
read ans

case $ans in
Y|y ) ;;
) ;;
N|n ) exit ;;
) exit ;;
* ) echo "Invalid command"
esac

В приведенном случае, если вы введете Yes, YES, yEs и любую их комбинацию, то значение будет найдено.

Циклы
Цикл while
Синтаксис:

while condition_is_true
do
execute commands
done
while [ $num -gt 100 ]
do
sleep 5
done

while:
do
execute some commands
done

Выше код реализует бесконечный цикл. Вы также можете написать "в то время как справедливо" вместо "а:". Здесь я хотел бы ввести два ключевых слова в связи с looping условные. Они перерыв и продолжить. Перерыв - Это ключевое слово вызывает контроль вырваться из петли. далее - Это ключевое слово будет приостанавливать исполнение всех заявлений после него и выключатели контроль верхней части петли для следующей итерации.
Цикл until
Цикл выполняется пока выражение не станет ложным. Синтаксис:

until false
do
execute commands
done
...
until [ -r myfile ]
do
sleep 5
done

Вышеуказанный код выполняется повторно до тех пор, пока файл myfile может быть прочитан.
Цикл for
Синтаксис:

for variable in list
do
execute commands
done
...
for x in 1 2 3 4 5
do
echo "The value of x is $x";
done

Выводистя пять чиесл от 1 до 5. Вот еще один пример:

for var in $PATH $MAIL $HOME
do
echo $var
done

Предположим, у вас есть каталог с файлами java и вы хотите скомпилировать их. Вы можете написать скрипт, например такой:

...
for file in *.java
do
javac $file
done

Примечание: Вы можете использовать wild-card выражения в ваших скриптах.

Несколько специальных символов и их значения w.r.t shell scripts

$* - Это означает, что все параметры передаются скрипт
на момент его исполнения.. Что включает в себя $ 1, $ 2
и так далее.
$0 - Имя выполняемого скрипта.
$# - Количество аргументов, указанных в командной строке.
$? - Выходной статус последней команды.

Выше приведенные символы известны, как позиционные параметры (positional parameters). Позвольте мне объяснить позиционные параметры с помощью примера. Предположим у меня есть скрипт с названием my_script.sh. Теперь выполним этот скрипт в командной строке следующее:

$ ./my_script.sh linux is a robust OS

Как вы можете видеть выше, я указал 5 параметров скрипта. В соответствии с этим сценарием, значения позиционных параметров состоят в следующем: $ * - "linux "," является "," "," надежных "," OS". $ 0 - my_script.sh - имя скрипт время казнен. $ # - $ $ - $ 1 - $ 2 - $* - будет содержать значения "linux","is","a","robust","OS".
$0 - будет содержать значение my_script.sh - имя скрипта во время исполнения.
$# - содержит значения 5 - общее количество параметров.br>

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

$1 - содержит значения "linux"
$2 - содержит значение "is"

$ set `date`
$ echo $1
$ echo $*
$ echo $#
$ echo $2

shift Пример:

$ set `date`
$ echo $1 $2 $3
$ shift
$ echo $1 $2 $3
$ shift
$ echo $1 $2 $3

Чтобы узнать ID процесса текущего оболочки, попробуйте следующее:

$ echo $$
2667

Для проверки, что это одно и то же значение, выполните следующие команды:

$ ps -f |grep bash

Оператор read
Сделайте ваш скрипт интерактивным. read позволит пользователю ввести значения, пока скрипт выполняется. Когда программа ждет ввода, она останавливается. Введенный через клавиатуру id считывается, и выполнение программы продолжается.
Например:

#!/bin/sh
echo "Enter your name: "
read name
echo "Hello $name , Have a nice day."

Выходной статус последней команды

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

Обновлено: 07 октября 2009 Просмотров: 10041

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

Итак, приступим к изучению командной оболочки Bash.
Давайте начнем наше обучение с простого скрипта "Hello World".

1. Bash-скрипт Hello World
Для начала необходимо выяснить, где находится транслятор. Для этого введите следующую команду:
$ which bash
Откройте ваш любимый текстовый редактор и создайте файл под названием hello_world.sh. В этом файле сохраните следующие строки:
#!/bin/bash # объявите переменную типа STRING STRING="Hello World" #выведите переменную на экран echo $STRING
Примечание. Каждый bash-скрипт в этом тьюториале начинается с последовательности знаков "#!", который не интерпретируется как комментарий!
Перейдите в директорию, в которую вы сохранили файл hello_world.sh и сделайте этот файл исполняемым:
$ chmod +x hello_world.sh
Ну, теперь вы полностью готовы создать свой первый bash-скрипт:
./hello_world.sh

2. Простой bash-скрипт для резервного копирования:
#!/bin/bash tar -czf myhome_directory.tar.gz /home/linuxconfig

3. Переменные
В этом примере мы объявим простую bash-переменную и выведем ее на экран с помощью команды echo.
#!/bin/bash STRING="HELLO WORLD!!!" echo $STRING
Скрипт для резервной копии и переменных:
#!/bin/bash OF=myhome_directory_$(date +%Y%m%d).tar.gz tar -czf $OF /home/linuxconfig

3.1. Глобальные и локальные переменные
#!/bin/bash #Объявление глобальной переменной #Эта переменная глобальна и может быть использована в любом месте скрипта VAR="global variable" function bash { #Объявление локальной переменной #Эта переменная локальна и может быть использована только в этой функции bash local VAR="local variable" echo $VAR } echo $VAR bash # Обратите внимание, глобальная переменная не изменилась # "local" это зарезервированное слово в bash echo $VAR

4. Передача аргументов в bash-скрипт
#!/bin/bash # используйте ранее определенные переменные для доступа к переданным аргументам to access passed arguments # аргументы на экран echo $1 $2 $3 " -> echo $1 $2 $3" # Мы можем сохранить аргументы из командной строки bash в специальный массив args=("$@") # echo arguments to the shell echo ${args} ${args} ${args} " -> args=("$@"); echo ${args} ${args} ${args}" # используйте $@ для вывода сразу всех аргументов echo $@ " -> echo $@" # используйте переменную $# для вывода # числа переданных в bash-скрипт переменных echo Number of arguments passed: $# " -> echo Number of arguments passed: $#" /arguments.sh Bash Scripting Tutorial

5. Исполнение команд shell с помощью bash
#!/bin/bash # используйте обратные кавычки " ` ` " для исполнения команд shell echo `uname -o` # исполнение bash-команд вызывается без кавычек echo uname -o

6. Чтение введенных пользователем данных
#!/bin/bash echo -e "Hi, please type the word: \c " read word echo "The word you entered is: $word" echo -e "Can you please enter two words? " read word1 word2 echo "Here is your input: \"$word1\" \"$word2\"" echo -e "How do you feel about bash scripting? " # команда read сохраняет ответы в дефолтную переменную$REPLY read echo "You said $REPLY, I"m glad to hear that! " echo -e "What are your favorite colours ? " # -a позволяет команде read сохранять несколько значений в массив read -a colours echo "My favorite colours are also ${colours}, ${colours} and ${colours}:-)"

7. Bash-команда trap
#!/bin/bash # команда trap trap bashtrap INT # bash-команда очистки экрана clear; # bash функция trap исполняется, когда нажимается CTRL-C # bash выводит сообщение => Executing bash trap ! bashtrap() { echo "CTRL+C Detected !...executing bash trap !" } # для значений от 1/10 до 10/10 for a in `seq 1 10`; do echo "$a/10 to Exit." sleep 1; done echo "Exit Bash Trap Example!!!"

8. Массивы
8.1. Объявление простого bash-массива
#!/bin/bash # объявление массива из 3 элементов ARRAY=("Debian Linux" "Redhat Linux" "Ubuntu Linux") # получение числа элементов массива ELEMENTS=${#ARRAY[@]} # вывод каждого элемента массива # при заданном диапазоне номеров элементов for ((i=0;i

8.2. Импорт файла в массив bash
#!/bin/bash # объявление массива declare -a ARRAY # вывести filedescriptor 10 в stdin exec 10

Исполнение bash-скрипта с выводом в файл execution with an output:
linuxconfig.org $ cat bash.txt Bash Scripting Tutorial Guide linuxconfig.org $ ./bash-script.sh bash.txt Number of elements: 4 Bash Scripting Tutorial Guide linuxconfig.org $

9. Bash-скрипты с if / else / fi
9.1. Простое Bash-выражение с if/else
Обратите внимание на пробелы в скобках [ и ]! Без этих пробелов, скрипт работать не будет.
#!/bin/bash directory="./BashScripting" # bash проверка существования директории if [ -d $directory ]; then echo "Directory exists" else echo "Directory does not exists" fi

9.2. Встроенный if/else
#!/bin/bash # объявление выбранной переменной и присваивание ей значения 4 choice=4 # Вывод на stdout echo "1. Bash" echo "2. Scripting" echo "3. Tutorial" echo -n "Please choose a word ? " # Повторение цикла, пока переменная равна 4 # bash цикл while while [ $choice -eq 4 ]; do # чтение введенного значения read choice # bash nested if/else if [ $choice -eq 1 ] ; then echo "You have chosen word: Bash" else if [ $choice -eq 2 ] ; then echo "You have chosen word: Scripting" else if [ $choice -eq 3 ] ; then echo "You have chosen word: Tutorial" else echo "Please make a choice between 1-3 !" echo "1. Bash" echo "2. Scripting" echo "3. Tutorial" echo -n "Please choose a word ? " choice=4 fi fi fi done

10. Bash сравнения
10.1. Арифметические сравнения
-lt -gt >-le -ge >=
-eq ==
-ne !=

#!/bin/bash # объявление целочисленных переменных NUM1=2 NUM2=2 if [ $NUM1 -eq $NUM2 ]; then echo "Both Values are equal" else echo "Values are NOT equal" fi

#!/bin/bash # объявление целочисленных переменных NUM1=2 NUM2=1 if [ $NUM1 -eq $NUM2 ]; then echo "Both Values are equal" else echo "Values are NOT equal" fi

#!/bin/bash # объявление целочисленных переменных NUM1=2 NUM2=1 if [ $NUM1 -eq $NUM2 ]; then echo "Both Values are equal" elif [ $NUM1 -gt $NUM2 ]; then echo "NUM1 is greater then NUM2" else echo "NUM2 is greater then NUM1" fi

10.2. Сравнение строк
= equal
!= not equal
> greater then
-n s1 string s1 is not empty
-z s1 string s1 is empty

#!/bin/bash #Объявление строки S1 S1="Bash" #Объявление строки S2 S2="Scripting" if [ $S1 = $S2 ]; then echo "Both Strings are equal" else echo "Strings are NOT equal" fi

#!/bin/bash #Объявление строки S1 S1="Bash" #Объявление строки S2 S2="Bash" if [ $S1 = $S2 ]; then echo "Both Strings are equal" else echo "Strings are NOT equal" fi

11. Bash проверка файла
-b filename - блокирование файла
-c filename - файл содержит спец. символы
-d directoryname - проверка существования директории
-e filename - проверка существования файла
-f filename - проверка существования НЕдиректории
-G filename Check if file exists and is owned by effective group ID.
-g filename true if file exists and is set-group-id.
-k filename Sticky bit
-L filename Symbolic link
-O filename True if file exists and is owned by the effective user id.
-r filename - проверка доступности файла
-S filename Check if file is socket
-s filename - проверка того, что размер файла больше нуля
-u filename Check if file set-ser-id bit is set
-w filename - проверка перезаписываемости файла
-x filename - проверка исполняемости файла
#!/bin/bash file="./file" if [ -e $file ]; then echo "File exists" else echo "File does not exists" fi
Аналогично для проверки существования файла можно использоватьe цикл while. Этот скрипт не будет работать, пока файл существует. Обратите внимание на bash оператор отрицания "!", который отрицает функцию -e.
#!/bin/bash while [ ! -e myfile ]; do # Не реагировать, пока файл создан и существует sleep 1 done

12. Цикл
12.1. Bash команда зацикливания
#!/bin/bash # bash цикл for f in $(ls /var/); do echo $f done
Запуск цикла из командной строки bash:
$ for f in $(ls /var/); do echo $f; done

12.2. Bash цикл while
#!/bin/bash COUNT=6 # bash цикл while while [ $COUNT -gt 0 ]; do echo Value of count is: $COUNT let COUNT=COUNT-1 done

12.3. Bash цикл until
#!/bin/bash COUNT=0 # bash цикл until until [ $COUNT -gt 5 ]; do echo Value of count is: $COUNT let COUNT=COUNT+1 done

12.4. Контролирование цикла bash
Ниже представлен пример цикла while, контролируемого стандартным вводом. Bash цикл while работает, пока существует переход от STDOUT к STDIN и к команде read.
#!/bin/bash # этот bash скрипт найдет и заменит пробелы # в именах файлов DIR="." # контролирование цикла с помощью bash команды read путем перенаправления STDOUT к # STDIN в цикле while # команда find не будет отбрасывать имена файлов, содержащие пробелы find $DIR -type f | while read file; do # использование POSIX class [:space:] для поиска пробела в имени файла if [[ "$file" = *[[:space:]]* ]]; then # замена пробела символом "_" и, следовательно, переименование файла mv "$file" `echo $file | tr " " "_"` fi; # конец цикла while done

13. Функции Bash
#!/bin/bash # функции Bash могут объявляться в любом порядке function function_B { echo Function B. } function function_A { echo $1 } function function_D { echo Function D. } function function_C { echo $1 } # вызов функций # передача параметра функции А function_A "Function A." function_B # передача параметра функции С function_C "Function C." function_D

14. Bash выделение
#!/bin/bash PS3="Choose one word: " # bash select select word in "linux" "bash" "scripting" "tutorial" do echo "The word you have selected is: $word" # остановка цикла, иначе он станет бесконечным break done exit 0

15. Переключатель
#!/bin/bash echo "What is your preferred programming / scripting language" echo "1) bash" echo "2) perl" echo "3) python" echo "4) c++" echo "5) I do not know !" read case; # структура простого bash условия # обратите внимание: в этом случае $case -это переменная, которая не обязана так называться # здесь она названа так для примера case $case in 1) echo "You selected bash";; 2) echo "You selected perl";; 3) echo "You selected python";; 4) echo "You selected c++";; 5) exit esac

16. Кавычки в Bash
Кавычки являются важным элементом языка bash и bash скриптов. Ниже вы найдете некоторые основы использования кавычек в bash.
16.1. Экранирование специальных символов
Перед тем, как мы приступим к использованию кавычек, нам необходимо узнать, как экранировать специальные символы. Эта процедура позволит bash напрямую распознать значение этих символов. Для этого нам нужно использовать обратный слеш "\". Например:
#!/bin/bash # объявление bash переменной типа string BASH_VAR="Bash Script" # вывод переменной BASH_VAR echo $BASH_VAR # если спецсимвол "$" экранирован символом "\", он может быть напрямую распознан echo \$BASH_VAR # у обратного слеша также есть специальное значение, и оно может быть раскрыто с помощью еще одного слеша "\" echo "\\"

16.2. Одинарные кавычки
Одинарные кавычки в bash экранируют значение всех специальных символов. Таким образом, специальные символы будут распознаны буквально. При этом нельзя использовать одинарную кавычку внутри двух дургих таких же кавычек, даже если какая-то из них экранирована обратным слешем.
#!/bin/bash # объявление bash переменной типа string BASH_VAR="Bash Script" # вывод переменной BASH_VAR echo $BASH_VAR # значение спец. символов в bash экранируется при использовании одинарных кавычек echo "$BASH_VAR "$BASH_VAR""

16.3. Двойные кавычки
Двойные кавычки используются в bash для экранирования всех специальных символов, кроме "$", "\" и "`". Все остальные спец. символы будут распознаваться буквально. В отличие от предыдущего пункта, внутри двойных кавычек можно использовать одинарную. Если между двойными кавычками нужно использовать еще одну двойную кавычку, можно заставить bash распознать их буквально, используя обратный слеш "\". Например:
#!/bin/bash # объявление bash переменной типа string BASH_VAR="Bash Script" # echo variable BASH_VAR echo $BASH_VAR # спец. символ и его значение экранируется # при использовании двойных кавычек вместно "$", "\" и "`" echo "It"s $BASH_VAR and \"$BASH_VAR\" using backticks: `date`"

16.4. Bash экранирование ANSI-C
В bash существует также еще один вид экранирования - ANSI-C. При использовании этого типа экранирования, символы, обозначенные обратным слешем "\" получают специальное значение в соответствии со стандартом ANSI-C.
\a alert (bell)
\b backspace
\e an escape character
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\` single quote
\nnn octal value of characters (see )
\xnn hexadecimal value of characters (see )

Обозначение ansi-c bash-экранирования: $"" . Пример:
#!/bin/bash # для примера мы использовали \n для новой строки, \x40 для шестнадцатеричного значения @ # и \56 для восьмеричного значения. echo $"web: www.linuxconfig.org\nemail: web\x40linuxconfig\56org"

17. Арифметические операции
17.1. Пример сложения с помощью bash
#!/bin/bash let RESULT1=$1+$2 echo $1+$2=$RESULT1 " -> # let RESULT1=$1+$2" declare -i RESULT2 RESULT2=$1+$2 echo $1+$2=$RESULT2 " -> # declare -i RESULT2; RESULT2=$1+$2" echo $1+$2=$(($1 + $2)) " -> # $(($1 + $2))"

17.2. Арифметика в bash
#!/bin/bash echo "### let ###" # bash сложение let ADDITION=3+5 echo "3 + 5 =" $ADDITION # bash вычитание let SUBTRACTION=7-8 echo "7 - 8 =" $SUBTRACTION # bash умножение let MULTIPLICATION=5*8 echo "5 * 8 =" $MULTIPLICATION # bash деление let DIVISION=4/2 echo "4 / 2 =" $DIVISION # bash modulus let MODULUS=9%4 echo "9 % 4 =" $MODULUS # bash возведение в степень let POWEROFTWO=2**2 echo "2 ^ 2 =" $POWEROFTWO echo "### Bash Arithmetic Expansion ###" # существуют два формата обозначения арифметических выражений: $[ выражение ] # и $((выражение #)) - вы можете выбирать тот, который вам нравится больше echo 4 + 5 = $((4 + 5)) echo 7 - 7 = $[ 7 - 7 ] echo 4 x 6 = $((3 * 2)) echo 6 / 3 = $((6 / 3)) echo 8 % 7 = $((8 % 7)) echo 2 ^ 8 = $[ 2 ** 8 ] echo "### Declare ###" echo -e "Please enter two numbers \c" # распознавание ввода read num1 num2 declare -i result result=$num1+$num2 echo "Result is:$result " # bash конвертация бинарного числа 10001 result=2#10001 echo $result # bash конвертация восьмеричного числа 16 result=8#16 echo $result # bash конвертация шестнадцатеричного числа 0xE6A result=16#E6A echo $result

17.3. Округление числа с плавающей точкой
#!/bin/bash # получение числа с плавающей точкой floating_point_number=3.3446 echo $floating_point_number # округление числа с плавающей точкой с помощью bash for bash_rounded_number in $(printf %.0f $floating_point_number); do echo "Rounded number with bash:" $bash_rounded_number done

17.4. Bash вычисления с плавающей точкой
#!/bin/bash # реализация простого калькулятора в linux на bash echo "Enter input:" read userinput # вывод результата с двумя знаками после запятой echo "Result with 2 digits after decimal point:" echo "scale=2; ${userinput}" | bc # вывод результата с десятью знаками после запятой echo "Result with 10 digits after decimal point:" echo "scale=10; ${userinput}" | bc # вывод результата в виде округленного целого числа echo "Result as rounded integer:" echo $userinput | bc

18. Перенаправления
18.1. STDOUT из bash скрипта в STDERR
#!/bin/bash echo "Redirect this STDOUT to STDERR" 1>&2
Для проверки перенаправления STDOUT в STDERR можно перенаправить вывод скрипта в файл:

18.2. STDERR из bash скрипта в STDOUT
#!/bin/bash cat $1 2>&1
Для проверки перенаправления STDERR iв STDOUT можно перенаправить вывод скрипта в файл:

18.3. STDOUT на экран
Простым способом перенаправления STDOUT является простое использование любой команды, поскольку по умолчанию STDOUT автоматически выводится на экран. Но для начала создайте файл "file1":
$ touch file1 $ ls file1 file1
Как вы можете увидеть из вышеприведенного примера, выполнение команды ls вызывает STDOUT, который по умолчанию выводится на экран.

18.4. STDOUT в файл
Чтобы блокировать дефолтное поведение STDOUT, мы можем использовать ">" для перенаправления вывода в файл:
$ ls file1 > STDOUT $ cat STDOUT file1

18.5. STDERR в файл
По умолчанию, STDERR выводится на экран:
$ ls file1 STDOUT $ ls file2 ls: cannot access file2: No such file or directory
В следующем примере перенаправим стандартную ошибку (stderr) в файл, а stdout - как по умолчанию, на экран. Имейте в виду, что STDOUT выводится на экран, а STDERR записывается в файл под наазванием STDERR:
$ ls file1 STDOUT $ ls file1 file2 2> STDERR file1 $ cat STDERR ls: cannot access file2: No such file or directory

18.6. STDOUT в STDERR
Также возможно перенаправление STDOUT и STDERR в один файл. В следующем примере перенаправим STDOUT в тот же дескриптор, что и STDERR. И STDOUT, и STDERR будут перенаправлены в файл "STDERR_STDOUT".
$ ls file1 STDERR STDOUT $ ls file1 file2 2> STDERR_STDOUT 1>&2 $ cat STDERR_STDOUT ls: cannot access file2: No such file or directory file1
Теперь файл STDERR_STDOUT содержит и STDOUT, и STDERR.

18.7. STDERR to STDOUT
Пример выше можно переделать так, чтобы перенаправлять STDERR в тот же дескриптор, что и SDTOUT:
$ ls file1 STDERR STDOUT $ ls file1 file2 > STDERR_STDOUT 2>&1 $ cat STDERR_STDOUT ls: cannot access file2: No such file or directory file1

18.8. STDERR и STDOUT в файл
Оба верхних примера перенаправляли STDOUT и STDERR в файл. Существует и другой способ добиться того же эффекта:
$ ls file1 STDERR STDOUT $ ls file1 file2 &> STDERR_STDOUT $ cat STDERR_STDOUT ls: cannot access file2: No such file or directory file1
or
ls file1 file2 >& STDERR_STDOUT $ cat STDERR_STDOUT ls: cannot access file2: No such file or directory file1

Данная статья является любительским переводом статьи с

Прочитав эту статью, вы узнаете что такое bash (стандартный командный интерпретатор линукс), научитесь обращаться со стандартными командами: ls , cp , mv ... поймете назначение инодов, жестких и символических ссылок и многое другое.

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

Введение в bash

Shell

Если вы используете линукс, то знаете что после логина вас приветствует приглашение командного интерпретатора. Например такое:

\$

Если после логина загружается графическая оболочка, то чтобы добраться до командного интерпретатора нужно запустить эмулятор терминала (gnome-terminal, xfce4-terminal, konsole, xterm, rxvt...) или переключиться на один из виртуальных терминалов нажав Ctrl Alt F1 или Ctrl Alt F2 и т.д.

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

У вас запущен bash?

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

\$ echo \$SHELL /bin/bash

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

\$ bash

Что такое bash

Bash (акроним от "B ourne-a gain SH ell") это стандартный интерпретатор команд на большинстве линукс систем. В его обязанности входит обработка и исполнение команд с помощью которых пользователь управляет компьютером. После того как вы завершили работу, можно завершить процесс командного интерпретатора. После нажатия клавиш Ctrl D , команд exit или logout процесс командного интерпретатора будет завершен и на экране снова появится приглашение ввести имя пользователя и пароль.

Использование "cd"

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

$ cd /

Этой командой мы указали bash-у что хотим переместиться в корневую директорию - / . Все директории в системе организованы в древовидную структуру и / это её начало (или корень). Команда cd служит для изменения текущей рабочей директории.

Пути

Чтобы узнать в каком месте файловой системы в данный момент вы находитесь (текущую рабочую директорию) наберите:

\$ pwd /

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

Абсолютные пути

Вот несколько примеров абсолютных путей

/dev /usr /usr/bin /usr/local/bin

Как вы уже могли заметить, все эти пути объединяет то, что они начинаются с / . Указывая путь /usr/local/bin в качестве аргумента команде cd мы говорим ей перейти в корневую директорию / , затем в директорию usr, потом в local и bin. Абсолютные пути всегда начинаются с /

Относительные пути

Второй вид путей называется относительными. Bash , команда cd и другие команды отсчитывают эти пути относительно текущей директории. Относительные пути никогда не начинаются с / . Например, если мы находимся в /usr

\$ cd /usr

Затем мы можем перейти в /usr/local/bin используя относительный путь

\$ cd local/bin \$ pwd /usr/local/bin

Использование ".."

Относительные пути могут содержать одну или несколько директорий ".." . ".." указывает на родительскую директорию по отношению к нашей рабочей директории. Пример:

\$ pwd /usr/local/bin \$ cd .. \$ pwd /usr/local

Как вы видите, команда cd .. "поднимает нас на уровень выше".

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

\$ pwd /usr/local \$ cd ../share \$ pwd /usr/share

Примеры с использованием относительных путей

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

\$ cd /bin \$ cd ../usr/share/zoneinfo \$ cd /usr/X11R6/bin \$ cd ../lib/X11 \$ cd /usr/bin \$ cd ../bin/../bin

Рабочая директория "."

Перед тем как закончить разговор о команде cd , следует упомянуть еще несколько вещей. Во-первых, существует ещё одна специальная директория "." , которая указывает на текущую директорию. Эта директория используется для запуска исполняемых файлов, находящихся в текущей директории.

\$ ./myprog

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

cd и домашняя директория пользователя

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

\$ cd

Без аргумента cd переместит вас в домашнюю директорию. Для суперпользователя домашней обычно является директория /root, а для обычных пользователей - /home/username/. Но что если мы хотим указать конкретный файл, находящийся в домашней директории. Например, как аргумент к программе "myprog" ? Можно написать:

\$ ./myprog /home/user/myfile.txt

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

\$ ./myprog ~/myfile.txt

~ - специальное имя, указывающее в bash на домашнюю директорию пользователя.

Домашние директории других пользователей

Но что если нам нужно указать файл в домашней директории другого пользователя? Для этого после тильды нужно указать имя этого пользователя. Например, чтобы указать на файл fredsfile.txt находящийся в домашней директории пользователя fred:

\$ ./myprog ~fred/fredsfile.txt

Команды линукс

Введение в ls

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

\$ cd /usr \$ ls X11R6 doc i686-pc-linux-gnu lib man sbin ssl bin gentoo-x86 include libexec portage share tmp distfiles i686-linux info local portage.old src

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

\$ ls -a . bin gentoo-x86 include libexec portage share tmp .. distfiles i686-linux info local portage.old src X11R6 doc i686-pc-linux-gnu lib man sbin ssl

Подробный список директорий

После самой команды ls в качестве ее аргумента можно указать один или более файлов или директорий. Если указать имя файла, то команда ls выведет информацию только об этом файле. А если указать название директории, ls покажет все ее содержимое. Опция "-l" команды ls бывает очень полезной если вы хотите кроме имен файлов узнать более подробную информацию о них (права на файл, имя владельца, время последнего изменения файла и его размер).

В следующем примере показано применение опции "-l" для вывода информации о файлах хранящихся в директории /usr

\$ ls -l /usr drwxr-xr-x 7 root root 168 Nov 24 14:02 X11R6 drwxr-xr-x 2 root root 14576 Dec 27 08:56 bin drwxr-xr-x 2 root root 8856 Dec 26 12:47 distfiles lrwxrwxrwx 1 root root 9 Dec 22 20:57 doc -> share/doc drwxr-xr-x 62 root root 1856 Dec 27 15:54 gentoo-x86 drwxr-xr-x 4 root root 152 Dec 12 23:10 i686-linux drwxr-xr-x 4 root root 96 Nov 24 13:17 i686-pc-linux-gnu drwxr-xr-x 54 root root 5992 Dec 24 22:30 include lrwxrwxrwx 1 root root 10 Dec 22 20:57 info -> share/info drwxr-xr-x 28 root root 13552 Dec 26 00:31 lib drwxr-xr-x 3 root root 72 Nov 25 00:34 libexec drwxr-xr-x 8 root root 240 Dec 22 20:57 local lrwxrwxrwx 1 root root 9 Dec 22 20:57 man -> share/man lrwxrwxrwx 1 root root 11 Dec 8 07:59 portage -> gentoo-x86/ drwxr-xr-x 60 root root 1864 Dec 8 07:55 portage.old drwxr-xr-x 3 root root 3096 Dec 22 20:57 sbin drwxr-xr-x 46 root root 1144 Dec 24 15:32 share drwxr-xr-x 8 root root 328 Dec 26 00:07 src drwxr-xr-x 6 root root 176 Nov 24 14:25 ssl lrwxrwxrwx 1 root root 10 Dec 22 20:57 tmp -> ../var/tmp

В первой колонке показана информация о правах доступа к каждому файлу в списке. (Немного позже я объясню какая буква что обозначает) Следующая колонка показывает количество ссылок на каждый элемент списка. Третья и четвертая колонки - владелец и группа файла соответственно. Пятая колонка - размер. Шестая - время последнего изменения файла ("last modified time" или mtime). Последняя колонка - имя файла или директории (Если это ссылка, то после знака "–> " стоит имя объекта на который она ссылается).

Как посмотреть только директории

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

\$ ls -dl /usr /usr/bin /usr/X11R6/bin ../share drwxr-xr-x 4 root root 96 Dec 18 18:17 ../share drwxr-xr-x 17 root root 576 Dec 24 09:03 /usr drwxr-xr-x 2 root root 3192 Dec 26 12:52 /usr/X11R6/bin drwxr-xr-x 2 root root 14576 Dec 27 08:56 /usr/bin

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

Действие опции "-R" противоположно действию "-d" . Она позволяет выводить информацию о файлах находящихся в директории рекурсивно. Сначала показывается содержимое директории верхнего уровня, потом по очереди содержимое всех поддиректорий и так далее. Вывод этой команды может быть достаточно объемным, поэтому мы не приводим ее пример, но вы можете попробовать сделать это самостоятельно, набрав в командной строке "ls -R " или "ls -Rl ".

И, наконец, опция "-i" используется для вывода инодов каждого объекта файловой системы.

\$ ls -i /usr 1409 X11R6 314258 i686-linux 43090 libexec 13394 sbin 1417 bin 1513 i686-pc-linux-gnu 5120 local 13408 share 8316 distfiles 1517 include 776 man 23779 src 43 doc 1386 info 93892 portage 36737 ssl 70744 gentoo-x86 1585 lib 5132 portage.old 784 tmp

Что такое иноды?

Каждый объект файловой системы (файл, директория...) имеет свой уникальный номер, называемый инодом (inode number). Эта информация может показаться незначительной, но понимание функции инодов поможет вам разобраться во многих операциях над файловой системой. Например, посмотрим на "." и ".." как на ссылки, присутствующие в каждой директории. Чтобы понять что из себя представляет директория ".." , узнаем инод директории /use/local

\$ ls -id /usr/local 5120 /usr/local

Как можем видеть, инод директории /usr/local - 5120. Теперь посмотрим какой инод у директории /usr/local/bin/..:

\$ ls -id /usr/local/bin/.. 5120 /usr/local/bin/..

Получается, что иноды директорий /usr/local и /usr/local/bin/.. совпадают! Это значит, что на инод 5120 ссылаются два имени: /usr/local и /usr/local/bin/.. То есть это два разных имени одной директории. Каждый инод указывает на определенное место на диске.

С каждым инодом может быть связано несколько имен объектов файловой системы. Количество "синонимов" файла (объектов файловой системы, ссылающихся на один инод) показывает число во втором столбце вывода команды "ls -l ".

\$ ls -dl /usr/local drwxr-xr-x 8 root root 240 Dec 22 20:57 /usr/local

На этом примере видно (второй столбец), что на директорию /usr/local ссылаются 8 разных объектов файловой системы. Вот их имена:

/usr/local /usr/local/. /usr/local/bin/.. /usr/local/games/.. /usr/local/lib/.. /usr/local/sbin/.. /usr/local/share/.. /usr/local/src/..

mkdir

Давайте рассмотрим команду mkdir . Она служит для создания новых директорий. В следующем примере демонстрируется создание трех новых директорий (tic, tac, toe) в директории /tmp

\$ cd /tmp $ mkdir tic tac toe

По умолчанию команда mkdir не может создать вложенной структуры директорий. Поэтому, если вам нужно создать несколько вложенных одна в другую директорий (won/der/ful ), то вам придется три раза поочередно вызывать эту команду:

\$ mkdir won/der/ful mkdir: cannot create directory "won/der/ful": No such file or directory \$ mkdir won \$ mkdir won/der \$ mkdir won/der/ful

Упростить эту операцию можно добавив опцию "-p" к команде mkdir. Эта опция позволяет создавать вложенную структуру директорий:

\$ mkdir -p easy/as/pie

Чтобы узнать о возможностях этой утилиты подробнее, прочитайте справку, которая вызывается командой man mkdir . Справки есть практически ко всем командам из этого руководства (например man ls ), кроме cd , т.к. она встроена в bash (для таких команд справка вызывается так: help cd )

touch

Перейдем к изучению команд cp и mv , служащих для копирования, переименования и перемещения файлов и директорий. Но перед этим создадим пустой файл в директории /tmp при помощи команды touch :

\$ cd /tmp \$ touch copyme

Команда touch обновляет время последнего доступа к файлу (шестая колонка вывода команды ls -l ) если он уже существует или создает новый пустой файл, если его ещё нету. После этой операции у нас должен появиться пустой файл /tmp/copyme .

echo

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

\$ echo "firstfile" firstfile

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

\$ echo "firstfile" > copyme

Знак > (больше) указывает командной оболочке что нужно перенаправить вывод команды стоящей слева в файл, имя которого находится справа. Если файла с таким именем не существует, он будет создан автоматически. А если такой файл уже есть, то он будет перезаписан (все его содержимое будет стерто перед записью нашей строки). Команда "ls -l" покажет что размер нашего файла теперь равен 10 байтам - девять байт занимает слово "firstfile" и один байт символ перевода строки.

\$ ls -l copyme -rw-r--r-- 1 root root 10 Dec 28 14:13 copyme

cat и cp

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

\$ cat copyme firstfile

Теперь мы можем приступить к разбору базовой функциональности команды cp . Эта команда принимает два аргумента. Первый - имя уже существующего файла ("copyme"), второй - название новой копии, которую мы хотим сделать ("copiedme").

\$ cp copyme copiedme

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

\$ ls -i copyme copiedme 648284 copiedme 650704 copyme

mv

Теперь применим команду mv чтобы переименовать файл ("copiedme" –> "movedme"). Номер инода после этой операции не меняется, а изменяется только название файла.

\$ mv copiedme movedme \$ ls -i movedme 648284 movedme

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

Команда mv позволяет не только переименовывать файлы, но и перемещать их. Например, чтобы переместить файл /var/tmp/myfile.txt в директорию /home/user нужно дать команду:

\$ mv /var/tmp/myfile.txt /home/user

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

Нужно заметить, существует вероятность, что новый присвоенный номер инода может совпасть со старым, но она чрезвычайно мала.

Чтобы переместить одновременно несколько файлов в одну директорию нужно написать:

\$ mv /var/tmp/myfile1.txt /var/tmp/myfile2.txt /home/user \$ mv -t /home/user /var/tmp/myfile1.txt /var/tmp/myfile2.txt

Если добавить опцию "-v" , на экран будет выведен отчет о проделанной операции:

\$ mv -vt /home/user /var/tmp/myfile1.txt /var/tmp/myfile2.txt "/var/tmp/myfile1.txt" -> "/home/user/myfile1.txt" "/var/tmp/myfile2.txt" -> "/home/user/myfile2.txt"

Создание ссылок и удаление файлов

Жесткие ссылки

Я уже упоминал слово "ссылка" когда говорил о директориях и инодах. На самом деле в линуксе существует два вида ссылок. Первый вид называют жесткими ссылками. Каждый инод может иметь несколько связанных с ним жестких ссылок. Таким образом, получается что файл присутствует в системе под несколькими разными именами. Файл существует до тех пор, пока с его инодом связано хотя бы одно имя. Понятия «жёсткая ссылка на файл» и «имя файла» являются синонимами. Новые жесткие ссылки на файл можно сделать при помощи команды ln

\$ cd /tmp \$ touch firstlink \$ ln firstlink secondlink \$ ls -i firstlink secondlink 15782 firstlink 15782 secondlink

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

Символические ссылки

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

Симлинки создаются командой ln с опцией "-s" :

\$ ln -s secondlink thirdlink \$ ls -l firstlink secondlink thirdlink -rw-rw-r-- 2 agriffis agriffis 0 Dec 31 19:08 firstlink -rw-rw-r-- 2 agriffis agriffis 0 Dec 31 19:08 secondlink lrwxrwxrwx 1 agriffis agriffis 10 Dec 31 19:39 thirdlink -> secondlink

Символическую ссылку можно распознать по выводу команды ls -l : во-первых, в первой колонке у симлинков стоит буква "l" (первая буква английского слова link–ссылка), во-вторых, размер симлинка равен количеству букв в имени файла на который он ссылается ("secondlink" в нашем случае), в-третьих, последняя колонка помимо имени ссылки содержит имя файла на который она ссылается после знака –>

Подробнее о симлинках

Рассмотрим ситуацию, когда мы хотим сделать симлинк который указывает на /usr/local/bin и находится в директории /tmp/. Мы можем написать:

\$ ln -s /usr/local/bin bin1 \$ ls -l bin1 lrwxrwxrwx 1 root root 14 Jan 1 15:42 bin1 -> /usr/local/bin \$ ln -s ../usr/local/bin bin2 \$ ls -l bin2 lrwxrwxrwx 1 root root 16 Jan 1 15:43 bin2 -> ../usr/local/bin \$ ls -l bin2 lrwxrwxrwx 1 root root 16 Jan 1 15:43 bin2 -> ../usr/local/bin \$ mkdir mynewdir \$ mv bin2 mynewdir \$ cd mynewdir \$ cd bin2 bash: cd: bin2: No such file or directory

Так как не существует директории /tmp/usr/local/bin/, мы не сможем сменить рабочую директорию на bin2; другими словами, после перемещения ссылка перестала работать (стала "битой").

По этой причине, иногда стоит избегать создания симлинков, используя относительные пути. Но иногда это бывает удобно. Рассмотрим такой случай: допустим мы хотим сделать ссылку на программу в /usr/bin (или другими словами присвоить этой программе альтернативное имя):

# ls -l /usr/bin/keychain -rwxr-xr-x 1 root root 10150 Dec 12 20:09 /usr/bin/keychain

Суперпользователь (root) может захотеть сделать ссылку на программу "keychain" с более коротким именем "kc". В этом примере у нас есть рутовый доступ к системе, о чем свидетельствует приглашение bash, изменившееся на "#" . Нам нужны права суперпользователя потому, что обычные пользователи не могут создавать файлы в директории /usr/bin/. Теперь мы можем от имени рута создать альтернативное имя для нашей программы:

# cd /usr/bin # ln -s /usr/bin/keychain kc # ls -l keychain -rwxr-xr-x 1 root root 10150 Dec 12 20:09 /usr/bin/keychain # ls -l kc lrwxrwxrwx 1 root root 17 Mar 27 17:44 kc -> /usr/bin/keychain

В этом примере мы создали симлинк kc ссылающийся на файл /usr/bin/keychain.

# mv /usr/bin/keychain /usr/bin/kc /usr/local/bin # ls -l /usr/local/bin/kc lrwxrwxrwx 1 root root 17 Mar 27 17:44 kc -> /usr/bin/keychain

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

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

# cd /usr/bin # ln -s keychain kc # ls -l kc lrwxrwxrwx 1 root root 8 Jan 5 12:40 kc -> keychain # mv keychain kc /usr/local/bin # ls -l /usr/local/bin/keychain -rwxr-xr-x 1 root root 10150 Dec 12 20:09 /usr/local/bin/keychain # ls -l /usr/local/bin/kc lrwxrwxrwx 1 root root 17 Mar 27 17:44 kc -> keychain

Теперь мы можем запускать программу "keychain", обратившись к ней по имени /usr/local/bin/kc

rm

Теперь когда мы знаем как работают команды cp , mv и ln пришло время узнать как удалять файлы. Обычно, удаление производится при помощи команды rm . Чтобы удалить несколько файлов, просто укажите их имена через пробел в командной строке как аргументы rm :

\$ cd /tmp \$ touch file1 file2 \$ ls -l file1 file2 -rw-r--r-- 1 root root 0 Jan 1 16:41 file1 -rw-r--r-- 1 root root 0 Jan 1 16:41 file2 \$ rm file1 file2 \$ ls -l file1 file2 ls: file1: No such file or directory ls: file2: No such file or directory

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

\$ rm -i file1 file2 rm: remove regular empty file `file1"? y rm: remove regular empty file `file2"? y

В последнем примере перед удалением каждого файла команда rm спрашивает: действительно ли пользователь хочет удалить файл? Чтобы подтвердить удаление, нудно нажать клавишу "y" на клавиатуре, а чтобы отказаться от удаления - клавишу "n" .

Прервать выполнение любой команды (если что-то пошло не так как задумывалось) можно нажав комбинацию Ctrl C .

Сделать так, чтобы команда rm запрашивала подтверждение на удаление каждого файла даже без опции "-i" можно добавив в файл ~/.bashrc с помощью любимого текстового редактора строку:

alias rm="rm -i"

rmdir

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

\$ mkdir mydir \$ touch mydir/file1 \$ rm mydir/file1 \$ rmdir mydir

Этот способ обычно называют "метод удаления директорий для неудачников". Намного удобнее использовать команду "rm -rf" для удаления директории со всем ее содержимым.

\$ rm -rf mydir

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

Использование wildcards

Что такое wildcards

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

\$ rm file1 file2 file3 file4 file5 file6 file7 file8

Решить эту проблему можно при помощи шаблонов замены (wildcards). Командный интерпретатор линукс поддерживает возможность указания множества файлов используя шаблоны (по историческим причинам это еще называют "globbing"). Bash и другие команды линукс выбирают только те файлы, которые совпадают с шаблоном. Так, если вам нужно удалить файлы с file1 по file8, нужно написать:

\$ rm file

А если нужно удалить все файлы имена которых начинаются со слова file и файл с именем file:

\$ rm file*

Шаблон * соответствует любому символу, последовательности символов или "отсутствию символа". Конечно, шаблоны можно применять не только для удаления файлов, как будет показано ниже.

Если совпадение не найдено

Если вы хотите вывести список файлов в директории /etc/ имена которых начинаются с буквы "g" и файл с именем "g" (если такой существует), нужно написать:

\$ ls -d /etc/g* /etc/gconf /etc/ggi /etc/gimp /etc/gnome /etc/gnome-vfs-mime-magic /etc/gpm /etc/group /etc/group-

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

\$ ls -d /usr/bin/asdf*jkl ls: /usr/bin/asdf*jkl: No such file or directory

В этом примере мы попытались вывести список файлов имена которых начинаются на "asdf" и заканчиваются на "jkl". Интерпретатор команд выдал сообщение что файлов с такими именами не найдено.

Синтаксис шаблона: * и?

Мы посмотрели как работает глоббинг (подстановка имен файлов). А теперь рассмотрим подробнее синтаксис шаблонов:

* соответствует нулю или большему количеству символов:

  • /etc/g* - все файлы в директории /etc/ имена которых начинаются с "g" и файл с именем "g".
  • /tmp/my*1 - все файлы в директории /tmp имена которых начинаются с "my" и заканчиваются на "1" (включая файл с именем "my1")

? заменяет один любой символ:

  • myfile? - любой файл чье имя начинается со слова "myfile" за которым следует один любой символ.
  • /tmp/notes?txt - соответствует файлам с именами "notes.txt" и "notes_txt" (если они существуют в /tmp/).

Квадратные скобки:

Шаблон "" очень похож на "? " но позволяет явно указывать набор символов. Шаблон "" совпадает с одним символом из тех что указаны в скобках. Также в скобках можно указать диапазон символов (для этого используется символ –/дефис) или несколько диапазонов подряд, тогда шаблон будет совпадать с одним любым символом из этого диапазона:

  • myfile - соответствует myfile1 и myfile2. Шаблон будет работать пока существует хотя бы один из этих двух файлов.
  • hangeog - соответствует файлам с именами Changelog, ChangeLog, changeLog, и changelog. Как вы могли заметить, использование шаблона полезно при поиске имен отличающихся регистром букв.
  • ls /etc/* - вывести список файлов в директории /etc/ имена которых начинаются с цифры.
  • ls /tmp/* - вывести список файлов в директории /tmp/ имена которых начинаются с буквы (заглавной или прописной)

Конструкция [ похожа на , за исключением того что она соответствует единичному символу, не упомянутому между [[ и ] . Например:

  • rm myfile[ - удалит все файлы, имена которых состоят из слова "myfile" и идущей за ним одной цифрой, кроме файла "myfile9".

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

Вот несколько примеров использования шаблонов. Так как bash интерпретирует символы ? , [ , ] , * как шаблоны замены, необходимо принять меры предосторожности при использовании аргументов содержащих эти символы. Например, если вы хотите создать файл содержащий строку "* ", то следующая команда сделает не то что вы хотите:

\$ echo * > /tmp/mynewfile.txt

Если в вашей рабочей директории найдется один или несколько файлов, имена которых попадают под шаблон "* ", то вы обнаружите в /tmp/mynewfile.txt список их имен, а не строку "* ". Но как же добиться того чего мы хотели? Первый способ - это взять строку в одинарные кавычки. К строке в одинарных кавычках bash относится как к обычной текстовой строке и не раскрывает символы замены.

\$ echo "*" > /tmp/mynewfile.txt

После выполнения этой команды ваш файл будет содержать строку "* " как и ожидалось. Другой способ - заэкранировать спец.символы с помощью обратного слэша (\ ). Бэкслэш стоящий перед спец.символом сообщает интерпретатору, что этот символ нужно рассматривать как обычный текст а не как шаблон.

\$ echo \\* > /tmp/mynewfile.txt

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

Замечание : Двойные кавычки работаю почти так же как и одинарные, но позволяют bash-у интерпретировать некоторые спец.символы. Поэтому одинарные кавычки - лучший способ передать команде только текст. Для дополнительной информации о шаблонах читайте справку "man 7 glob" . Для дополнительной информации об использовании кавычек, читайте раздел QUOTING справки "man 8 glob" .

Заключение

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

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

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

Pwd ; whoami
На самом деле, если вы опробовали это в своём терминале, ваш первый bash-скрипт, в котором задействованы две команды, уже написан. Работает он так. Сначала команда pwd выводит на экран сведения о текущей рабочей директории, потом команда whoami показывает данные о пользователе, под которым вы вошли в систему.

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

Getconf ARG_MAX
Командная строка - отличный инструмент, но команды в неё приходится вводить каждый раз, когда в них возникает необходимость. Что если записать набор команд в файл и просто вызывать этот файл для их выполнения? Собственно говоря, тот файл, о котором мы говорим, и называется сценарием командной строки.

Как устроены bash-скрипты

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

#!/bin/bash
В других строках этого файла символ решётки используется для обозначения комментариев, которые оболочка не обрабатывает. Однако, первая строка - это особый случай, здесь решётка, за которой следует восклицательный знак (эту последовательность называют ) и путь к bash , указывают системе на то, что сценарий создан именно для bash .

Команды оболочки отделяются знаком перевода строки, комментарии выделяют знаком решётки. Вот как это выглядит:

#!/bin/bash # This is a comment pwd whoami
Тут, так же, как и в командной строке, можно записывать команды в одной строке, разделяя точкой с запятой. Однако, если писать команды на разных строках, файл легче читать. В любом случае оболочка их обработает.

Установка разрешений для файла сценария

Сохраните файл, дав ему имя myscript , и работа по созданию bash-скрипта почти закончена. Сейчас осталось лишь сделать этот файл исполняемым, иначе, попытавшись его запустить, вы столкнётесь с ошибкой Permission denied .



Попытка запуска файла сценария с неправильно настроенными разрешениями

Сделаем файл исполняемым:

Chmod +x ./myscript
Теперь попытаемся его выполнить:

./myscript
После настройки разрешений всё работает как надо.



Успешный запуск bash-скрипта

Вывод сообщений

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

#!/bin/bash # our comment is here echo "The current directory is:" pwd echo "The user logged in is:" whoami
Вот что получится после запуска обновлённого скрипта.



Вывод сообщений из скрипта

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

Использование переменных

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

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

Существуют два типа переменных, которые можно использовать в bash-скриптах:


  • Переменные среды

  • Пользовательские переменные

Переменные среды

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

#!/bin/bash # display user home echo "Home for the current user is: $HOME"
Обратите внимание на то, что мы можем использовать системную переменную $HOME в двойных кавычках, это не помешает системе её распознать. Вот что получится, если выполнить вышеприведённый сценарий.


Использование переменной среды в сценарии

А что если надо вывести на экран значок доллара? Попробуем так:


Система обнаружит знак доллара в строке, ограниченной кавычками, и решит, что мы сослались на переменную. Скрипт попытается вывести на экран значение неопределённой переменной $1 . Это не то, что нам нужно. Что делать?

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

Echo "I have $1 in my pocket"
Теперь сценарий выведет именно то, что ожидается.


Использование управляющей последовательности для вывода знака доллара

Пользовательские переменные

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

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

#!/bin/bash # testing variables grade=5 person="Adam" echo "$person is a good boy, he is in grade $grade"
Вот что получится после запуска такого сценария.


Пользовательские переменные в сценарии

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

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

Сделать это можно двумя способами.


  • С помощью значка обратного апострофа «`»

  • С помощью конструкции $()

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

Mydir=`pwd`
При втором подходе то же самое записывают так:

Mydir=$(pwd)
А скрипт, в итоге, может выглядеть так:

#!/bin/bash mydir=$(pwd) echo $mydir
В ходе его работы вывод команды pwd будет сохранён в переменной mydir , содержимое которой, с помощью команды echo , попадёт в консоль.


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

Математические операции

Для выполнения математических операций в файле скрипта можно использовать конструкцию вида $((a+b)) :

#!/bin/bash var1=$((5 + 5)) echo $var1 var2=$(($var1 * 2)) echo $var2



Математические операции в сценарии

Управляющая конструкция if-then

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

If команда then команды fi
А вот рабочий пример:

#!/bin/bash if pwd then echo "It works" fi
В данном случае, если выполнение команды pwd завершится успешно, в консоль будет выведен текст «it works».

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

#!/bin/bash user=likegeeks if grep $user /etc/passwd then echo "The user $user Exists" fi
Вот что получается после запуска этого скрипта.



Поиск пользователя

Здесь мы воспользовались командой grep для поиска пользователя в файле /etc/passwd . Если команда grep вам незнакома, её описание можно найти .

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

Управляющая конструкция if-then-else

Для того, чтобы программа смогла сообщить и о результатах успешного поиска, и о неудаче, воспользуемся конструкцией if-then-else . Вот как она устроена:

If команда then команды else команды fi
Если первая команда возвратит ноль, что означает её успешное выполнение, условие окажется истинным и выполнение не пойдёт по ветке else . В противном случае, если будет возвращено что-то, отличающееся от нуля, что будет означать неудачу, или ложный результат, будут выполнены команды, расположенные после else .

Напишем такой скрипт:

#!/bin/bash user=anotherUser if grep $user /etc/passwd then echo "The user $user Exists" else echo "The user $user doesn’t exist" fi
Его исполнение пошло по ветке else .


Запуск скрипта с конструкцией if-then-else

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

If команда1 then команды elif команда2 then команды fi
Если первая команда вернёт ноль, что говорит о её успешном выполнении, выполнятся команды в первом блоке then , иначе, если первое условие окажется ложным, и если вторая команда вернёт ноль, выполнится второй блок кода.

#!/bin/bash user=anotherUser if grep $user /etc/passwd then echo "The user $user Exists" elif ls /home then echo "The user doesn’t exist but anyway there is a directory under /home" fi
В подобном скрипте можно, например, создавать нового пользователя с помощью команды useradd , если поиск не дал результатов, или делать ещё что-нибудь полезное.

Сравнение чисел

В скриптах можно сравнивать числовые значения. Ниже приведён список соответствующих команд.

n1 -eq n2 Возвращает истинное значение, если n1 равно n2 .
n1 -ge n2 Возвращает истинное значение, если n1 больше или равно n2 .
n1 -gt n2 Возвращает истинное значение, если n1 больше n2 .
n1 -le n2 Возвращает истинное значение, если n1 меньше или равно n2 .
n1 -lt n2 Возвращает истинное значение, если n1 меньше n2 .
n1 -ne n2 Возвращает истинное значение, если n1 не равно n2 .


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

#!/bin/bash val1=6 if [ $val1 -gt 5 ] then echo "The test value $value1 is greater than 5" else echo "The test value $value1 is not greater than 5" fi
Вот что выведет эта команда.


Сравнение чисел в скриптах

Значение переменной val1 больше чем 5, в итоге выполняется ветвь then оператора сравнения и в консоль выводится соответствующее сообщение.

Сравнение строк

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

str1 = str2 Проверяет строки на равенство, возвращает истину, если строки идентичны.
s tr1 != str2 Возвращает истину, если строки не идентичны.
str1 str1 > str2 Возвращает истину, если str1 больше, чем str2 .
-n str1 Возвращает истину, если длина str1 больше нуля.
-z str1 Возвращает истину, если длина str1 равна нулю.


Вот пример сравнения строк в сценарии:

#!/bin/bash user ="likegeeks" if [$user = $USER] then echo "The user $user is the current logged in user" fi
В результате выполнения скрипта получим следующее.



Сравнение строк в скриптах

Вот одна особенность сравнения строк, о которой стоит упомянуть. А именно, операторы «>» и «» как команду перенаправления вывода.

Вот как работа с этими операторами выглядит в коде:

#!/bin/bash val1=text val2="another text" if [ $val1 >
Вот результаты работы скрипта.



Сравнение строк, выведенное предупреждение

Обратите внимание на то, что скрипт, хотя и выполняется, выдаёт предупреждение:

./myscript: line 5: [: too many arguments
Для того, чтобы избавиться от этого предупреждения, заключим $val2 в двойные кавычки:

#!/bin/bash val1=text val2="another text" if [ $val1 > "$val2" ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
Теперь всё работает как надо.


Сравнение строк

Ещё одна особенность операторов «>» и «
Likegeeks likegeeks
Сохраним его, дав имя myfile , после чего выполним в терминале такую команду:

Sort myfile
Она отсортирует строки из файла так:

Likegeeks Likegeeks
Команда sort , по умолчанию, сортирует строки по возрастанию, то есть строчная буква в нашем примере меньше прописной. Теперь подготовим скрипт, который будет сравнивать те же строки:

#!/bin/bash val1=Likegeeks val2=likegeeks if [ $val1 > $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
Если его запустить, окажется, что всё наоборот - строчная буква теперь больше прописной.



Команда sort и сравнение строк в файле сценария

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

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

Проверки файлов

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

D file Проверяет, существует ли файл, и является ли он директорией.
-e file Проверяет, существует ли файл.
-f file Проверяет, существует ли файл, и является ли он файлом.
-r file Проверяет, существует ли файл, и доступен ли он для чтения.
-s file П роверяет, существует ли файл, и не является ли он пустым.
-w file Проверяет, существует ли файл, и доступен ли он для записи.
-x file Проверяет, существует ли файл, и является ли он исполняемым.
file1 -nt file2 Проверяет, новее ли file1 , чем file2 .
file1 -ot file2 Проверяет, старше ли file1 , чем file2 .
-O file Проверяет, существует ли файл, и является ли его владельцем текущий пользователь.
-G file Проверяет, существует ли файл, и соответствует ли его идентификатор группы идентификатору группы текущего пользователя.


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

Опробуем одну из команд на практике:

#!/bin/bash mydir=/home/likegeeks if [ -d $mydir ] then echo "The $mydir directory exists" cd $ mydir ls else echo "The $mydir directory does not exist" fi
Этот скрипт, для существующей директории, выведет её содержимое.



Вывод содержимого директории

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

Итоги

Сегодня мы рассказали о том, как приступить к написанию bash-скриптов и рассмотрели некоторые базовые вещи. На самом деле, тема bash-программирования огромна. Эта статья является переводом первой части большой серии из 11 материалов. Если вы хотите продолжения прямо сейчас - вот список оригиналов этих материалов. Для удобства сюда включён и тот, перевод которого вы только что прочли.
  • - здесь приведены приёмы работы с сообщениями, которые можно отправлять пользователям, а так же методика мониторинга диска.

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

    Переводить остальные части цикла статей?









    Да!

    Нет, не нужно

    Только зарегистрированные пользователи могут участвовать в опросе. , пожалуйста.