Bash

Bash общая информация

Консоль работает с текстом, поэтому центральная задача - обработка текста.

echo Просто выводит строку
printf

Выводит строку с модификаторами 

printf "%s %d" "ff" 22

Поиск приложения: whereis name

~ - домашняя директория, ~sergey домашняя директория пользователя sergey

cd без аргументов в домашнюю, cd - в предыдущую

Маски для ls 

? один символ
* много символов
[set]

Набор символов, в данном случае s,e,t 

[a-c] a,b,c

[!0-9] где нет цифр

{}

перечисляются наборы текста, например echo f{io,am} 

Утилиты фильтрации текста

cat

перенаправление ввода на вывод

-b - нумеровать только непустые строки;
-E - показывать символ $ в конце каждой строки;
-n - нумеровать все строки;
-s - удалять пустые повторяющиеся строки

cat file1 file2 > file3

grep

поиск строк во вводе

Может анализировать один файл или директорию.

-e несколько регулярных выражений, например -e ... -e ...

-n номер строки, где найдено совпадение

-i, --ignore-case - не учитывать регистр символов;
-v, --invert-match - вывести только те строки, в которых шаблон поиска не найден;
-w, --word-regexp - искать шаблон как слово, отделенное пробелами или другими знаками препинания;
-x, --line-regexp - искать шаблон как целую строку, от начала и до символа перевода строки;
-c - вывести количество найденных строк;
-L, --files-without-match - выводить только имена файлов, будут выведены все файлы в которых выполняется поиск;
-l, --files-with-match - аналогично предыдущему, но будут выведены только файлы, в которых есть хотя бы одно вхождение;
-m, --max-count - остановить поиск после того как будет найдено указанное количество строк;
-o, --only-matching - отображать только совпавшую часть, вместо отображения всей строки;
-h, --no-filename - не выводить имя файла;
-s, --no-messages - не выводить ошибки чтения файлов;
-A, --after-content - показать вхождение и n строк после него; Те -A2 строка + 2 строки после
-B, --before-content - показать вхождение и n строк перед ним;
-C - показать n строк до и после вхождения;
-a, --text - обрабатывать двоичные файлы как текст;
--exclude - пропустить файлы имена которых соответствуют регулярному выражению;
--exclude-dir - пропустить все файлы в указанной директории;
-I - пропускать двоичные файлы;
--include - искать только в файлах, имена которых соответствуют регулярному выражению;
-r - рекурсивный поиск по всем подпапкам;
-R - рекурсивный поиск включая ссылки;

grep -r "поисковой_запрос" /путь/к/директории/

 

 

sort

сортировка строк

-b - не учитывать пробелы
-d - использовать для сортировки только буквы и цифры
-i - сортировать только по ASCII символах
-n - сортировка строк linux по числовому значению
-r - сортировать в обратном порядке
-o - вывести результат в файл
-u - игнорировать повторяющиеся строки
-m - объединение ранее отсортированных файлов
-k - указать столбец по которому нужно сортировать строки, если не задано, сортировка выполняется по всей строке.

ls -l | sort -k9
-f - использовать в качестве разделителя полей ваш символ вместо пробела.

uniq f1 > f2

Удаляет повторяющиеся строки

cut

извлечение символов из ввода

-b 2-6, 8 отобразит символы от 2 по 6 из строки и 8

-b 5- символы с 5 до конца

-с нечто похожее на -b

-d ':' -f 1,3 считать разделителем : и оставить первый и третий столбцы

sed

операции изменения данных перед выводом

Позволяет вырезать строки, поиск/замена по регулярке, вывод. Крутая штука.

tr

транслирование символов на вводе в другие символы

-d набор - удаление символов

    tr -d '0-9'

-s заменяет последовательность повторяющихся символов в SET1 на один такой символ;

    tr -s ' ' заменит много пробелов на один

head -n кол-во Выводит первые кол-во строк
awk

Считывает построчно данные, выполняет действия и выводит в stdout. Включает целый язык для обработки текста.

awk опции 'условие {действие} условие {действие}'

Опции:

