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

Предположим, что нам нужно найти подстроку в строке при помощи php.

Основы регулярных выражений

В общем виде синтаксис команды ‘grep’ выглядит следующим образом:

$ grep поисковый_запрос_regex расположение_файла

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

. будет соответствовать любому символу;
[ ] будет соответствовать диапазону символов;
[^ ] будет соответствовать всем символам, кроме указанных в фигурных скобках;
* будет соответствовать любому количеству символов, предшествующих звездочке, в том числе нулю;
+ будет соответствовать одному или нескольким из стоящих перед ним выражений;
? будет соответствовать нулю или одному из стоящих перед ним выражений;
{n} будет соответствовать ‘n’ повторениям предшествующих выражений;
{n,} будет соответствовать не менее ‘n’ повторениям предшествующих выражений;
{n m} будет соответствовать не менее ‘n’ и не более ‘m’ повторениям предшествующих выражений;
{,m} будет соответствовать не более или равному ‘m’ повторениям предшествующих выражений;
является escape-символом (символом экранирования), используемым, когда нужно включить один из метасимволов.

Поиск подстроки при помощи функции preg_match

Эта функция производит поиск подстроки при помощи регулярного выражения.

Регулярное выражение — это шаблон, который сравнивается со строкой. Под один шаблон может подходить сразу множество разных строк.

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

Пример:

$html = ‘content <title>hello php!</title> content’; if (preg_match(«!<title>(.*?)</title>!si», $html, $matches)){ echo $matches[1]; } else { echo «Тег не найден»; }

Начать рекомендую с этой статьи: регулярные выражения.

PHP располагает широким выбором функций по работе с регулярными выражениями.

Была ли эта статья полезна? Да Нет

Алгоритм Бойера — Мура

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

Рассмотрим пример:

ровкдткотор кот********

Начиная проверку с конца к началу определяем, что не совпадают символы «в» и «т». Сдвиг, величина шага которого зависит от таблицы, описанную позже, в этом случае будет равен 3:

Читайте также:  Заработок на облачном майнинге и своём компьютере с NiceHash

ровкдткотор ***кот*****

Снова проверяем сконца: после совпадения «т» в обеих строках не совпадают «д» и «о». Снова сдвигаем, шаг в этом случае равен 3:

ровкдткотор ******кот**

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

персональные данные данные************* -> не совпал «н» (не совпал в первом символе, индекс 5), сдвигаем на 5 — 3 = 2 (3 по таблице) **данные*********** -> не совпал «л», сдвигаем на 6, т.к. символа нет в таблице ********данные***** -> не совпал «д» (не совпал в первом символе индекс 5), сдвигаем на 5 — 0 = 5 (0 по таблице) *************данные -> совпали

Для составления таблицы используется следующее правило: значение для символа равно максимальному индексу этого элемента в образце (исключая последний символ, для него и всех других значение равно количеству символов в образце). Так для строки «данные» это будет:

д а н ы *
1 3 4 6

Тогда величина сдвига при сравнении справа налево и при не совпадении символа на j-ой позиции, где сам символ , будет равна . Приведём алгоритм с приведённой эвристикой, называемой эвристикой стоп-символа:

table = create map for i = 0 to — 1 do table[P[i]] = i end for for i = 0 to do #NEXT for j = — 1 down to 0 do if P[j] != S[j + i] then step = j — table[S[j + i]] i = i + step go to #NEXT end if end for return i end for return -1

Эффективность поиска в таком алгоритме достигает

Операции со строками

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

  • выделить блок оперативной памяти под массив;
  • проинициализировать строку.

Для выделения памяти под хранение строки могут использоваться функции динамического выделения памяти. При этом необходимо учитывать требуемый размер строки:

Для ввода строки использована функция scanf(), причем введенная строка не может превышать 9 символов. Последний символ будет содержать '\0'.

Функции ввода строк

Для ввода строки может использоваться функция scanf(). Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки. Для ввода строки, включая пробелы, используется функция char * gets_s(char *); В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

Читайте также:  Ubuntu Budgie Linux — подробный обзор и установка дистрибутива

Функции вывода строк

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

или в сокращенном формате int puts (char *s);

которая печатает строку s и переводит курсор на новую строку (в отличие от printf()). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.

Функция ввода символов

Для ввода символов может использоваться функция

Функция вывода символов

