Работа с командной строкой Linux & Shell скрипты для начинающих

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

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

Начнем.

Оглавление

  1. Минимальные требования

  2. Введение

  • Определение Bash-скрипта

  • Преимущества Bash-скриптов

  • Обзор оболочки Bash и интерфейса командной строки

3. Как начать работать с Bash-скриптами

4. Основы Bash скриптов

5. Циклы и ветвления в Bash

  • Цикл While

  • Цикл For

  • Оператор Case

6. Планирование сценариев с помощью Сron

7. Отладка и устранение неполадок Bash-скриптов

8. Заключение

Минимальные требования

Чтобы следовать этому руководству, необходимо иметь следующее:

Работающая версия Linux с доступом к командной строке.
Если у вас не установлен Linux или вы только начинаете его изучать, вы можете легко получить доступ к командной строке Linux через Replit. Replit — это браузерная IDE, в которой вы можете получить доступ к оболочке bash за несколько минут.

Вы также можете установить Linux поверх вашей системы Windows, используя WSL (подсистема Windows для Linux). Инструкция по ссылке.

Введение

Определение Bash-скрипта

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

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

Преимущества Bash-скриптов

Сценарии Bash — это мощный и универсальный инструмент для автоматизации задач системного администрирования, управления системными ресурсами и выполнения других рутинных задач в системах Unix/Linux. Некоторые преимущества сценариев оболочки:

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

  • Портативность: сценарии оболочки можно запускать на различных платформах и операционных системах, включая Unix, Linux, macOS и даже Windows, с помощью эмуляторов или виртуальных машин.

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

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

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

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

Обзор оболочки Bash и интерфейса командной строки

Термины «оболочка» и «bash» взаимозаменяемы. Но между ними есть тонкая разница.

Термин «оболочка» относится к программе, которая предоставляет интерфейс командной строки для взаимодействия с операционной системой. Bash (Bourne Again SHell) является одной из наиболее часто используемых оболочек Unix/Linux и является оболочкой по умолчанию во многих дистрибутивах Linux.

Интерфейс оболочки zsh или командной строки выглядит следующим образом:

Оболочка принимает команды от пользователя и отображает вывод
Оболочка принимает команды от пользователя и отображает вывод

В приведенном выше выводе clockber::~>> — это приглашение оболочки zsh. Когда оболочка используется в интерактивном режиме, в Linux она отображает $, когда ожидает команды от пользователя.

Если оболочка запущена от имени пользователя root (пользователь с правами администратора), приглашение меняется на #. Приглашение оболочки суперпользователя выглядит следующим образом:

[root@host ~]#

Хотя Bash — это тип оболочки, существуют и другие доступные оболочки, такие как оболочка Korn (ksh), оболочка C (csh) и оболочка Z (zsh). Каждая оболочка имеет свой собственный синтаксис и набор функций, но все они имеют общую цель — предоставить интерфейс командной строки для взаимодействия с операционной системой.

Вы можете определить свой тип оболочки с помощью команды ps:

ps

Пример вывода моего терминала:

Проверка типа оболочки. Я использую оболочку zsh
Проверка типа оболочки. Я использую оболочку zsh

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

Примечание: в этом руководстве мы будем использовать оболочку «bash».

Как начать работать с Bash-скриптами

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

[user@host ~]$

Вы можете ввести любую команду после знака $ и увидеть результат на терминале.

Как правило, команды имеют следующий синтаксис:

command [OPTIONS] arguments

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

  • date: отображает текущую дату

admin@user-new:/$ date
Sat 25 Mar 2023 14 12:04:17 PM MSK
  • pwd: Отображает текущий рабочий каталог.

admin@user-new:/usr/lib$ pwd
/usr/lib
  • ls: Выводит содержимое текущего каталога.

admin@user-new:/home$ ls
clockber
  • echo: Выводит на терминал строку текста или значение переменной.

admin@user-new:/home$ echo "Hello bash"
Hello bash

Вы всегда можете обратиться к руководству по командам с помощью команды man.

Например, руководство по echo выглядит примерно так:

Как создавать и выполнять сценарии Bash

Соглашения об именах сценариев

По соглашению об именах сценарии bash заканчиваются на .sh. Однако сценарии bash могут прекрасно работать без расширения sh.

Добавляем Шебанг(Shebang)