-F, --field-separator - разделитель полей, используется для разбиения текста на колонки;
-f, --file - прочитать данные не из стандартного вывода, а из файла;
-v, --assign - присвоить значение переменной, например foo=bar;
-b, --characters-as-bytes - считать все символы однобайтовыми;
-d, --dump-variables - вывести значения всех переменных awk по умолчанию;
-D, --debug - режим отладки, позволяет вводить команды интерактивно с клавиатуры;
-e, --source - выполнить указанный код на языке awk;
-o, --pretty-print - вывести результат работы программы в файл;

Действия:

print(строка) - вывод чего либо в стандартный поток вывода;
printf(строка) - форматированный вывод в стандартный поток вывода;
system(команда) - выполняет команду в системе;
length(строка) - возвращает длину строки;
substr(строка, старт, количество) - обрезает строку и возвращает результат;
tolower(строка) - переводит строку в нижний регистр;
toupper(строка) - переводить строку в верхний регистр.

 

Переменные:

$NF - последняя строка

$(NF-1) - предпоследняя

NR - количество строк с начала

 

awk -F":" '{print $4}' Возьмет строку и по разделителю : выведет 4 элемент

Поддерживает регулярные выражения

echo -e 'one 1\n two 2' | awk '{sum+=$2} END {print sum}' сумма элементов.

awk 'NR < 10' log.txt

sed

Тоже очень крутая штука, этим двум командам посвящена целая книга.

diff file1 file2

Различие в строках

ndiff

Различие в результатах сканирования nmap 

${BIN_PATH}ndiff $BASE_RESULTS $NEW_RESULTS > $NDIFF_RESULTS
jq

Утилита для анализа JSON.

jq -r '.first' возвращает значение ключа first

jq '.[0].plugins.HTTPServer.string[0] определяет следующий элемент: 

 

[
  {
    "plugins": {
      "HTTPServer": {
        "string": [
          "Werkzeug/3.0.1 Python/3.12.3"
        ]
      }
    }
  }
]
tail -F filename

Отображения изменения в файле

wget

Загрузка файлов

-q тихий режим

-r рекурсивное скачивание

-np скачивание файлов из данной директории или ниже

-R "index.html" исключить загрузку файлов вида index.html

-P foldername директория сохранения

curl

Must have.

-s тихий режим

-X GET|POST|PUT|DELETE → явный выбор метода

-d "param=value" → данные формы (POST)

curl -X POST -H "Content-Type: application/json" \
     -d '{"name":"Alice"}' https://api.example.com/users

-H "Header: value" → добавить заголовок 

curl -H "Authorization: Bearer TOKEN" https://api.example.com

-b "name=value" → передать cookie
-c cookies.txt → сохранить cookie в файл
-b cookies.txt → использовать cookie из файла

-o file → сохранить в файл

 -u user:pass → basic auth

-k → игнорировать ошибки сертификатов (небезопасно!)
--cacert file.crt → указать свой сертификат CA

-w "%{http_code}\n" → вывести только HTTP-код

find / -name "file.txt"

Поиск файла

Редиректы

Вывод в файл:

Оператор Значение Пример
> Перенаправить вывод (перезаписать файл) echo "hi" > file.txt
>> Перенаправить вывод (добавить в файл) echo "hi" >> file.txt

Вывод из файла:

Оператор Значение Пример
< Чтение из файла wc -l < file.txt
<< Here document — передаёт блок текста как stdin cat << EOFстрока1строка2EOF
<<< Here string — передаёт одну строку (или переменную) grep foo <<< "foo bar baz"

Фоновые задачи

Фоновые задачи не получают данные от клавиатуры

Команда Что делает
command & Запускает процесс в фоне
jobs Показывает список фоновых задач (с job ID: %1, %2 …)
fg %N Переводит задачу номер N в передний план
bg %N Возобновляет приостановленную задачу в фоне
Ctrl+Z Приостанавливает текущий процесс (отправляет в «stopped»)
kill %N Завершает задачу по её job ID
kill PID Завершает задачу по PID
kill -9 PID Жёсткое завершение (если обычный kill не помог)
disown %N «Отвязывает» задачу от текущего терминала (будет жить после выхода)
`ps aux grep name`
pkill -f pattern Завершение процессов по шаблону

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

