Язык shell в Linux

Конспект в доработке

    Sourcing Files

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

    # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi

    В коде выше if гарантирует, что файл $HOME/.bashrc — если он существует (-f) — будет обработан (то есть прочитан и выполнен) при входе в систему


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

    . ~/.bashrc

    Команда source является синонимом .. Таким образом, чтобы выполнить команду source для ~/.bashrc, можно сделать так:

    source ~/.bashrc
    Переменные

    Bash делит переменные на локальные (которые существуют только в рамках оболочки, в которой они были созданы) и глобальные (которые наследуются дочерними оболочками и/или процессами)
    В Bash присвоение значения имени называется присваиванием переменной
    Процесс обращения к значению, содержащемуся в имени, называется ссылкой на переменную.
    Имя переменной может содержать буквы (a-z,A-Z), цифры (0-9) и символы подчеркивания (_)
    При обращении к переменной, значение которой содержит начальные (или дополнительные) пробелы, иногда в сочетании со звездочками, необходимо использовать двойные кавычки после команды echo, чтобы избежать разделения поля и расширения пути:

    $ lizard=" род | uros" $ echo $lizard род | uros $ echo "$lizard" род | uros

    Если в ссылке на переменную стоит закрывающий восклицательный знак, он должен быть последним символом в строке (иначе Bash решит, что мы ссылаемся на событие history):

    $ distro=zorin.?/!os -bash: !os: событие не найдено $ distro=zorin.?/! $ echo $distro zorin.?/!

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

    $ distro=zorinos\ > $ distro=zorinos\\ $ echo $distro zorinos\
    Локальные переменные или переменные оболочки

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


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

    readonly reptile=черепаха

    При попытке изменить такую переменную, получим ошибку: переменная доступна только для чтения


    Чтобы вывести список всех переменных, доступных только для чтения в текущем сеансе, введите в терминале readonly или readonly -p

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

    #Просмотр всех назначенных переменных set | less

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

    chich@T460:~$ bash chich@T460:~$ set | grep reptile

    Чтобы удалить все переменные (локальные или глобальные), мы используем команду unset

    unset reptile
    Глобальные переменные или переменные среды

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


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

    #Экспорт переменной export reptile #export можно использовать для одновременного присвоения и экспорта переменной export amphibian=лягушка #переменная будет преобразована обратно в локальную переменную оболочки export -n reptile #export также выводит список всех существующих переменных среды, если ввести ее без параметров export #Команда declare -x эквивалентна export. chich@T460:~$ declare -x reptile chich@T460:~$ bash chich@T460:~$ set | grep reptile reptile=черепаха chich@T460:~$ export | grep reptile declare -x reptile="черепаха" chich@T460:~$ #Еще две команды, с помощью которых можно вывести список всех переменных среды env printenv printenv HOME

    Используйте команду export, чтобы добавить новый каталог в переменную PATH (после перезагрузки изменения сохранятся).
    Вы можете временно добавить в переменную PATH новый каталог (например, myfiles в вашем домашнем каталоге) с помощью export PATH="/home/yourname/myfiles:$PATH"

    export PATH="/home/yourname/myfiles:$PATH"

    Чтобы запустить новую сессию Bash с максимально пустой средой — без большинства переменных (а также функций и псевдонимов), — мы будем использовать env с опцией -i:

    env -i bash echo $USER env

    Можно использовать env для установки определенной переменной для конкретной программы
    Скрипты не считывают стандартные файлы запуска, а вместо этого ищут значение переменной BASH_ENV и используют его в качестве файла запуска, если он существует.
    Создадим собственный файл запуска под названием .startup_script со следующим содержимым:

    CROCODILIAN=caiman

    Мы пишем Bash-скрипт с именем test_env.sh со следующим содержимым:

    #!/bin/bash echo $CROCODILIAN #Добавим бит исполняемого файла chmod +x test_env.sh #используем env для установки BASH_ENV в .startup_script при выполнении test_env.sh env BASH_ENV=/home/user/.startup_script ./test_env.sh
    Общие Переменные среды

    DISPLAY - Значение этой переменной, связанной с сервером X, обычно состоит из трех элементов:
    Имя хоста (его отсутствие означает localhost), на котором запущен X-сервер.
    Двоеточие в качестве разделителя.
    Число (обычно 0 и обозначает дисплей компьютера).
    Пустое значение этой переменной означает, что сервер не использует X Window System. Дополнительное число — например, my.xserver:0:1 — указывает на номер экрана, если их несколько.


    HISTFILE - Имя файла, в котором хранятся все введенные команды.

    HISTCONTROL - определяет, какие команды будут сохранены в HISTFILE. Возможны три варианта:
    ignorespace - Команды, начинающиеся с пробела, не будут сохранены.
    ignoredups - Команда, совпадающая с предыдущей, не будет сохранена.
    ignoreboth - Команды, относящиеся к одной из двух предыдущих категорий, не будут сохранены.

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

    HISTFILESIZE - количество команд, которые будут сохранены в HISTFILE в начале и в конце сеанса

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

    #фрагмент кода — из ~/.profile ## включить .bashrc, если он существует if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi

    HOSTNAME - В этой переменной хранится TCP/IP-имя хост-компьютера


    HOSTTYPE - Здесь хранится информация об архитектуре процессора основного компьютера

    LANG - Эта переменная сохраняет языковой стандарт системы

    LD_LIBRARY_PATH - Эта переменная состоит из набора каталогов, разделенных двоеточиями, в которых находятся разделяемые библиотеки для программ

    MAIL - В этой переменной хранится файл, в котором Bash ищет электронную почту

    MAILCHECK - Эта переменная содержит числовое значение, указывающее в секундах частоту, с которой Bash проверяет наличие новых писем

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

    if [ "`id -u`" -eq 0 ]; then PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ещё PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" fi export PATH

    В этой переменной хранится значение приглашения Bash. В следующем фрагменте кода (также из /etc/profile), оператор if проверяет личность пользователя и в зависимости от результата выводит очень сдержанное приглашение

    if [ "`id -u`" -eq 0 ]; then PS1='# ' ещё PS1='$ ' fi

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


    PS3 - Используется в качестве подсказки для команды select PS4 - Обычно устанавливается в + и используется для отладки.

    SHELL - Эта переменная содержит абсолютный путь к текущей оболочке

    SSH_CONNECTION - Ссылка на переменную среды, в которой хранится информация о ssh соединениях

    #Добавить каталог для исполняемых файлов в переменную среды PATH=$PATH:/home/carol/scripts
    Псевдоним

    Псевдоним — это альтернативное название другой команды (других команд). Он может запускаться как обычная команда, но вместо этого выполняет другую команду в соответствии с определением псевдонима.
    alias alias_name=команда
    Например:
    alias oldshell=sh


    Преимущество псевдонимов в том, что они позволяют писать короткие версии длинных команд:
    alias ls='ls --color=auto'

    Чтобы получить информацию о ls и его цветах, введите man dir_colors в терминале.

    #Команда alias выведет список всех доступных псевдонимов в системе: alias #Команда unalias удаляет псевдонимы. unalias git-info #Примеры alias alias ls='ls --color=auto' alias oldshell='sh' alias greet='echo Hello world!' alias ll='ls -al'

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

    function

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


    Функции только для чтения — это функции, содержимое которых мы не можем изменить
    readonly -f my_fun

    Специальные встроенные переменные Bash

    Bourne Again Shell поставляется с набором специальных переменных, которые особенно полезны для функций и скриптов. Они являются специальными, потому что на них можно только ссылаться, но нельзя присваивать им значения. Вот список наиболее важных из них:
    $? - результат выполнения последней команды
    $$ - Расшифровывается как PID (идентификатор процесса) оболочки
    $! - PID последнего фонового задания (амперсанд (&) используется для запуска процессов в фоновом режиме.)


    $0 по $9 - параметры и аргументы передаваемые скриптам

    $# - кол-во аргументов передаваемых в команде
    $@, $* - кол-во аргументов передаваемых в команде

    Файл сценария — это упорядоченная последовательность команд, которые должны быть выполнены соответствующим командным интерпретатором
    Интерпретатор может по-разному считывать файл сценария, и в сеансе работы с оболочкой Bash это можно сделать разными способами, но по умолчанию интерпретатором для файла сценария будет тот, который указан в первой строке сценария сразу после символов #! (так называемый шебанг)


    Bash вызовет команду, указанную после #!, в качестве интерпретатора для файла сценария. Это может быть полезно, например, для запуска других скриптовых языков, таких как Python (#!/usr/bin/python), Perl (#!/usr/bin/perl) или awk (#!/usr/bin/awk).

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

    При выполнении скрипта содержащиеся в нем команды запускаются не в текущем сеансе, а в новом процессе Bash, который называется под-оболочкой. Это предотвращает перезапись переменных среды текущего сеанса скриптом и внесение изменений в текущий сеанс без участия пользователя. Если нужно запустить содержимое скрипта в текущем сеансе оболочки, его следует запускать с помощью source script.sh или . script.sh (обратите внимание, что между точкой и названием скрипта есть пробел).

    Аргументы

    Аргументы, передаваемые в скрипт, и другая полезная информация хранятся в параметрах $0, $*, $? и т. д., где символ после знака доллара указывает на извлекаемую информацию:
    $* - Все аргументы, переданные в скрипт.


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

    $# - Количество аргументов.

    $0 - Имя файла скрипта.

    $! - PID последней запущенной программы.

    $$ - PID текущей оболочки.

    $? - Числовой код состояния выхода последней выполненной команды. Для стандартных процессов POSIX числовое значение 0 означает, что последняя команда была успешно выполнена. Это также относится к сценариям командной оболочки.

    Позиционный параметр - это параметр, обозначаемый одной или несколькими цифрами, отличными от однозначной 0
    Например, переменная $1 соответствует первому аргументу, заданному скрипту (позиционный параметр one), $2 соответствует второму аргументу и так далее. Если позиция параметра больше девяти, ссылка на него должна быть заключена в фигурные скобки, как в ${10}, ${11} и т.д.

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

    echo "Вы хотите продолжить (y/n)?" read ANSWER #можно использовать команду read для одновременного чтения нескольких переменных: echo "Введите свое имя и фамилию:" read NAME SURNAME #read может самостоятельно вывести сообщение для пользователя с помощью опции -p read -p "Введите свое имя и фамилию:" ИМЯ ФАМИЛИЯ

    Для сохранения вывода команды в переменной можно использовать обратные кавычки:
    $ OS=`uname -o`
    Аналогичный результат будет получен с помощью $():
    $ OS=$(uname -o)


    Чтобы узнать длину переменной, то есть количество содержащихся в ней символов, нужно добавить хэш # перед ее названием. Однако для использования этой функции необходимо указывать переменную в фигурных скобках:
    $ OS=$(uname -o)
    $ echo $OS
    GNU/Linux
    $ echo ${#OS}
    9
    

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

    #объявить переменную SIZES массивом: declare -a SIZES

    Массивы также могут быть объявлены неявно при заполнении из заранее заданного списка элементов с помощью скобок
    На элементы массива нужно ссылаться с помощью фигурных и квадратных скобок, иначе Bash не сможет корректно изменить или отобразить элемент. Поскольку индексы массива начинаются с 0, содержимое первого элемента находится в ${SIZES[0]}, второго — в ${SIZES[1]} и так далее.
    В отличие от чтения, изменение содержимого элемента массива выполняется без фигурных скобок (например, SIZES[0]=1048576)

    #Неявное объявление массивов SIZES=( 1048576 1073741824 ) echo ${SIZES[1]} #Присвоить значение элементу массива SIZES[0]=1048576 #длина элемента массива echo ${#SIZES[0]} #@ или *, возвращается общее количество элементов в массиве: echo ${#SIZES[*]}

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

    FS=( $(cut -f 2 < /proc/filesystems) ) echo ${FS[3]} proc

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


    Bash воспринимает каждый символ в $IFS (разделителе полей ввода) переменной окружения как разделитель. Чтобы изменить разделитель полей на символы новой строки, нужно сбросить переменную IFS с помощью команды IFS=$'\n'.

    Модель TCP/IP, так же как и модель OSI, имеет многоуровневую структуру, но для того, чтобы данные от приложения компьютера А были переданы приложению на компьютере B, они должны последовательно пройти 4 уровня: уровень приложений, транспортный уровень, уровень Интернет и уровень доступа к среде.

    Трем верхним уровням модели OSI соответствует уровень приложений (Application layer) в модели TCP/IP, который включается в себя функции представления, кодирования и контроля над установлением соединения. Существует множество протоколов уровня приложений, из которых самыми распространенными являются FTP, TFTP, HTTP/HTTPs, DHCP, DNS, Telnet, SMTP, POP3, IMAP и др.

    Транспортный уровень (Transport layer) модели TCP/IP выполняет те же функции, что и одноименный уровень в модели OSI.

    Уровень доступа к среде (Network access layer) объединяет функции канального и физического уровня модели OSI, обеспечивая физическую передачу данных в сети. Существует множество различных протоколов уровня доступа к сети, из которых самыми распространенными являются Ethernet, Token Ring, FDDI, PPP, IEEE 802.11 (Wi-Fi), ATM и др.

    Арифметические выражения

    Bash предоставляет удобный способ выполнения целочисленных арифметических операций с помощью встроенной команды expr
    Команду expr можно заменить на $(())

    #Сложение переменных SUM=`expr $VAL1 + $VAL2` #$(()) SUM=$(( $VAL1 + $VAL2 )) #Выражения со степенями SIZES=( $((1024**2)) $((1024**3)) ) #Умножение #количество свободных байт в ОЗУ FREE=$(( 1000 * `sed -nre '2s/[^[:digit:]]//gp' < /proc/meminfo` ))
    Условное выполнение

    Если разделить команды с помощью &&, то команда справа будет выполнена только в том случае, если команда слева не вызвала ошибку, то есть если ее код завершения был равен 0
    КОМАНДА A && КОМАНДА B && КОМАНДА C


    Если команды разделены символом ||., происходит обратное: следующая команда будет выполнена только в том случае, если предыдущая вызвала ошибку, то есть если ее код состояния отличается от 0.
    КОМАНДА A || КОМАНДА B

    Символ новой строки \n можно использовать для разделения строк вывода, поэтому тот же результат можно получить, объединив две команды echo в одну:

    echo -e "Операционная система:\t$OS\nНераспределенная оперативная память:\t$(( $FREE / 1024**2 )) МБ"

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

    printf "Операционная система:\t%s\nНераспределенная оперативная память:\t%d МБ\n" $OS $(( $FREE / 1024**2 ))

    Формат подстановки заполнителей, выполняемой с помощью printf, можно настроить, используя тот же формат, что и в функции printf языка программирования C. Полное описание функции printf можно найти на странице руководства, доступ к которой осуществляется с помощью команды man 3 printf.


    При использовании printf переменные размещаются за пределами текстового шаблона, что позволяет сохранить текстовый шаблон в отдельной переменной
    MSG='Операционная система:\t%s\nСвободная оперативная память:\t%d МБ\n'
    printf "$MSG" $OS $(( $FREE / 1024**2 ))

    Ввод пароля

    Опция -s для команды read полезна при вводе паролей, так как не отображает вводимый текст на экране.

    Команда test или if

    #Проверим что каталог это каталог test -d /etc #существует ли путь в VAR в файловой системе и является ли он файлом. VAR=/usr/bin/ip -a "$VAR" #является ли путь в VAR специальным блочным файлом. test -b "$VAR" #является ли путь в VAR файлом со специальным символом test -c "$VAR" # является ли путь в VAR каталогом. test -d "$VAR" #существует ли путь в VAR в файловой системе test -e "$VAR" #существует ли путь в VAR и является ли он обычным файлом test -f "$VAR" #Проверьте, есть ли у пути в VAR разрешение SGID test -g "$VAR" #является ли путь в VAR символической ссылкой test -h "$VAR" # является ли путь в VAR символической ссылкой (например, -h) test -L "$VAR" #есть ли у пути в VAR разрешение sticky test -k "$VAR" #является ли путь в VAR файлом pipe test -p "$VAR" #доступен ли путь в VAR для чтения текущему пользователю test -r "$VAR" # существует ли путь в VAR и не является ли он пустым. -s "$VAR" # является ли путь в VAR файлом сокета test -S "$VAR" #открыт ли путь в VAR в терминале test -t "$VAR" #есть ли у пути в VAR разрешение SUID test -u "$VAR" #доступен ли путь в VAR для записи текущему пользователю test -w "$VAR" #доступен ли путь в VAR для выполнения текущим пользователем test -x "$VAR" #принадлежит ли путь в VAR текущему пользователю test -O "$VAR" # относится ли путь в VAR к эффективной группе текущего пользователя -G "$VAR" #был ли изменен путь в VAR с момента последнего обращения к нему test -N "$VAR" #Сравните даты изменения файлов в VAR1 и VAR2 и определите, какой из них новее test "$VAR1" -ot "$VAR2" #не является ли путь в VAR1 более старым, чем VAR2 test "$VAR1" -ot "$VAR2" #выражение возвращает значение True, если путь в VAR1 является жесткой ссылкой на VAR2 test "$VAR1" -ef "$VAR2"

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

    #не является ли переменная TXT пустой test -z "$TXT" #не является ли переменная TXT пустой test -n "$TXT" или test "$TXT" #равны ли TXT1 и TXT2 test "$TXT1" = "$TXT2" #or test "$TXT1" == "$TXT2" #не равны ли TXT1 и TXT2 test "$TXT1" != "$TXT2" #стоит ли TXT1 перед TXT2, в алфавитном порядке test "$TXT1" > "$TXT2" #идет ли TXT1 после TXT2, в алфавитном порядке test "$TXT1" > "$TXT2"

    В разных языках могут быть разные правила алфавитного упорядочивания


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

    #меньше ли NUM1 чем NUM2 test $NUM1 -lt $NUM2 #больше ли NUM1 чем NUM2 test $NUM1 -gt $NUM2 #меньше ли NUM1 или равно NUM2 test $NUM1 -le $NUM2 #больше ли NUM1 или равно NUM2 test $NUM1 -ge $NUM2 #равно ли NUM1 NUM2 test $NUM1 -eq $NUM2 #не равно ли NUM1 NUM2 test $NUM1 -ne $NUM2 #является ли выражение EXPR ложным ! EXPR #верны ли оба утверждения: EXPR1 и EXPR2 EXPR1 -a EXPR2 #истинно ли хотя бы одно из двух выражений EXPR1 -o EXPR2
    Конструкция case

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

    #!/bin/bash DISTRO=$1 echo -n "Дистрибутив $DISTRO использует " case "$DISTRO" in debian | ubuntu | mint) echo -n "пакет DEB" ;; centos | fedora | opensuse ) echo -n "пакет RPM" ;; *) echo -n "неизвестный пакет" ;; esac echo "формат пакета."

    В Bash есть опция nocasematch , которая включает сопоставление с образцом без учета регистра для конструкции case и других условных команд. Встроенная команда shopt переключает значения параметров, управляющих дополнительными функциями оболочки: shopt -s включает (set) заданную опцию, а shopt -u отключает (unset) заданную опцию. Таким образом, если поместить shopt -s nocasematch перед конструкцией case, будет включено сопоставление с образцом без учета регистра. Параметры, измененные shopt, повлияют только на текущий сеанс, поэтому измененные параметры внутри скриптов, запущенных во вложенной оболочке, что является стандартным способом запуска скрипта, не влияют на параметры родительского сеанса.


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

    Циклические конструкции

    Bash есть три инструкции для циклов — for, until и while, — предназначенные для немного отличающихся друг от друга конструкций циклов.


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

    for VARNAME in LIST do КОМАНДЫ done

    Bash также поддерживает альтернативный формат конструкций for с использованием двойных скобок. Этот формат напоминает синтаксис инструкций for в языке программирования C и особенно удобен для работы с массивами:

    #!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) for (( IDX = 0; IDX < ${#SEQ[*]}; IDX++ )) do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi done

    Аналогичным образом конструкция until выполняет последовательность команд до тех пор, пока тестовая команда — как и сама команда test — не завершится со статусом 0 (успешно)

    #!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) IDX=0 until [ $IDX -eq ${#SEQ[*]} ] do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi IDX=$(( $IDX + 1 )) done

    Mapfile (также известна как readarray) — встроенная команда командной оболочки Bash в Linux и Unix-подобных операционных системах. Она считывает строки из стандартного ввода или файлового дескриптора в переменную индексированного массива.
    Строки читаются непосредственно в массив без использования цикла, что быстрее для обработки больших файлов.
    С помощью опции -t mapfile автоматически удаляет символ новой строки (по умолчанию) с конца каждой строки, что экономит дополнительный шаг в обработке


    #!/bin/bash set -ef # Список элементов для синхронизации FILE=~/.sync.list # Исходный каталог FROM=$1 # Целевой каталог TO=$2 # Проверяем, существуют ли оба каталога if [ ! -d "$FROM" -o ! -d "$TO" ] then echo Использование: echo "$0 " exit 1 fi # Создание массива из файла mapfile -t LIST < $FILE # Синхронизация элементов for (( IDX = 0; IDX < ${#LIST[*]}; IDX++ )) do echo -e "$FROM/${LIST[$IDX]} \u2192 $TO/${LIST[$IDX]}"; rsync -qa --delete "$FROM/${LIST[$IDX]}" "$TO"; done

    Первое действие скрипта — переопределение двух параметров оболочки с помощью команды set: опция -e немедленно завершает выполнение, если команда завершается с ненулевым кодом выхода, а опция -f отключает подстановку имен файлов. Обе опции можно сократить до -ef. Это необязательный шаг, но он помогает снизить вероятность непредвиденного поведения.


    FILEПеременная - это путь к файлу, содержащему список элементов, подлежащих копированию

    После определения всех параметров с помощью команды mapfile -t LIST < $FILE. создается массив, содержащий список элементов для копирования. Опция -t команды mapfile удаляет завершающий символ новой строки из каждой строки перед включением в переменную массива с именем LIST

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

    В выходном сообщении присутствует экранированный символ Юникода — \u2192 — для символа стрелка вправо, поэтому необходимо использовать опцию -e команды echo

    Параметр --delete приведет к rsync удалению элемента в целевом каталоге, которого больше нет в исходном каталоге, поэтому его следует использовать с осторожностью.

    Дополнительно

    Как можно использовать все аргументы командной строки скрипта для инициализации массива Bash?
    Команды PARAMS=( $* ) или PARAMS=( "$@" ) создают массив с именем PARAMS со всеми аргументами.


    Как пользователю временно изменить разделитель полей по умолчанию на символ новой строки, чтобы при этом иметь возможность вернуть его в исходное состояние?
    Копию переменной IFS можно сохранить в другой переменной: OLDIFS=$IFS. Затем с помощью IFS=$'\n' можно задать новый разделитель строк, а с помощью IFS=$OLDIFS. — вернуть переменную IFS в исходное состояние.

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

    hello="A B C D" echo $hello # A B C D echo "$hello" # A B C D # Здесь вы сможете наблюдать различия в выводе echo $hello и echo "$hello".
    устая команда. [двоеточие]

    Пустая команда. [двоеточие] Это эквивалент операции "NOP" (no op, нет операции). Может рассматриваться как синоним встроенной команды true. Команда ":" так же является встроенной командой Bash, которая всегда возвращает "true"

    #Бесконечный цикл: while : do operation-1 operation-2 ... operation-n done # То же самое: # while true # do # ... # done #Символ-заполнитель в условном операторе if/then: if condition then : # Никаких действий не производится и управление передается дальше else take-some-action fi #В операциях с подстановкой параметров #Вывод сообщения об ошибке, если одна или более переменных не определены. : ${HOSTNAME?} ${USER?} ${MAIL?}
    Круглые скобки

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

    #группа команд. (a=hello; echo $a) #инициализация массивов. Array=(element1 element2 element3)
    Фигурные скобки

    # Поиск всех вхождений слова "Linux" grep Linux file*.{txt,htm*} #Подстановка echo {file1,file2}\ :{\ A," B",' C'}

    Блок кода. [фигурные скобки] Известен так же как "вложенный блок", эта конструкция, фактически, создает анонимную функцию. Однако, в отличии от обычных функций, переменные, создаваемые во вложенных блоках кода, доступны объемлющему сценарию.

    { local a; a=123; }

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

    #!/bin/bash # Чтение строк из файла /etc/fstab. File=/etc/fstab { read line1 read line2 } < $File echo "Первая строка в $File :" echo "$line1" echo echo "Вторая строка в $File :" echo "$line2" exit 0

    Сохранение результата исполнения вложенного блока в файл

    { echo "Описание архива:" } > "file.txt" # Перенаправление вывода в файл.

    {} \; - pathname -- полное имя файла (т.е. путь к файлу и его имя). Чаще всего используется совместно с командой find.

    Принудительное перенаправление

    >|
    принудительное перенаправление, даже если установлен ключ noclobber option.


    Источник: https://www.opennet.ru/docs/RUS/bash_scripting_guide/c301.html

    Использование префикса "-" в перенаправлениях

    В случае, когда ожидается имя файла, тогда "-" перенаправляет вывод на stdout
    Перемещение полного дерева файлов и подкаталогов из одной директории в другую

    (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)

    # 1) cd /source/directory    Переход в исходный каталог, содержимое которого будет перемещено
    # 2) &&                     "И-список": благодаря этому все последующие команды будут выполнены
    #                            только тогда, когда 'cd' завершится успешно
    # 3) tar cf - .              ключом 'c' архиватор 'tar' создает новый архив,
    #                            ключом 'f' (file) и последующим '-' задается файл архива -- stdout,
    #                            в архив помещается текущий каталог ('.') с вложенными подкаталогами.
    # 4) |                       конвейер с ...
    # 5) ( ... )                 subshell-ом (дочерним экземпляром командной оболочки)
    # 6) cd /dest/directory      Переход в каталог назначения.
    # 7) &&                     "И-список", см. выше
    # 8) tar xpvf -              Разархивирование ('x'), с сохранением атрибутов "владельца" и прав доступа ('p') к файлам,
    #                            с выдачей более подробных сообщений на stdout ('v'),
    #                            файл архива -- stdin ('f' с последующим '-').
    #
    #                            Примечательно, что 'x' -- это команда, а 'p', 'v' и 'f' -- ключи
    

    Обратите внимание, что в этом контексте "-" - не самостоятельный оператор Bash, а скорее опция, распознаваемая некоторыми утилитами UNIX (такими как tar, cat и т.п.), которые выводят результаты своей работы в stdout.

    echo "whatever" | cat -

    Резервное архивирование всех файлов, которые были изменены в течение последних суток

    Резервное архивирование всех файлов, которые были изменены в течение последних суток
    #!/bin/bash # Резервное архивирование (backup) всех файлов в текущем каталоге, # которые были изменены в течение последних 24 часов #+ в тарболл (tarball) (.tar.gz - файл). BACKUPFILE=backup archive=${1:-$BACKUPFILE} # На случай, если имя архива в командной строке не задано, #+ т.е. по-умолчанию имя архива -- "backup.tar.gz" tar cvf - `find . -mtime -1 -type f -print` > $archive.tar gzip $archive.tar echo "Каталог $PWD заархивирован в файл \"$archive.tar.gz\"." # Stephane Chazelas заметил, что вышеприведенный код будет "падать" #+ если будет найдено слишком много файлов #+ или если имена файлов будут содержать символы пробела. # Им предложен альтернативный код: # ------------------------------------------------------------------- # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar" # используется версия GNU утилиты "find". # find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \; # более универсальный вариант, хотя и более медленный, # зато может использоваться в других версиях UNIX. # ------------------------------------------------------------------- exit 0

    Источник: https://www.opennet.ru/docs/RUS/bash_scripting_guide/c301.html

    Классы символов

    [:upper:] - Символы в верхнем регистре
    [^[:upper:]] - Кроме символов в верхнем регистре
    [:digit:] - Десятичные цифры
    [^- [:digit:]\(\)] - Кроме цифр, скобок, дефисов
    Перевод первого символа строки в верхний регистр:

    name=toly; echo $name | cut -c1 | tr '[:lower:]' '[:upper:]' echo 347.22 | cut -d. -f1 #получить значения слева от точки echo 347.22 | cut -d. -f2 #получить значения справа от точки

    Цикл работает пока num больше 5, в теле уменьшается число num:

    num=10; while [ $num -gt 5 ]; do echo $num; num=$(expr $num - 1); done

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

    while getopts "a:b:" opt; do case $opt in a ) echo "Это опция a" ;; b ) echo "Это опция b" ;; esac done

    #Первый символ num, num без первого символа

    num=-1; echo "${num%${num#?}}"; echo "${num#?}";

    #Оставить в переменной все кроме цифр:

    echo $num | sed "s/[[:digit:]]//g"

    #1. Убрать все символы, кроме точки, 2. Вывод символов слева от точки, 3. Символы справа от точки:

    num=10.5; echo $num | sed 's/[^.]//g'; echo $num | cut -d. -f1; echo ${num#*\.}
    Замена вхождений с помощью утилиты tr

    Замена регистра:

    ~/bash_scripts$ echo "HeLlo" | tr '[:upper:]' '[:lower:]' hello ~/bash_scripts$ echo "HeLlo" | tr '[:lower:]' '[:upper:]' HELLO

    Если year не делится без остатка на 4, тогда...

    ~$ year=20; if [ "$((year % 4))" -ne 0 ] ; then echo echo 1; else echo 0; fi 0

    Разбить дату на день, месяц, год:

    ~$ date=10/07/2022; echo $date | cut -d/ -f1 10 ~$ date=10/07/2022; echo $date | cut -d/ -f2 07 ~$ date=10/07/2022; echo $date | cut -d/ -f3 2022

    Удалить из текста все знаки переноса:

    cat test.txt | tr -d '\n'

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

    bc << EOF $test $* quit EOF

    $OPTIND - это индекс следующего обрабатываемого аргумента which - выводит полный путь до файла скрипта команды

    Перебор аргументов
    #!/bin/bash for arg in "$@" do echo "${PREFIX}: $arg" if [ -f ${arg} ] ; then echo "${arg} is a file" fi #Либо использовать case done

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

    t@x:~$ echo "test=2" >> tinyscript.sh t@x:~$ chmod +x tinyscript.sh t@x:~$ test=1 t@x:~$ ./tinyscript.sh t@x:~$ echo $test 1 t@x:~$

    Если выполнить это сценарий подключением файла с помощью точки идентичной команде source (include в языке C)FD

    . tinyscript.sh

    Таким образом можно подключить библиотечный файл с готовыми функциями, сценариями в один из каталогов перечисленных в окружении PATH
    Для вывода отладочной информации используй bash -x script.sh
    Как вариант, можно использовать set -x перед началом выполнения скрипта и set +x после выполнения скрипта


    Получение случайного числа
    echo $RANDOM
    Вывод директорий из переменной $PATH
    $ IFS=":"; for directory in $PATH ; do echo $directory; done
    Источники
    Последнее изменение: 27.05.2026 16:37


    Связанные темы

    Что такое tty

    Конфигурация vsftpd в ОС Linux Ubuntu

    Передача аргументов по ссылке

    Установка и конфигурация samba в Linux

    Оптимизация запросов в Postgresql

    Оператор разрешения видимости в php

    Типы данных в Postgresql

    Структура пакета deb

    Структура каталогов linux(Debian)

    Разделы диска Linux

    Ключевое слово static в php

    Позднее статическое связывание

    Модификация таблиц

    Язык программирования C в Linux

    Буферный кэш и журнал в Postgresql

    Установка и настройка MS SQL Server 2008 на Windows Server 2008 r

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

    Sysstat

    Использование hydra для тестирования

    Curl IMAP

    Очистка базы данных

    Шаблоны template в Postgresql

    Атрибуты в php

    Методы создания экземпляра класса в php

    Конфигурация сервиса SSHFS

    NVMe в Linux

    Проверка жесткого диска

    Команда exec linux

    Представления в Postgresql

    Значения по умолчанию

    Подзапросы в Postgresql

    gdb

    Конфигурация openvpn сервера в Linux Alpine

    sudo и su в Linux

    Инструкция return в php

    Удаление файлов из bash linux с возможностью восстановления

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

    Использование модуля pg_stat_statements в postgresql

    Поиск уязвимостей и следов взлома в Linux

    Транзакции в Postgresql

    Системный каталог в Postgresql

    Функции переменных в PHP

    Dialog в Linux Alpine

    Конфигурация ssl в Nginx

    Конфигурация почтового сервера

    Схемы в Postgresql

    Создание Unit в Linux Ubuntu

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

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

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

    Определение данных в Postgresql

    Изменение временной зоны в Postgresql

    Nginx content caching

    Балансировка нагрузки в Nginx

    Процессы и потоки в Linux

    Монтирование в linux

    Создание демона в среде Linux

    Сценарий инициализации в Linux

    Копирование в ssh

    Конфигурация nginx

    Табличные пространства в Postgresql

    Введение в Python

    Адаптивная верстка

    Индексы в Postgresql

    Systemd в Linux

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

    Менеджер пакетов dpkg

    Библиотеки Linux

    Анализ rdp

    Управление планировщиком в Postgresql

    Настройка swap в Linux

    Sysvinit в Linux Ubuntu

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

    Информация о системе

    Выполнение html и js кода в php

    Запросы в Postgresql

    Резервная копия postgresql

    Ядро Linux

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

    История команд в Linux

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

    Изменение данных в Postgresql

    Программирование на языке Assembler в Linux

    Основные команды psql и sql Postgresql

    Методы формирования соединений наборов строк

    Оптимизация производительности

    RabbitMQ

    Использование wget и curl в Linux

    ssh в Linux

    Возможности ssh в Linux

    Агрегирование и группировка в Postgresql

    Основные понятия реляционной модели

    Замыкание в PHP

    Присваивание объектов в php

    Автоматическая загрузка классов

    Управление учетными записями пользователей в Linux

    Разделяемые библиотеки в Linux

    Команда chattr и lsattr в Linux

    Сброс пароля root в grub (Linux)

    Лексическая структура в Postgresql

    Анонимные функции

    Константы классов

    Подготовленные операторы

    dmesg

    Почтовые протоколы

    DNS

    Базовые понятие о настройках и безопасности в сети

    Шпаргалка php

    Использование awk Linux Alpine

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

    Изменить часовой пояс в Linux Alpine

    X Window System

    Отладка в php

    Логирование в postgresql

    Перенести кластер Postgresql-10 на Postgresql-12

    Наследование с помощью extends в php

    Применение getopt в Linux

    Переменные окружения в Linux

    Конфигурация Postgresql-12 для удаленного подключения

    tmpfs в Linux

    Введение в docker

    Возможности шифрования

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

    Команды IMAP в Linux

    Команды SMTP в Linux

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

    IP-телефония в компьютерных сетях

    Роли и атрибуты в Postgresql

    Memcached

    Конфигурация

    Создание и управление кластером postgresql

    Системные каталоги в Postgresql

    Обновление кластера Postgresql

    HTTP cookies

    Типы данных в php

    Переменные в php

    Объекты и ссылки

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

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

    Этапы запроса и получения результата в postgresql

    Проверка и восстановление файловой системы в Linux

    Настройка репликации в postgresql

    Полнотекстовый поиск в Postgresql

    Саздание сертификатов SSL (TLS) для сайта

    Командная оболочка Shell

    Анализ производительности виртуальной машины

    Операторы в php

    Мониторинг событий в linux с помощью auditd

    Создание RAID массивов

    Использование RAID массивов в Linux

    Конфигурация пула php-fpm

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

    Управляющие структуры

    Классы символов в Linux

    Настройка виртуального сервера Nginx

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

    Перечисления в php

    Абстрактные классы в php

    Оптимизация производительности Postgresql

    Интерфейсы объектов в php

    Подстановка имен файлов

    Конфигурация Postfix в Linux Alpine

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

    Стандартные потоки и перенаправление ввода/вывода в Linux

    Конструкторы и деструкторы в php

    Устройство и принцип работы Postgresql

    Подстановочные символы bash

    Файлы в Linux

    Функции в языке Shell

    Низкий уровень Postgresql

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

    Трейты в PHP

    Редактор vim

    Анализ дисковой активности

    Архивирование и сжатие файлов в Linux

    Константы в php

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

    Сценарии инициализации в Linux Ubuntu

    Константы в php

    Полезные команды и скрипты Linux

    Переменные в Linux

    foreach for do-while

    Менеджер пакетов RPM

    Использование регулярных выражений в Linux

    Стрелочные функции в php

    Область видимости в php

    Условная конструкция if в Linux

    Анонимные классы в PHP

    Разделы диска

    Выбор процессора

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

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

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

    Фигурные скобки в bash

    Конфигурация NFS Linux

    Выбор сервер для Postgresql

    Циклы в языке shell

    Использование оператора select в языке shell

    Внутренние и внешние команды linux

    Использование командной строки bash

    Полезные функции ООП в PHP

    Перезагрузка в php

    Использование конструкции case в Linux

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

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

    switch и match

    Полезные сетевые утилиты Linux

    Поиск уязвимостей в сети

    Свойства в php

    Настройка openvpn сервера в Linux

    Сравнение файлов в Linux

    Установка сервера Apache Linux Alpine

    Конфигурация Apache2 в Linux

    Конфигурация сети в Alpine Linux

    Compression and Decompression Nginx

    Функция declare в php

    Магические методы в PHP

    Базовые возможности Nginx

    Ограничение доступа http

    Мониторинг активности в Nginx

    Настройка ведения журнала Nginx и поиск ошибок

    include и require

    Сериализация

    openssl в Linux Alpine

    Работа с модулями в Linux

    Преодоление разрыва соединения

    Оператор goto в php

    Классы только для чтения

    Perf

    Мониторинг системы Linix с помощью getconf

    Comet сервер

    RDP в Linux

    Callable-объекты в php

    Ведение журнала системы

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

    Использование ANCI последовательностей в Linux

    Серверная пищалка beep

    Работа в командной строке Linux

    Подключение к серверу Postgresql

    Ковариантность и контравариантность

    Создание deb пакета в Linux Ubuntu

    Проблемный сертификат IdenTrust DST Root CA X3

    Команды POP3 в Linux

    Подключение по ключу (ssh)

    Ключевое слово Final

    Установка и настройка tftp сервера в Linux Ubuntu

    Тест производительности с помощью pgbench в postgresql

    Многоверсионность в Postgresql

    Изменение кодировки базы данных в Postgresql

    Клонирование объектов

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

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

    Блокировки в Postgresql

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

    Использование Glances для мониторинг в Linux

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

    Шаблоны в Symfony

    Конфигурация Symfony

    Маршруты в Symfony

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

    Исключения

    Введение в Symfony

    Компонент Yaml в Symfony

    Контроллеры в Symfony

    AssetMapper

    Отправка сообщения из Linux с помощью бота Telegram

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

    Создание, регистрация, аутентификация пользователя в Symfony

    Мониторинг Postgresql

    composer

    Databases and the Doctrine

    Виртуализация в Linux

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

    Терминальный мультиплексор

    Локализация в Linux

    Основные понятия devops

    NoSql

    Базовые настройки сети в Linux

    Docker Compose

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

    Авторизоваться
    Я буду рекламой
    Я тоже буду рекламой
    И я
    ВВЕРХ