Скрипты Bash начинаются с шебанга. Шебанг(Shebang) — это комбинация bash # и bang ! за которым следует путь оболочки bash. Это первая строка скрипта. Шебанг говорит оболочке выполнить его через оболочку bash. Shebang — это просто абсолютный путь к интерпретатору bash.

Ниже приведен пример оператора шебанг.

#!/bin/bash

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

which bash

Наш первый bash-скрипт

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

Создайте файл с именем show_all.sh с помощью команды vi. Вы можете использовать любой редактор по вашему выбору.

vi show_all.sh

Добавьте следующие команды в свой файл и сохраните его:

#!/bin/bash
echo "сегодня " `date`

echo -e "\n введите путь к директории:"
read path_to

echo -e "\n ваша директория содержит файлы и папки:"
ls $path_to

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

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

#!/bin/bash
echo "Сегодня " `date`
  
echo -e "\n введите путь к директории:"
read path_to
  
echo -e "\n ваша директория содержит файлы и папки:"
ls $path_to
  • Строка #1: Шебанг (#!/bin/bash) указывает на путь к оболочке bash.

  • Строка #2: команда echo отображает текущую дату и время на терминале. Обратите внимание, что дата указана в обратных кавычках.

  • Строка #4: мы хотим, чтобы пользователь ввел правильный путь.Строка #5: Команда чтения считывает ввод и сохраняет его в переменной path_to.

  • строка #8: Команда lh берет переменную с сохраненным путем и отображает текущие файлы и папки.

Выполнение bash-скрипта

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

chmod u+x show_all.sh

Где,

  • chmod изменяет владельца файла для текущего пользователя u:.

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

  • show_all.sh — это файл, который мы хотим запустить.

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

  • sh show_all.sh

  • bash show_all.sh

  • ./show_all.sh

Давайте посмотрим, как он работает????

Основы Bash скриптов

Комментарии в сценариях bash

Комментарии начинаются с # в сценариях bash. Это означает, что любая строка, начинающаяся с #, является комментарием и будет игнорироваться интерпретатором.

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

Вот примеры комментариев:

# This is an example comment
# Можно комментить на русском
# These lines will be ignored by the interpreter

Переменные и типы данных в Bash

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

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

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

  1. Назначьте значение напрямую:

country=Russia

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

same_country=$country

Чтобы получить доступ к значению переменной, добавьте $ к имени переменной.

admin@user-new:/$ country=Russia
admin@user-new:/$ echo $country
Russia
admin@user-new:/$ new_country=$country
admin@user-new:/$ echo $new_country
Russia

Соглашения об именах переменных

В сценариях Bash следующие соглашения об именах переменных:

  1. Имена переменных должны начинаться с буквы или символа подчеркивания ().

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

  3. Имена переменных чувствительны к регистру.

  4. Имена переменных не должны содержать пробелов или специальных символов.

  5. Используйте описательные имена, отражающие назначение переменной.

  6. Избегайте использования зарезервированных ключевых слов, таких как if, then, else, fi и т. д., в качестве имен переменных.

Вот несколько примеров допустимых имен переменных в Bash:

name
count
_var
myVar
MY_VAR

А вот несколько примеров недопустимых имен переменных:

2ndvar (начинается с цифры)
my var (содержит пробел)
my-var (содержит дефис)

Соблюдение этих соглашений об именах помогает делать сценарии Bash более читабельными и простыми в использовании.

Ввод и вывод в Bash-скриптах

Обработка входных данных

В этом разделе мы обсудим некоторые методы ввода данных в наши сценарии.

  1. Чтение пользовательского ввода и сохранение его в переменной

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

#!/bin/bash

echo -e "\n Enter your name:"
read the_name

echo -e "\n welcome to Medium $the_name"

вывод:

2. Чтение из файла

Этот код считывает каждую строку из файла с именем input.txt и выводит ее на терминал. Мы изучим циклы while позже в этой статье.

while read line
do
  echo $line
done < input.txt

3. Аргументы командной строки

В скрипте или функции bash $1 обозначает переданный начальный аргумент, $2 обозначает переданный второй аргумент и так далее.

Этот сценарий принимает имя в качестве аргумента командной строки и печатает персонализированное приветствие.

echo "Hello, $1!"

Мы передаем скрипту clockber как аргумент.

#!/bin/bash
echo "Hello, $1!"

вывод:

Отображение вывода

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

  1. Печать в терминал:

echo "Hello, World!"

Этой командой напечатаем текст “Hello, World!” в терминале.

2. Запись в файл:

echo "let's write text." > output.txt

Эта команда запишет текст “let’s write text.” в файл с именем output.txt. Обратите внимание, что оператор > перезапишет файл, если в нем уже есть содержимое.

3. Добавление в файл:

echo "More text." >> output.txt

Добавляем текст “More text.” в конец файла output.txt.

4. Перенаправление вывода:

ls > files.txt

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

Основные команды Bash (echo, read и т. д.)

Вот список некоторых наиболее часто используемых команд bash:

  1. cd: Изменение директории на другую.

  2. ls: Отображение содержимого в текущей директории.

  3. mkdir: Создание новой директории.

  4. touch: Создать новый файл.

  5. rm: Удаление файла или директории.

  6. cp: Копирование файла или директории.

  7. mv: Перемещение или переименование файла или директории.

  8. echo: Печать текста в терминал.

  9. cat: Читает данные из файла и выводит их на экран.

  10. grep: Поиск в файлах.

  11. chmod: Изменение прав доступа к файлу или директории.

  12. sudo: Запуск команд с правами администратора.

  13. df: Отображение дискового пространства.

  14. history: Отображение истории предыдущих комманд.

  15. ps: Отображение информации о запущенных процессах.

Условные операторы (if/else)

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

Синтаксис:

if [[ condition ]];
then
 statement
elif [[ condition ]]; then
 statement 
else
 do this by default
fi

Можно использовать логические операторы, такие как AND -aи OR -o, чтобы делать сравнения, которые имеют большее значение.

if [ $a -gt 60 -a $b -lt 100 ]

Давайте рассмотрим пример сценария Bash, который использует операторы if, if-else, if-elif-else, чтобы определить, является ли введенное пользователем число положительным, отрицательным или нулевым:

#!/bin/bash

echo "Please enter a number: "
read num

if [ $num -gt 0 ]; then
  echo "$num is positive"
elif [ $num -lt 0 ]; then
  echo "$num is negative"
else
  echo "$num is zero"
fi

Сначала скрипт предлагает пользователю ввести число. Затем он использует оператор if, чтобы проверить, больше ли число, чем 0. Если это так, сценарий выводит, что число положительное. Если число не больше 0, скрипт переходит к следующему оператору, который является оператором if-elif. Здесь скрипт проверяет, меньше ли число 0. Если да, то скрипт выводит отрицательное число. Наконец, если число не больше 0 и не меньше 0, скрипт использует оператор else для вывода того, что число равно нулю.

Циклы и ветвление в Bash

Цикл While

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

В приведенном ниже примере (( i += 1 )) — это оператор счетчика, который увеличивает значение i. Цикл будет выполняться ровно 10 раз.

#!/bin/bash
i=1
while [[ $i -le 10 ]] ; do
   echo "$i"
  (( i += 1 ))
done

Цикл For

Цикл for, как и цикл while, позволяет выполнять операторы определенное количество раз. Каждый цикл отличается своим синтаксисом и использованием.

В приведенном ниже примере цикл повторяется 5 раз.

#!/bin/bash

for i in {1..5}
do
    echo $i
done

Оператор Case

В Bash операторы case используются для сравнения заданного значения со списком шаблонов и выполнения блока кода на основе первого совпавщего шаблона. Синтаксис оператора case в Bash следующий:

case expression in
    pattern1)
        # code to execute if expression matches pattern1
        ;;
    pattern2)
        # code to execute if expression matches pattern2
        ;;
    pattern3)
        # code to execute if expression matches pattern3
        ;;
    *)
        # code to execute if none of the above patterns match expression
        ;;
esac

Здесь expression— это значение, которое мы хотим сравнить, а pattern1, pattern2, pattern3 и т. д. — это шаблоны, с которыми мы хотим его сравнить.

Двойная точка с запятой “;;” отделяет каждый блок кода для выполнения для каждого шаблона. Звездочка “*” представляет случай по умолчанию, который выполняется, если ни один из указанных шаблонов не соответствует выражению.

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

fruit="apple"case in    "apple")        echo "This is a red fruit."        ;;    "banana")        echo "This is a yellow fruit."        ;;    "orange")        echo "This is an orange fruit."        ;;    *)        echo "Unknown fruit."        ;;esac