nohup ./myscript.sh &

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

Хранится где-то в сессии, сохраняется в .bash_history при закрытии сессии. Для просмотра введенных команд в пределах сессии используется утилита fc

-l

Последние 15 команд

4 выведет четвертую команду

4 7 команды с 4 по 7

строка - выведет с первого вхождения строки (из 15) и далее

-n без вывода номеров
-e nano

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

Чтобы не вводить редактор, можно в .bash_profile добавить переменную

FCEDIT=nano

!! исполнение предыдущей команды

Специальные файлы

.bash_profile, .bash_logout, .bashrc Если отсутствуют - используются файл /etc/profile и файлы из /etc/profile.d

.bash_profile - сейчас не используется. 

В .profile переменные окружения, .bashrc - скрипты. .bash_login при входе. Но идея осталась.

Последовательность поиска при авторизации, исполняется первый найденный 

Исполняет команды при каждом входе в систему.

Итого: 

~/.bashrc

Используется в интерактивных (обычных) shell-ах. Сюда кладём то, что нужно только в терминале:

~/.profile

Используется при login-shell (и не только Bash, а sh/dash/zsh тоже могут его читать). Сюда кладём:

~/.bash_profile или ~/.bash_login 

Сегодня почти не нужны. Если они есть, то Bash не будет читать ~/.profile. 

source .profile - перечитать файл

Alias, options и переменные окружения

Алиасы для команд. Создание алиасов: alias cdvoy='cd sipp/demo/animation/voyager'

Пробел перед закрывающей ' означает ожидание ввода пользователя.

unalias name - удаление 

set +o optionname установить опцию, -o убрать. Фиксированный набор. Не впечатлило.

Переменные

Синтаксис: varname='something', использование $varname удаление unset varname

Формат timestamp:

%a, %A Аббревиатура дня недели, Полное имя дня недели
%b, %B, %m Аббревиатура имени месяца, Полное имя месяца, Номер месяца в числовом формате
%c Дата и время локали
%C

Последние 2 цифры года

%H, %I, %p Час в 24-часовом формате, Час в 12-часовом формате, эквивалент am/pm
%d, %e Цифра дня, цифра дня с пробелом в случае одной цифры
%D Дата в американском формате (%m/%d/%y)
%j День года 001-366
%M Минута в десятичном представлении
%n, %t Новая строка, табуляция
%R Время в 24-часовом формате
%S Секунда в десятичном формате
%T Время (час:минута:секунда)
%u Номер дня недели в десятичном формате
%U Номер недели в году
%Y Год

Строка приглашения

PS1 - основное приглашение

PS2 - при незавершенной строке

В переменной PS1

Код Что показывает
\u Имя текущего пользователя
\h Имя хоста (до первой точки)
\H Полное имя хоста
\w Текущая директория (полный путь, с ~ для home)
\W Текущая директория (только имя последней папки)
\! Номер текущей команды в истории
\# Номер команды (считает все команды с момента запуска shell)
\$ Отображает $ для обычного пользователя и # для root
\t Время в формате HH:MM:SS
\T Время в формате HH:MM (12-часовой формат)
\@ Время в формате hh:mm AM/PM
\d Дата (например: Mon Aug 26)
\n Перенос строки
\s Имя используемой оболочки (обычно bash)
\v Версия Bash (например: 5.2)
\V Версия Bash с патч-уровнем
\j Количество фоновых задач, запущенных из shell
\! Номер команды в истории
\# Номер команды (считает все команды в текущей сессии)
\e или \033 Escape-символ (для цветов/ANSI-последовательностей)

Пример: PS1="\u@\h:\w\$ "

PATH

Просмотр последовательно всех путей.

Добавление в пути: PATH=$PATH":/home/you/bin"

Для ускорения поиска пути к приложениям хранятся в хэш таблице в каждой сессии. 

hash -r очищает таблицу хэшей путей.

CDPATH

Аналог path для директорий поиска при использовании cd. 

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

