1. - [x] [Bash Special Characters and Quoting](https://www.oreilly.com/library/view/learning-the-bash/1565923472/ch01s09.html)






---

[Терминал](../1.3.0%20Terminal.md) предоставляет визуальный интерфейс ([GUI](https://github.com/eldaroid/iTWiki/blob/master/5%20Swift/5.2%20Glossary.md#gui)) для ввода и отображения команд оболочки (шеллов/shells). 

"Shell" - это программа, которая облегчает взаимодействие между пользователем и операционной системой (ядром). Служит интерфейсом между пользователем и [ядром](/2%20ComputerScience/2.0%20Linux/2.0.2%20Processor(CPU).md), который изолирует пользователя от сложности функций ядра.

Наиболее популярными являются [sh (Bourne shell)](https://www.ibm.com/docs/en/aix/7.1?topic=s-sh-command), [bash](https://www.gnu.org/software/bash/), [zsh](https://www.zsh.org/), [fish](https://fishshell.com/).


## Классификация сессий оболочки shell

> ❗ Bourne shell (sh) не реализует опцию -l для запуска в режиме login shell. Все нижеприведенное относится к bash

### Классификация по авторизации (стартовая vs. дочерняя)

| Тип сессии | Описание | Читаемые файлы конфигурации | Примеры |
|---|---|---|---|
| **Стартовая (login)** | Первичный запуск авторизации пользователя (терминал или SSH) для оболочки при входе в систему | Системный: `/etc/profile`<br>Пользовательский: `~/.bash_profile`, `~/.bash_login` или `~/.profile` +  при завершении оболочки `~/.bash_logout` | Первый вход в систему через консоль/SSH или запуск`exec $SHELL --login` |
| **Дочерняя (non-login)**| Запускается из уже авторизованной оболочки без повторной авторизации. | Системный: `/etc/bash.bashrc`<br>Пользовательский: [~/.bashrc](/1%20Common/1.1%20Configs/1.1.4%20bashrc.md) | Запуск новой bash-сессии из активного терминала |

### Классификация по интерактивности

| Тип сессии | Описание | Читаемые файлы конфигурации | Примеры |
|---|---|---|---|
| **Интерактивная** | Любой экземпляр командной оболочки, запущенный пользователем непосредственно | /etc/bashrc и [~/.bashrc](/1%20Common/1.1%20Configs/1.1.4%20bashrc.md) | сессия, привязанная к терминалу |
| **Неинтерактивная** | Оболочка, которая не может взаимодействовать с пользователем / используется для скриптов, когда команды считываются из файла, а не вводятся пользователям | source $BASH_ENV | сессия, не привязанная к терминалу |

![ShellsInvokes](/pictures/Common/ShellsInvokes2.png?raw=true)

> ❗ **Терминальная сессия** – это различные комбинации этих двух свойств.
> 
> Обычная сессия, открытая с помощью SSH, как правило, является **интерактивной стартовой сессией**
> 
> **Скрипт**, запущенный через командную строку, обычно работает в **неинтерактивной дочерней сессии** 

Если вы хотите автоматически запускать команды из [~/.bashrc](/1%20Common/1.1%20Configs/1.1.4%20bashrc.md) при входе в систему, то внутри`~/.bash_profile` нужно добавить команду для включения в него файла [~/.bashrc](/1%20Common/1.1%20Configs/1.1.4%20bashrc.md): `test -f ~/.bashrc && source ~/.bashrc`

Проверить в интерактивной или неинтерактивной оболочке с помощью: `[[ $- == *i* ]] && echo 'Interactive' || echo 'not-interactive'`

Проверить в login или non-login: [[ -o login ]] && echo "login" || echo "not-login"

### Задачка со звездочкой

-> /bin/bash -l
-> Popov-MacBook-Pro$ echo $SHELL
/bin/zsh

Почему несмотря на то что мы зашли в bash, то оболочка все еще zsh?

## Bash (поверх sh)

Bash: “Bourne again shell”. Есть много оболочек, которые могут выполнять команды UNIX, и та, которая используется в терминале Mac - Bash.
Она была создана Брайаном Фоксом для операционной системы GNU и является альтернативой [Bourne Shell (sh)](https://www.ibm.com/docs/en/aix/7.1?topic=s-sh-command).


> Bash имеет обратную совместимость с sh, тк Bash включает все возможности стандартного sh и дополнительно расширяет его (н/р, расширенный синтаксис условных операторов, массивы и другие bash-расширения). Но bash скрипты могут не запускаться или отрабатывать некорректно c sh


### Базовые скрипты

Пример скрипта в терминале:

```console
➜  mcd() {
mkdir -p "$1"
cd "$1"
}
➜  mcd testFolder
➜  testFolder 
```

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

`vim python.sh` -> Enter script -> `chmod +x python.sh` -> `./python.sh`

```console
➜  cat python.py 
#!/usr/bin/python3
print("hello")
```


> #! - [Шебанг](https://ru.wikipedia.org/wiki/Шебанг_(Unix)) указывает на выполнение бинарного файла из этой директории ([/bin](/2%20ComputerScience/2.0%20Linux/2.0.3%20FileSystemLinux.md)). Н/р: `#!/usr/bin/env python3`

Для проверки где происходит исполнение скрипта на нужном нам языке, пишем `which (название языка/команды)`. [Ссылка](../1.3.1%20DeepDiveInTerminal.md) с более глубоким пониманием команд which/whereis/type:

![](/pictures/Common/DeepDiveInTerminal.png?raw=true)

Чтобы дать права на исполнение созданному файлу нужно написать команду [chmod +x (название файла)](./1.3.3.3%20Chmod.md)

### Запуск скрипта

* `./` запускает скрипт **как отдельную программу** с интерпретатором, указанным в шебанге (или если шебанга нет, то возникнет ошибка);
* `source` или `.` выполняет скрипт **в текущем процессе** оболочки, не требуя прав на выполнение, и изменения в нем сохраняются в текущей оболочке;
* `sh` выполняет скрипт **в новом процессе** с использованием интерпретатора, ассоциированного с командой sh, игнорируя шебанг;



### Отладка скриптов

Из-за сложных правил обработки пробелов и кавычек сложно понять, как произошла ошибка. 

Для решения этой проблемы обычно в начало скрипта добавляют опцию `set -x` или аргумент в [шебанг](https://ru.wikipedia.org/wiki/Шебанг_(Unix)) `#!/usr/bin/env bash -x`. 

После включения `-x` опции оболочка будет **выводить каждую команду**, которую она запускает со списком фактических аргументов (с раскрытыми подстановками переменных и т.п.). 


Также для скриптов полезна опция `set -e` или аргумент в [шебанг](https://ru.wikipedia.org/wiki/Шебанг_(Unix)) `#!/usr/bin/env bash -e`, которая **остановит выполнение скрипта**, как только какая-либо команда **вернет ненулевое значение**.



### Операторы

Таблица операторов:

| Cимвол | Значение |
| ------------- |------------------|
| ~ | Домашняя директория |
| # | Коммент |
| $ | Переменные выражения |
| & | Фоновая задача |
| () | Вызов subshell внутри скобок |
| | | Или |
| ! | Логическое нет |
| '' | Строгое цитирование текста. `echo 'Hatter\'s tea party'` выведет `Hatter's tea party` |
| "" | Слабое цитирование - командная строка может выполнять некоторые операторы внутри. `echo "Hatter\'s tea party"` выведет `Hatter's tea party` |
| \ | Цитируй следующий символ. \* равносильно '*' |
| < | Перенаправление ввода |
| > | Перенаправление вывода |

### Аргументы $:

```bash
➜  print_args() {
echo $0 # — имя текущего скрипта.
echo $1 # - первый переданный аргумент функции. $2...$n
echo $_ # — последняя аргумент последней команды.
echo $@ # - показать все аргументы
echo $# # - показать количество аргументов
echo $$ # - показать PID (process ID)
echo $? # — статус выхода последней выполненной команды
}
```
Вывод:
```console
➜  print_args 1 2 3 4 helloWorld!
print_args
1
1 2 3 4 helloWorld!
5
877
0
```

### Сравнение

![Photo](/pictures/Common/BashComparison.png?raw=true)

`[20 -eq 20]` = true

#### Переменные выражения

Output_1: Hello to 

```bash
NAME=${1}
echo "Hello to $NAME"
```

---

Output_2: Error: no name given

```bash
NAME=${1?Error: no name given}
echo "Hello to $NAME"
```

---

Output_3: Hello to ME

```bash
NAME=${1:-ME}
echo "Hello to $NAME"
```

---

#### Ввод с консоли

```bash
echo "Enter your name"
read name
echo "Hello, $name"
```

name - переменная присваемая введенном тексту из консоли после исполнения файла и вывода "Enter your name".

---

[1.3.2 Text Editors Folder](../1.3.2%20TextEditors/) | [Back To iTWiki Contents](https://github.com/eldaroid/iTWiki) |  [1.3.3.2 Link Theme](./1.3.3.2%20Link(ln).md)