В данном примере, поскольку значение “fruit” является “apple”, чему соответствует первый шаблон и блок кода, следовательно в терминале мы увидем “This is a red fruit.”. Если бы значением “fruit” было “banana”, второй шаблон соответствовал бы и блоку кода, который повторяет “This is a yellow fruit.”. будет выполняться и так далее. Если значение “fruit”не соответствует ни одному из указанных шаблонов, выполняется случай по умолчанию, который повторяет “Unknown fruit.”.

Планирование сценариев с помощью Сron

Cron — мощная утилита для планирования заданий, доступная в Unix-подобных операционных системах. Настроив cron, вы можете настроить автоматические задания для запуска ежедневно, еженедельно, ежемесячно или в определенное время. Возможности автоматизации, предоставляемые cron, играют решающую роль в системном администрировании Linux.

Ниже приведен синтаксис для планирования crons:

# Cron job example* * * * * sh /path/to/script.sh

Здесь * представляют собой минуты (минуты), часы (часы), день (дни), месяцы и дни недели соответственно.

Ниже приведены несколько примеров планирования заданий cron.

schedule    description                                          example0 0 * * *   Run a script at midnight every day                   0 0 * * * /path/to/script.sh*/5 * * * * Run a script every 5 minutes                         */5 * * * * /path/to/script.sh0 6 * * 1-5 Run a script at 6 am from Monday  to Friday          0 6 * * 1-5 /path/to/script.sh0 0 1-7 * * Run a script on the first 7 days of every month      0 0 1-7 * * /path/to/script.sh0 12 1 * *  Run a script on the first day of every month at noon

Использование crontab
Утилита crontab используется для добавления и редактирования заданий cron.

crontab -l перечисляет уже запланированные сценарии для конкретного пользователя.

Вы можете добавлять и редактировать cron через crontab -e.

Вы можете прочитать больше о работе с Cron здесь.

Как отлаживать и устранять неполадки Bash-скриптов

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

Установите параметр set -x

Один из наиболее полезных способов отладки сценариев Bash — установка параметра set -x в начале сценария. Эта опция включает режим отладки, в котором Bash печатает каждую команду, которую он выполняет, на терминал, перед которой ставится знак +. Это может быть невероятно полезно для определения того, где в сценарии возникают ошибки.

#!/bin/bashset -x# Your script goes here

Проверьте код выхода

Когда Bash обнаруживает ошибку, он устанавливает код выхода, который указывает характер ошибки. Вы можете проверить код выхода самой последней команды, используя $? переменная. Значение 0 указывает на успех, а любое другое значение указывает на ошибку.

#!/bin/bash# Your script goes hereif [ $? -ne 0 ]; then    echo "Error occurred."fi

Используйте операторы echo

Другой полезный метод отладки скриптов Bash — вставка echo-оператора в ваш код. Это может помочь вам определить, где возникают ошибки и какие значения передаются в переменные.

#!/bin/bash# Your script goes hereecho "Value of variable x is: " class="formula inline">x"# More code goes here

Используйте опцию set -e

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

#!/bin/bashset -e# Your script goes here

Устранение неполадок Cron путем проверки log журналов

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

Для Ubuntu/Debian вы можете найти cronlogs по адресу:

/var/log/syslog

Расположение отличается для других дистрибутивов.

Файл журнала заданий cron может выглядеть следующим образом:

2022-03-11 00:00:01 Task started2022-03-11 00:00:02 Running script /path/to/script.sh2022-03-11 00:00:03 Script completed successfully2022-03-11 00:05:01 Task started2022-03-11 00:05:02 Running script /path/to/script.sh2022-03-11 00:05:03 Error: unable to connect to database2022-03-11 00:05:03 Script exited with error code 12022-03-11 00:10:01 Task started2022-03-11 00:10:02 Running script /path/to/script.sh2022-03-11 00:10:03 Script completed successfully

Заключение

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