Вызванная программа не знает переменных консоли. Для видимости нужно экспортировать переменную в переменную окружения.

env Список переменных окружения
export varnames Может быть список через пробел
export varname=value command Доступность переменной только для определенной команды

source .envfile догружает переменные из файла

Переменные по умолчанию

BASH_VERSION Версия
BASHPID
GROUPS Группы текущего пользователя
HOSTNAME Имя хоста
OSTYPE
PWD Текущая рабочая директория
RANDOM Случайное число от 0 до 32767
UID Идентификатор пользователя
SHELL Полный путь к текущей консоли

Периферийные функции

sleep n Пауза на n секунд
seq 1 10 Последовательность чисел от 1 до 10
date '+%Y-%m-%d %H:%M:%S' Текущая дата и время
tail -f fname Выводит изменения файла в текущую консоль

Bash скрипты

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

Можно запускать через source, имя (если . в PATH), ./... , и ./ ... & С фоновой задачей аккуратно с объемом вывода, ^C не работает.

Shebang

Лучше использовать shebang в начале (указатель, какую консоль использовать)

#!/bin/bash

#!/bin/bash -x Выводит все команды во время исполнения
#!/bin/bash -r Блокирует потенциально опасные действия

Параметры можно указывать при запуске скрипта, тогда shebang работать не будет.

Удобства

Комментарии #

bash -n script.sh проверка синтаксиса без исполнения скрипта

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

#!/bin/bash
...
set -x
...potentially error part...
set +x

Операция ; запускает несколько команд независимо от их статуса завершения 

ls; ps; whoami

выполнит все команды

Перенаправления результата выполнения 

> Stdout в файл, файл очищается
>> Stdout в файл, файл дополняется
&> or >& Stdout и Stderr в файл, файл очищается
&>> Stdout и Stderr в файл, файл дополняется
< Перенаправление ввода в команду
<< Перенаправление многострочного ввода в команду

Номера потоков

0 - stdin, 1 - stdout, 2 - stderr

lzl -l 1> stdout.txt 2>stderr.txt

выведет в stderr.txt

Функции

function functname{
shell commands
}

functname(){
shell commands
}

Используют позиционные переменные. 

functname "one" $7

Если внутри функции нужна локальная переменная, то local var1="something", иначе используется глобальная переменная.

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

cd baddir
echo $?

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

builtin mkdir "/var/first"
es=$?
echo "$OLDPWD --> $PWD"
return $es

Желательно возвращать код результата, а не просто цифру.

Программы для работы с функциями

declare -f список функций с описанием

-F только имена функций
unset fname удалить функцию из памяти
type fname Описание функции

-t выведет тип

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

  1. Aliases
  2. Служебные слова типа if, ...
  3. Функции
  4. Встроенные команды типа cd, type, ...
  5. Скрипты и исполняемые команды

Переменные

Строковые (по умолчанию)

Описывается $varname или ${varname} Например есть переменная UID. Для вывода 0_ нужно использовать echo ${varname}_

Удаление переменной unset var1

$1, $2, ... Позиционные параметры
$* Строка, содержащая все параметры через пробел
$@ Равна N строкам-параметрам. Актуально при передаче в функции.
$# Количество аргументов
var1=$(cmd) Сохранение результата cmd в переменную

Определение глобальной переменной: var1="something"

Обработка значений переменных перед вводом

${varname:-word } Если переменная не существует или существует но пустая - вернет word
${varname:=word} Если переменная не существует или существует но пустая - присвоит ей word и вернет word
${varname:?message} Если переменная не существует или существует но пустая - выведет сообщение и завершит скрипт
${varname:+word} Если переменная существует или пустая - вернет word, иначе null
${varname:offset:length}

Срез. 

count=frogfootman

${count:4} вернет footman

${count:4:4} вернет foot

Обработка переменных 