Для вывода символов может использоваться функция 1234567891011121314151617181920212223242526#include <stdio.h>#include <string.h>#include <stdlib.h>int main() { char s[80], sym; int count, i; system("chcp 1251"); system("cls"); printf("Введите строку : "); gets_s(s); printf("Введите символ : "); sym = getchar(); count = 0; for (i = 0; s[i] != ‘\0’; i++) { if (s[i] == sym) count++; } printf("В строке\n"); puts(s); // Вывод строки printf("символ "); putchar(sym); // Вывод символа printf(" встречается %d раз", count); getchar(); getchar(); return 0;}

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

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

Удаление из скрипта команды echo позволило нам получить код завершения. Что делать, если нужно сделать разные действия в случае успешного и неуспешного выполнения команды touch? Речь идёт о печати stdout в случае успеха и stderr в случае неуспеха.

Проверяем коды завершения

Выше мы пользовались специальной переменной $?, чтобы получить код завершения скрипта. Также с помощью этой переменной можно проверить, выполнилась ли команда touch успешно.

#!/bin/bash touch /root/test 2> /dev/null if [ $? -eq 0 ] then echo «Successfully created file» else echo «Could not create file» >&2 fi

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

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

Любой код завершения кроме 0 значит неудачную попытку создать файл. Скрипт с помощью echo отправляет сообщение о неудаче в stderr.

Выполнение:

$ ./ Could not create file

Создаём собственный код завершения

Наш скрипт уже сообщает об ошибке, если команда touch выполняется с ошибкой. Но в случае успешного выполнения команды мы всё также получаем код 0.

$ ./ Could not create file $ echo $? 0

Поскольку скрипт завершился с ошибкой, было бы не очень хорошей идеей передавать код успешного завершения в другую программу, которая использует этот скрипт. Чтобы добавить собственный код завершения, можно воспользоваться командой exit.

#!/bin/bash touch /root/test 2> /dev/null if [ $? -eq 0 ] then echo «Successfully created file» exit 0 else echo «Could not create file» >&2 exit 1 fi

Теперь в случае успешного выполнения команды touch скрипт с помощью echo сообщает об успехе и завершается с кодом 0. В противном случае скрипт печатает сообщение об ошибке при попытке создать файл и завершается с кодом 1.

Читайте также:  Какой дистрибутив Linux выбрать в 2021 году

Выполнение:

$ ./ Could not create file $ echo $? 1

Подсчет уникальных строк и дубликатов в текстовом файле Linux

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

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

$ sort | uniq -u | wc -l

Всё достаточно просто. Утилита uniq с функцией -u выводит на экран уникальные строки (u—unique, видимо так) и с помощью | результат перенаправляется в утилиту wc , какая просто считает количество строк, т.к. исполняется с опцией -l. В самом начале нам необходимо просортировать входной поток данных (текстовый файл), иначе утилита uniq не сможет правильно подсчитать уникальные строки. Выполняется сортировка с помощью sort и результат, используя |, перенаправляется в uniq. После исполнения такой команды для файла на экран будет выведено число 5.

Для этого чтобы решить вторую подзадачу, сделаем всё тоже самое, только uniq станет выполнен с опцией -d (видимо d—duplicate):

$ sort | uniq -d | wc -l

В результате на экран выведено количество 2. Обе подзадачи решены достаточно простым способом. Записал небольшую демонстрацию кому забавно.

Работа с подстроками

Рассмотрим javascript функции для работы с подстроками.

  • slice(start, [end]) — возвращает символы, между конкретных позиций.

    let s = ‘0123456789’; let s_new = (0, 4); (s_new); // 0123

    Если второй параметр не указан, то вернет всё до конца строки.

  • substring(start, [end]) — работает аналогично. Отличие от «slice» в 2 моментах. Если стартовое значение больше конечного, то первая функция вернет пустую строку.

    let s = ‘0123456789’; ((6, 4)); // » ((6, 4)); // 45

    Ещё различие в подходе при неверных параметрах.

    let s = ‘0123456789’; ((-4, -2)); // 67 ((-4, -2)); // »

    Функция «slice()» конвертирует отрицательные значения в положительные, отталкиваясь от длины строки, а «substring()» просто устанавливает их в ноль, поэтому возвращает пустую строку.

  • substr(start, [length]) — возвращает подстроку, начиная с определенной позиции и определенной длины.

    let s = ‘0123456789’; let s_new = (4, 3); (s_new); // 456