Надеюсь вся вышеперечисленная информация вам помогла :)

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


  1. DikSoft
    00.00.0000 00:00
    +2

    Как понять, что команда вернула значение соответствующее ответу "да"?

    Ведь это может быть: "True", "Yes", "LONG_TRUE_COMMAND_KEY_YES" , "1" , ...

    Изучать генеалогию тараканов и травмы детства автора команды? Если вариант, что будет хоть какой-то стандарт, или всё, поезд ушёл, принять и страдать?


    1. iig
      00.00.0000 00:00

      Как понять, что команда вернула значение соответствующее ответу "да"?

      Читать маны, они рулез

      Например , команда ps вывалила 2 экрана текста. Это "да" или "нет"?


      1. DikSoft
        00.00.0000 00:00
        +1

        Читать маны, они рулез

        Я именно про это и пишу. У каждого своё видение "как оно должно быть" Зоопарк несогласованный в итоге. И это только вершина айсберга. Что творится в config файлах - психушка отдыхает. Креатив через край. Что по словарю, что по оформлению и отступам.

        В том же PowerShell нет проблемы понять, что возвращается $true или $false. А здесь я обязан сходить и понять логику каждого "художника, который так видит"?

        PS Это не к тому, что "всё тут отстой", а к тому, что рассказывая про преимущества и мощь, стоит таки упомянуть о тяжёлом наследии из-за длинной истории развития, и что так вот сложилось, запоминать и принимать "как есть" придётся очень многое.


        1. rsashka
          00.00.0000 00:00
          +1

          Вот только не нужно про PowerShell


          1. DikSoft
            00.00.0000 00:00

            Всё с этим нормально у PowerShell. Да/Нет всегда одинаково пишутся.
            И как минимум не надо голову ломать, вспоминая слолько символов "-" перед какой фразой в ключах ставить один/два/ни одного )


            1. rsashka
              00.00.0000 00:00
              +2

              А причем тут bash, если это зависит от конкретного приложения?


              1. DikSoft
                00.00.0000 00:00
                +1

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


                1. saboteur_kiev
                  00.00.0000 00:00
                  +1

                  ВСЕ команды в posix (и не только) возвращают код возврата 0, что означает success. А дальше - смотрим как эту команду юзать, чтобы ею что-то именно проверитьт


        1. randomsimplenumber
          00.00.0000 00:00
          +2

          В том же PowerShell нет проблемы понять, что возвращается $true или $false.

          Возвращается значение откуда? Если из внешней программы - то при чём тут bash/powershell? Если из своей функции - ну, договоритесь там как то с собой, что вы будете возвращать;)


    1. Nalivai
      00.00.0000 00:00
      +3

      Можно спросить код выхода последней команды, $?

      Там стандарт, там 0 это "да"


      1. iig
        00.00.0000 00:00
        -1

        0 - это, как правило, отсутствие ошибки (в С/С++ наоборот) . А как вы его собираетесь интерпретировать - "да", "нет", BLACK_COLOR - от логики работы вашего скрипта зависит.


        1. tzlom
          00.00.0000 00:00
          +3

          в С/С++ обычно 0 это тоже отсутствие ошибки а остальное - коды ошибок


          1. iig
            00.00.0000 00:00

            Да, с true/false немного перепутал ;)


      1. saboteur_kiev
        00.00.0000 00:00

        это проблема того, что автор статьи терминологией владеет плохо.
        0 = true
        не ноль - false

        с этим работают конструкции в шелл скриптах ( &&, ||, if)


    1. Thomas_Hanniball
      00.00.0000 00:00
      +1

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


      Наличие удобного инструмента (Ansible), позволяет абстрагироваться от более низкого уровня (shell команды) и позволяет экономить огромное количество времени и избавляет от необходимости читать man по каждой отдельной shell команде.


      1. DikSoft
        00.00.0000 00:00

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


  1. ZvaroG
    00.00.0000 00:00

    Я сейчас изучаю про bash и по bash полно документации и достаточно хорошей. Проблема в том что сам bash жуткое старьё. Стал искать альтернативу. Остановился на zsh - который стандарт на osx.

    Я смотрю вы используете zsh. Мне кажется более актуально написать не очередную статью о bash, а от том как перейти с bash на zsh т.е. пример на bash -> Пример на zsh.


    1. kon_ov Автор
      00.00.0000 00:00

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


    1. saboteur_kiev
      00.00.0000 00:00

      Последняя стабильная версия bash - декабрь 2022. Последняя стабильная версия zsh - июль 2022. Какое старье?
      Может вы не видите разницы между POSIX и свои фичи?


  1. saboteur_kiev
    00.00.0000 00:00
    +21

    Куча неточностей и непонимания на глубоком уровне как все работает.

    1. В тексте - " в Linux она отображает $, когда ожидает команды от пользователя. ",
      а на скриншоте вместо $ у вас ">>". Почему несоответствие?

    2. "Это первая строка скрипта. Шебанг говорит оболочке выполнить его через оболочку bash"
      Ничего шебанг не говорит оболочке. Для оболочки это просто комментарий.

    3. "command [OPTIONS] arguments"
      Неправильно. Правильно будет "command [ARGUMENTS]".
      А вот ARGUMENTS уже могут быть или [OPTIONS] или [PARAMETERS], и те и другие - опциональны в зависимости от команды

    4. В примере "echo "сегодня " `date`"
      В современном мире используют $(), а не ``. И вообще сразу использовать command substitute, просто сказав "обратите внимание, что date нужно указать в кавычках и не пояснив а что собственно происходит?

    5. "sh show_all.sh"
      при этом может оказаться что некоторые баш конструкции выдадут ошибку, потому что ниже у вас есть примеры и [] и [[]]

    6. Пишете "В Bash нет типов данных. В Bash переменная может хранить числовые значения, отдельные символы или строки символов. "
      Но это неправильно. В bash есть типы данных, но баш не строго типизированный язык, поэтому тип данных легко конвертируется в другой, при этом могут быть потери, когда попытаетесь текст конвертнуть в integer. Плюс есть массивы.

    7. "touch: Создать новый файл."
      Вообще-то touch был создан для другого, это побочный эффект, что при попытке открыть несуществующий файл, создается пустой файл. Так можно сказать, что и "echo" это команда для создания новых файлов

    8. if [[ condition ]]; then
      Неправильно. Правильно if EXPRESSION; then...

    9. Вдобавок тут же несколько строк ниже у вас "if [ $num -gt 0 ]; then". Куда пропали двойные квадратные скобки? Почему показывая пример синтаксиса у вас одно одно, а в примере использования чуть ниже - другое? Что будет думать новичок?

    10. В примере с циклом у вас "(( i += 1 ))" - это что такое? Куда доллар пропал? Правильно "$(( i+=1 ))"

    11. "case expression in" А тут уже ошибка наоборот. Тут как раз должно быть не expression, а конкретное значение. Да, его можно создать, но expression может быть например просто выполнение команды, результатом которой может быть просто exit code с пустым output, и что тогда?

    12. И тут же в примере ниже куда-то форматирование пропало:
      fruit="apple"case in "apple") echo "This is a red fruit." ;; "banana") echo "This is a yellow fruit." ;; "orange") echo "This is an orange fruit." ;; *) echo "Unknown fruit." ;;esac

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

    13. "используя $? переменная." - опечатка

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


    1. uvelichitel
      00.00.0000 00:00
      -1

      По моему, и такие посты полезны и имеют право на существование)
      Поставил себе основной оболочкой KornShell, конкретно mksh из MirBSD. Потому что понравилась (ну и для разнообразия). Об man MKSH(1) поломал мозг).
      @saboteur_kiev, может быть, подскажете хороший гайд по KornShell (на английском пойдёт)


      1. mc2
        00.00.0000 00:00

        У O'Reilly есть книжка Learning the Korn Shell.


      1. saboteur_kiev
        00.00.0000 00:00

        ну есть же официальная документация на http://www.kornshell.com/doc/.
        Но я бы не советовал переходить на ksh, потому что его разработка заброшена более 10 лет назад...


        1. uvelichitel
          00.00.0000 00:00

          Попробовать ksh сподвигли рекоммендации suckless.org, которые для меня авторитетны) Конкретно mksh живёт и поддерживается, последний commit датирован прошлой неделей https://github.com/MirBSD/mksh И, пожалуй, ksh более Posix shell compliant нежели bash)

          В целом то я к mksh приноровился и научился использовать достоинства. И, даже, поддерживаю собственный форк)
          Но постижение через штудирование man отняло несуразно много времени и сил. В man, да и http://www.kornshell.com/doc информация подаётся в чрезвычайно сжатом виде. Поэтому и повторюсь, гайды и туториалы, пусть и не настолько формально точные и компактные как man, имеют право на существование)


          1. saboteur_kiev
            00.00.0000 00:00

            за исключением конструкции [[ ]], я не особо припоминаю какие башизмы я использовал в баш.
            Возможно что-то из variable expansion, но в принципе можно просто писать Posix compliant скрипты и выполнять их в любом подходящем шелле, в этом смысле разницы между ksh или bash или zsh вы не заметите.
            То есть нет особого смысла переходить на ksh, если вы используете глобальный стандарт.

            man не самый удачный вариант, да. Там часто критически не хватает информации и примеров.
            Можно изучить https://www.tutorialspoint.com/index.htm и полезные gnu тулзы типа sed/awk/grep с регулярками на более продвинутом уровне, и в принципе этого может быть достаточно с головой.
            Еще немного поковырять скрипты bash completion, и в принципе можно будет считать себя гуру шелл скриптов


    1. invasy
      00.00.0000 00:00
      +1

      В пункте 10 всё же не ошибка. Конструкция (( expr )) вполне допустима: вычисляется арифметическое выражение внутри скобок. Но не выполняется постановка значения, только устанавливается код ошибки/возврата $?: 0, если результат вычислений ненулевой; 1, если результат 0 (вот такая не очень очевидная, но ожидаемая логика).


    1. nickinit
      00.00.0000 00:00
      -1

      Ничего шебанг не говорит оболочке. Для оболочки это просто комментарий.

      не могу с этим согласиться: если вызываешь скрипт как bash script.sh - то вероятно так оно и будет, но, если вызов идёт из текущей оболочки ./script.sh, то в этой строке будет задан интерпретатор. Небольшой пример:

      #!/usr/bin/python3
      
      print(123)
      

      При выполнении ./script.sh с данным содержимым, программа напечатает 123


      1. saboteur_kiev
        00.00.0000 00:00
        +1

        Так а что запускается, когда ты делаешь так?
        ./script.sh

        То есть ты считаешь, что когда ты пишешь в консоли ./script.sh, это оболочка его открывает и считывает шебанг?
        Или ядро линукса открывает executable файл, считывает сигнатуру, видит что это сигнатура скрипта и согласно правилу считывает интерпретатор.
        Ведь executable файл может быть например elf, а не шелл скрипт.


  1. invasy
    00.00.0000 00:00

    del


  1. Berserkr
    00.00.0000 00:00
    +1

    Забыли 0 пункт: Никогда не программируйте на bash


    1. saboteur_kiev
      00.00.0000 00:00
      +1

      почему это вдруг? отличный универсальный язык автоматизации


      1. AlexanderAstafiev
        00.00.0000 00:00
        -1

        Отличный универсальный язык автоматизации это Python


        1. DikSoft
          00.00.0000 00:00
          -1

          Отличный универсальный язык автоматизации это PowerShell )


          1. tzlom
            00.00.0000 00:00

            Он нигде не работает )



          1. saboteur_kiev
            00.00.0000 00:00

            он как раз не универсальный


        1. randomsimplenumber
          00.00.0000 00:00

          Напишите на python скрипт для автоматического переименования файлов по шаблону, например. На bash это 1 недлинная строка.

          Ну да, пробелы, спецсимволы, экранирование.. ;)


        1. tzlom
          00.00.0000 00:00

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


          1. randomsimplenumber
            00.00.0000 00:00

            Странно, документация вроде на уровне, и отладчик встроенный.


            1. tzlom
              00.00.0000 00:00

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

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


              1. randomsimplenumber
                00.00.0000 00:00

                Тут что-то по программистски, не смог разобрать ;) В документации как раз возвращаемые значения указаны. Если код писать не в блокноте, а в IDE - с типами будет проще.


              1. iig
                00.00.0000 00:00

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

                Really? Навскидку:

                "os.environ

                A mapping object representing the string environment. For example, environ['HOME'] is the pathname of your home directory (on some platforms), and is equivalent to getenv("HOME") in C."

                Вроде как вполне понятно, что именно возвращается. Некоторые модули, конечно, бывают с отвратительной документацией.. Но это к python не относится же? ;)


                1. tzlom
                  00.00.0000 00:00

                  что согласно документации вернет type(os.times()) ?


                  1. iig
                    00.00.0000 00:00

                    Сеанс чтения манов вслух с выражением :) </s>

                    Обьект с 5 атрибутами?

                    Да

                    os.times()
                    Out[116]: posix.times_result(user=651.58, system=163.65, children_user=0.9, children_system=2.57, elapsed=17739271.21)

                    Или кортеж из 5 элементов?

                    Тоже да

                    user, system, children_user, children_system, elapsed = os.times()
                    user
                    Out[118]: 651.79

                    Да, это python, можно и так и так ;)


                    1. tzlom
                      00.00.0000 00:00

                      ну тут вы лукавите, мы оба знаем что times_result в доке не описан вообще, а ответ вы получили запустив код

                      https://docs.python.org/3/search.html?q=times_result

                      ну и если бы вы действительно читали то знали бы что type() всегда возвращает class, а не объект или кортеж


                      1. iig
                        00.00.0000 00:00

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

                        Hidden text

                        А что это отдельный класс со специальным именем - не знал. Можно и так:

                        type(os.times())
                        Out[128]: posix.times_result
                        import posix
                        help(posix.times_result)

                        Python с собой тащит свою документацию - можно и так. Странно, конечно, что локальный help отличается от официального сайта.


        1. saboteur_kiev
          00.00.0000 00:00

          Который нужно постоянно ставить
          В котором нужно постоянно что-то доустанавливать
          В котором случился питон2 vs питон3, а вот скрипт на посикс шелле заработает на машине 20летней давности и 20 лет спустя без проблем
          Который совсем не так прост для манипулирования внешними утилитами


          1. randomsimplenumber
            00.00.0000 00:00

            Который нужно постоянно ставить

            Не более чем 1 раз ;)

            В котором нужно постоянно что-то доустанавливать

            Хм ;) Не чаще чем 1 раз

            питон2 vs питон3

            sh vs bash ;)

            скрипт на посикс шелле заработает на машине 20летней давности и 20 лет спустя без проблем

            Кроме самого sh, нужно чтобы утилиты, к которым он взывает, тоже за 20 лет не поменялись. Сможете это гарантировать?

            Который совсем не так прост для манипулирования внешними утилитами

            Но и сложностей особых нет.


            1. saboteur_kiev
              00.00.0000 00:00

              На каждой машине нужно ставить по разу. А если машин много, а если продакшен, а потом подерживать одинаковую версионность.

              скрипты на sh отлично работают в bash и наоборот, если соблюдать posix стандарт

              Утилиты, которые вы вызываете из скриптов - это обычный набор gnu tools
              И есть POSIX, если его соблюдать при написании, то да - 20 лет назад, 20 лет вперед - будет работать.


              1. randomsimplenumber
                00.00.0000 00:00

                На каждой машине нужно ставить по разу. А если машин много, а если продакшен, а потом подерживать одинаковую версионность.

                Для этого случая есть специальная сисадминская магия ;)

                скрипты на sh отлично работают в bash и наоборот,

                Если не использовать башизмов. Если не использовать башизмов - зачем нужен bash? ;)


  1. dinisoft
    00.00.0000 00:00
    +4

    Основные команды bash, которые никак к нему не относятся? Даже не читал дальше, т.к. ls, pwd и т.д. из списка, это не команды оболочки, а отдельные программы.


  1. pae174
    00.00.0000 00:00

    Планирование сценариев с помощью Сron

    Здесь критически важно проверить PATH, с которым работает cron. Это потому что PATH при интерактивном использовании bash и PATH при запуске из cron очень даже могут быть разными, что в комбинации с привычкой забивать на обработку ошибок может приводить к весьма плачевным результатам. Ещё имеет смысл убедиться в том, что вы получаете почту на которую cron будет потом присылать вам отчеты по этим вот скриптам.

    Вы можете прочитать больше о работе с Cron здесь.

    Здесь должна быть ссылка но её нет.


  1. guvernir4
    00.00.0000 00:00

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


    1. saboteur_kiev
      00.00.0000 00:00

      смотря где.
      Если вы про оператор test - то нужно понимать почему.
      если вы про определение массива или command substitution - то не обязательно.


  1. grossws
    00.00.0000 00:00

    Последнее время всё больше пишу скрипты под zsh (ибо там есть приятности типа zparseopts) когда могу себе позволить. Естественно на целевых машинах zsh в этом случае раскрывается ansible вместе со всякими полезными утилитами типа. htop/iotop/iostat/iftop/lsof/etc.

    Когда не получается, то приходится целиться на ash/sh, т.к. в тех условиях bash может просто отсутствовать. А если можно ставить пакеты, то 7MiB на zsh не жалко.

    И новичкам, и опытным собаководам крайне рекомендую взять на вооружение shellcheck, невнимательность и некоторое количество corner cases он ловит.

    Ну и set -euo pipefail тоже хорошее подспорье, особенно против опечаток в именах переменных.