${var#pattern}

 


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

var="/home/user/docs/file.txt"
echo ${var#*/}   # home/user/docs/file.txt   (отрезан только первый "/")

${var##pattern}

var="/home/user/docs/file.txt"

echo ${var##*/}  # file.txt                  (отрезано всё до последнего "/")

${variable%pattern}

file="archive.tar.gz"

echo ${file%.*}   # archive.tar

${variable%%pattern}

file="archive.tar.gz"

echo ${file%%.*}  # archive 

${variable/pattern/string}

Наибольшее совпадение шаблона с переменной заменяется строкой. Первое совпадение

${variable//pattern/ string}

Наибольшее совпадение шаблона с переменной заменяется строкой. Все совпадения


 echo -e ${PATH//:/'\n'}

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

Длина значения ${#filename}

Типизированные

При помощи declare <param> var

-a Массив
-i Целое число
-r Переменная только для чтения
-x Переменная экспортируется в окружение
-f

Хрень. Возвращает тело функции если она есть.

myfunc() {
    echo "Hello from myfunc"
}
declare -f myfunc
-F Возвратит имя функции если она есть.

Пример: 

declare -i val3=12 val4=5
declare -i result2
result2=val3*val
echo $result2

Выведет 60

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

let result="4 * 5"
echo $result

Также можно использовать двойные скобки 

let result=$((4 * 5))
echo $result

Есть операции +,-,/,*,%-модуль, += увеличение на константу, -=

Массивы

arr = (1 2 3)
echo "${arr[*]}" #весь массив
echo "${arr[0]}" #1
unset ${arr[1]} #удалит 2 из массива
${arr[0]}=10 #перезапишет 1 в 10

Условия

Условия завершения программы

Условие анализируется не на логическом, а на статусе результата (exit status) выполнения программы. 0 - ОК, 1-255 ошибка.

if condition; then
statements
[elif condition; then 
statements...]
[else
statements]
fi

Условие анализа строк

 конструкция [], внутри нее возможны условия проверки и сравнения строк.

str1 = str2 Строка 1 равна строке 2
str1 != str2 Строка 1 не равна строке 2
str1 > str2 str1 < str2 Больше/меньше
-n str1 Строка 1 не пустая
-z str1 Строка 1 пустая

Условия сравнения чисел

-lt Менее чем
-le Меньше или равно
-eq Равно
-ge Больше или равно
-gt Больше
-ne Не равно

Можно комбинировать 

if command && [ condition ]; then

Логика внутри условия

&& или -a

Выполнить команду 1, если статус 0 - выполнить команду 2

if statement1 && statement2
then
...
fi
|| или -o

Выполнить команду 1, если статус не 0 - выполнить команду 2

if statement1 || statement2
then
...
fi
!

Отрицание

Свойства файла, проверяемые в условиях

-a file, -e file Файл существует
-d file Директория существует
-f file Файл существует и является файлом (не директория или специальный файл)
-r file, -w file Есть право чтения файла, Есть право записи в файл, 
-x file Есть право исполнения файла или право поиска в директории
-s file Файл существует и не пустой
-N file Файл был изменен с момента последнего чтения
-O file, -G file Запустивший скрипт является владельцем файла, Группа запустившего скрипт входит в группу файла
file1 -nt file2 file1 новее file2 (сравниваются время модификации)
file1 -ot file2 file1 старее file2 (сравниваются время модификации)

Цикл for

Итерируется только по полному списку.

for name [in list]; do
    statements that can use $name...
    done

Если list не определен, то используется $@

Есть переменная IFS 

IFS=:
for dir in $PATH
  do
    ls -ld $dir
  done

break выход из цикла, continue продолжить следующую итерацию

Цикл while

while condition; do
statements...
done

Для бесконечного цикла можно использовать while true; do

Просмотр каждой строки вывода программы (например ping) 

#!/bin/bash

ping 172.16.10.1 | while read -r line; do
  echo Пинг $line | awk '{print $1 $6}'
  done

Цикл until

until command; do
statements...
done

Case

for filename in "$@"; do
  pnmfile=${filename%.*}.ppm
  case $filename in
    *.jpg ) exit 0 ;;
    *.tga ) tgatoppm $filename > $pnmfile ;;
    *.xpm ) xpmtoppm $filename > $pnmfile ;;
    *.pcx ) pcxtoppm $filename > $pnmfile ;;
    *.tif ) tifftopnm $filename > $pnmfile ;;
    *.gif ) giftopnm $filename > $pnmfile ;;
    * ) echo "procfile: $filename is an unknown graphics file." 
        exit 1 ;;
  esac
  outfile=${pnmfile%.ppm}.new.jpg
  pnmtojpeg $pnmfile > $outfile
  rm $pnmfile
done

Опции исполнения

shift смещает переменные влево.

myshift.sh
echo $1 $2
shift
echo $1 $2
Использование: ./myshift.sh one two
Вывод:
one two
two

Вариант скрипта, считывающего параметры со случайным размещением параметров 

while [ -n "$(echo $1 | grep '-')" ]; do
  case $1 in
    -a ) aopt=$2
         shift;;
    -b ) bopt="True"
        ;;
    -c ) copt=$2
        shift;;
    *  ) echo 'usage: alice [-a] [-b] [-c] args...'
         exit 1
  esac
  shift
done

Опция -b является одинарной, -a и -c параметризованные.

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

echo "First arg"
read -r farg
echo "First arg is ${farg}"

Вызов другого скрипта

Если есть права на исполнение и правильный shebang то вызов по имени. Скрипт исполняется в подпроцессе.

#!/bin/bash
echo "Это первый скрипт"

./script2.sh   # вызов второго скрипта

Если директория script2.sh не в PATH то нужен полный путь.

Для выполнения скрипта в одном процессе, все переменные передаются: 

#!/bin/bash
echo "Это первый скрипт"

source script2.sh

Также можно передавать аргументы.


Примеры скриптов

Задача: Есть файл формата кол-во альбомов TAB исполнитель. Нужно вывести первые N исполнителей. Первый аргумент имя файла, второй (необязательный) N. По умолчанию 10. 

filename=${1:?'Нужно определить имя файла в первом аргументе!'}
maxcount=${2:-10}
sort -nr $filename | head -n $maxcount

Задача: Обертка для команды ls, которая выводит информацию в человекочитаемом виде.

if [ ! -e "$1" ]; then
    echo "Файл $1 не существует"
    exit 1
fi
if [ -d "$1" ]; then
    echo -n "$1 директория, в которой "
    if [ ! -x "$1" ]; then
       echo -n "нельзя "
    fi
    echo "проводить поиск."
elif [ -f "$1" ]; then
    echo "$1 обычный файл."
else
    echo "$1 специальный файл."
fi
if [ -O "$1" ]; then
    echo 'Вы владелец этого файла'
else
    echo 'Вы не являетесь владельцем этого файла.'
fi
if [ -r "$1" ]; then
    echo 'У вас есть право чтения этого файла.'
fi
if [ -w "$1" ]; then
    echo 'У вас есть право записи этого файла.'
fi
if [ -x "$1" -a ! -d "$1" ]; then
    echo 'У вас есть право исполнения этого файла.'
fi

Задача: На входе скрипта два параметра: текстовый идентификатор и адрес сайта. Если не хватает параметров - ошибка и выход. Пропинговать адрес, сохранить данные в файл в виде Идентификатор, адрес, результат пинг (Да/Нет), дата и время.

#!/bin/bash

PINGRESULT='ping_result.csv'

ident=${1:?'Нужно определить идентификатор хоста в первом аргументе!'}
myhost=${2:?'Нужно определить адрес хоста во втором аргументе!'}


if [ ! -e "$PINGRESULT" ]; then
    touch $PINGRESULT
fi

if [ -d "$PINGRESULT" ]; then
    echo "$PINGRESULT это директория. Удалите ее или измените имя файла."
        exit 1
fi

declare -i res=$(ping $myhost -c 1 | grep transmitted | awk '{print $4}')
if [ $res -eq "1" ]; then
    isaval="Доступен"
else
    isaval="Не доступен"
fi
echo ${ident},${myhost},${isaval},$(date '+%Y-%m-%d %H:%M:%S') > $PINGRESULT

Задача: Отправить сообщение пользователю telegram

#!/bin/bash
#sudo apt update && sudo apt install -y jq
#usage ./tgsender "My message"

BOT_TOKEN="..."
# 📢 ID канала или ID user
CHAT_ID="..."

MESSAGE=${1:?"Необходимо определить сообщение в первом аргументе"}

# Запрос в Telegram API
res=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
     -d chat_id="${CHAT_ID}" \
     -d text="${MESSAGE}" \
     -d parse_mode="Markdown"\
     | jq -r '.ok')

if [ "${res}" = "true" ]; then
  echo "Ok"
else
  echo "Error"
fi

 

Регулярные выражения

Метасимволы
^ начало
$ конец
[]

список символов

[1-6] перечисление, может комбинироваться порядок роли не играет [0-5a-fkl] 

[- если дефис в начале, то как символ

^ Если в начале, то инверсия правила. Если не в начале, то обычный символ

|

или. Желательно экранировать остальное скобками, например gr(e|a)y

внутри могут быть полноценные регулярные выражения

. Один любой символ, кроме новой строки \n.
? 0 или 1 вхождение предшествующего элемента
+ 1 и более вхождений предшествующего элемента
* 0 и более вхождений предшествующего элемента
\w

Любая цифра или буква


\W все, кроме буквы или цифры
\d Любая цифра [0-9]
\D все, кроме цифры
\xFF шестнадцатеричное число
\s Любой пробельный символ
\S любой непробельный символ
\b Граница слова
\A начало текста
\t, \n, \r Символ табуляции, новой строки и возврата каретки соответственно
{n,m}

От n до m вхождений

{n} ровно n вхождений

{n,} от n вхождений

{,m} — от 0 до m

Иногда нужно экранировать \{

Модификаторы
(?i:что-то) интервальный модификатор, отключающий поиск с учетом регистра для "что-то"
(?:что-то) Атомарная группировка проходит как обычно, но когда процесс поиска выходит за пределы конструкции (за закрывающую круглую скобку), все сохраненные состояния удаляются.
(?P<word>...)

Именованная группа, в данном случае имя - word

m.group('word')  - пример обращения к группе

Опережающая проверка
(?<=...) Должно совпасть слева (Позитивная ретроспективная проверка), в Python - fixed length. 
(?<!...) Не должно совпасть слева (Негативная ретроспективная проверка), в Python не поддерживается.
(?=...) Должно совпасть справа (Позитивная опережающая проверка).
(?!...) Не должно совпасть справа (Негативная опережающая проверка).
\g<...> группы при обратных ссылках, g<1> группа 1 
.*?  "ленивый" поиск
Атрибуты
\p{атрибут}
\p{L} \p{Letter} – символы, считающиеся буквами
\p{M} \p{Mark} – различные символы, существующие не самостоятельно, а лишь в сочетании с другими базовыми символами (диакритические знаки, рамки и т. д.)
\p{Z} \p{Separator} – символы, выполняющие функции разделителей, но не имеющие собственного визуального представления (разнообразные пробелы и т. д.)
\p{S} \p{Symbol} – различные декоративные элементы и знаки
\p{N} \p{Number} – цифры
\p{P} \p{Punctuation} – знаки препинания
\p{C} \p{Other} – прочие символы (редко используется при работе с обычным текстом)
Похоже, что python не поддерживает


Python
Флаги при обработке
re.compile('...', re.IGNORECASE) - игнор регистра
re.VERBOSE re.X Allow inline comments and extra whitespace. 
re.IGNORECASE re.I Do case-insensitive matches.
re.MULTILINE re.M Allow anchors (^ and $) to match the beginnings and ends of lines instead of matching the beginning and end of the whole text.
re.DOTALL re.S Allow dot (.) to match any character, including a newline. (The default behavior of dot is to match anything, except for a newline.)

Нюансы python
В возвращаемом кортеже группа 0 - максимальная группа. Группа определяется скобками. Поэтому если внутри есть () для формирования регулярки, то необходимо всю регулярку брать в скобки.
Вместо r'gr(e|a)y' можно использовать f-строки, {} будет означать переменную
Пример: 
m = re.finditer(r'gr(e|a)y', 'gray grey')
    for ma in m:
        print(ma.groups())
#('a',)
#('e',)
m = re.finditer(r'(gr(e|a)y)', 'gray grey')
    for ma in m:
        print(ma.groups())
#('gray', 'a')
#('grey', 'e')

По умолчанию символы повторения жадные (greedy). Если нужно отключить жадность, достаточно добавить знак вопроса после символов повторения: match = re.search(r'<.*?>', line)

re.sub(pattern, repl, string, count=0) Заменить в строке string все непересекающиеся шаблоны pattern на repl

Grep, awk, sed

Общий синтаксис для sed и awk: command [options] script filename

Если скрипт определяется в команде, то одинарные кавычки.

-f filename имя скрипта

Каждая инструкция скрипта состоит из блока шаблона и процедуры. Шаблон отделяется /. Строки скрипта интерпретируются последовательно, если найдено соответствие шаблону - исполняется процедура. Применяется каждая строка скрипта. Sed выводит строку, поведение awk нужно определять в скрипте. В скриптовом файле шаблон пишется без кавычек

cat sedscr
s/ MA/, Massachusetts/
s/ PA/, Pennsylvania/
s/ CA/, California/
s/ VA/, Virginia/
s/ OK/, Oklahoma/

grep

Регулярки пишутся в двойных кавычках

grep "[PV]A" testone.txt

grep "10\{1,2\}1" testone.txt

grep по умолчанию не понимает спецсимволы типа \d,... \d интерпретируется как символ d. Чтобы понимал: 

echo "123 abc" | grep -P '\d'
Опция Описание
-P

Регулярка в стиле Perl

-o

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


sed

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

Опция Описание
-e

Многострочный скрипт в командной строке, 

sed -e ’s/ MA/ Massachusetts/’ -e ’s/ PA/ Pennsylvania/’ list

Но проще через ;

sed ’s/ MA/ Massachusetts/; s/ PA/ Pennsylvania/’ list

Правила для скрипта

Правило Описание
s

Замена, файл меняется

sed 's/ MA/ Massachusetts/' testone.txt

! случай 's/ MA/, Massachusetts/' не сработал, получилось без запятой. Какой-то нюанс.

 

-n 's/.../.../p'

Выводится только соответствующие шаблону, файл не меняется.

's/.../.../g'

Все вхождения в строке

's/что/на что/число'

Заменить каждое вхождение с номером Число.

's/foo/bar/2' - второе вхождение foo

sed 's/что/на что/w имяфайла'

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

/Sebastopol/s/CA/California/g

Замена CA на California если есть слово Sebastopol

'/.../d'

Удаление

awk

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

$0 полная строка

$1, $2, ... номера полей. Вне awk скрипта $ - параметр bash!

Различные форматы применяются последовательно, например 

awk '/VA/ { print $1}' testone.txt

Для строк, в которых есть VA, будет выведено первое поле.

Можно создавать переменные и затем использовать их в сравнении. Переменные создаются внутри {}, используются вне. Изначально все переменные - пустые строки, автоматически инициализируются.

{LastState = $1}

Параметр Описание
-F

Разделитель, например 

awk -F, '{ print $1}' testone.txt

   

Правила для скрипта формата {}

Правило Описание
print

Вывод данных

awk '{ print $1 }' testone.txt

awk '{ print "Name: " $1}' testone.txt 

;

Разделитель команд внутри

awk '{ print $1; print $2 }' testone.txt



Правила для скрипта формата //

Правило Описание
/some/

Поиск с выводом соответствия шаблону

awk ’/some/’ list

   

Пример совмещения задач

! /bin/sh
awk -F, '{print $4 ", " $0}' $* |
sort |
awk -F, '
$1 == LastState {print "\t" $2}
$1 != LastState {LastState = $1; print $1; print "\t" $2}
'

Вывод 

 CA
         Amy Wilde
 Massachusetts
         Eric Adams
         John Daggett
         Sal Carpenter
 OK
         Orville Thomas
 PA
         Terry Kalkas
 VA
         Alice Ford
         Hubert Sims