gladilov.org.ru gladilov.org.ua

17 заметок с тегом

BASH

bash (bourne again shell) — командная среда, используемая по умолчанию во многих современных Linux-дистрибутивах. Если используется ОС из семейства Linux, то, скорее всего, используется и bash.



Позднее Ctrl + ↑

Скрипт подсчёта количества автономных систем

Количество ASN’ок, зареганных в мире, можно получить так:

wget -q http://www.cidr-report.org/as2.0/ -O - \
| sed -r 's/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\& ]+[\/]?[\>]//g' $1 \
| grep "Number of ASes in routing system" | cut -f1 -d"&"

Показать

Небольшой разбор.
Командой

wget -q http://www.cidr-report.org/as2.0/ -O -

получаем в консоль (ключ -O -) страницу с сайта www.cidr-report.org (нужная нам строка будет в тексте страницы представлена приблизительно таким текстом: <tr><td align=right><tt>59222&nbsp;&nbsp;</tt></td><td>Number of ASes in routing system</td></tr>), затем по конвейеру с помощью построчного редактора sed и простейшего регулярного выражения (см. постскриптум)

sed -r 's/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\& ]+[\/]?[\>]//g' $1

очищаем текст от HTML-тегов, потом командой

grep "Number of ASes in routing system"

печатаем только строку, содержащую текст «Number of ASes in routing system». Вывод получается приблизительно такой: 59222&nbsp;&nbsp;Number of ASes in routing system
Заключительной командой

cut -f1 -d"&"

из полученной строки печатаются только символы до первого знака «&».

Quod erat faciendum.


P. S. Регулярка

s/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\& ]+[\/]?[\>]//g

заменяет (действие s, substitute) фрагменты, содержащие условие
(строка [\<][\/]?[a-zA-Z0-9\=\«\-\#\.\& ]+[\/]?[\>] между первым и вторым слешами)
на пустую строку (пустая строка определяется отсутствием символов между вторым и третьим слешами //) во всём тексте (флаг g, global — теперь условие сработает везде). Под условие подпадают все подстроки, ограниченные символами < или </ в начале и > или /> в конце и (обязательно) содержащиеся между ними буквы от a до z и от A до Z, цифры от 0 до 9, символы = (равно), " (двойную кавычку), (минус), # (октоторп), . (точку), & (амперсанд) или   (пробел) в любой последовательности. Строки, удовлетворяющие этому регэкспу:
<html>
<head>
<title>ASNs</title>

<link href="../common.css" type="text/css" rel="stylesheet" />
</head>
<body>
<table>
<tbody>
<tr>
<td align="left">Autonomous Sysmem Number</td>
<td align="center">
<img src="../image.png" />
</td>
</tr>
</tbody>
</table>
</body>
</html>
Из примера видно, что регулярка срабатывает на строках вида <тег>...</тег> и <тег ... />, а строки вида <тег .../... /> пропускает. Вообще говоря, этот regexp сработает и на такие строки: </ 1 />, < 2 />, </ 3 >, < 4 >. Если регулярное выражение заменить на

s/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\&\/ ]+[\/]?[\>]//g

(добавить \/ в квадратных скобках с плюсом), то срабатывать оно будет и на строки вида <тег .../... />,
т. е. строки определения стиля страницы и вывода изображения в таблице заменятся на пустые (удалятся).
P. P. S. Цветовое выделение добавлено для лучшей читаемости (и понимаемости) регулярного выражения.

Количество Linux и Windows систем в локальной сети

Количество Linux- и Windows-хостов в сети можно с помощью следующих команд:

$ sudo nmap -F -O 192.168.1.1-255 | grep "Running: " > /tmp/os; \
echo "$(cat /tmp/os | grep Linux | wc -l) Linux device(s)"; \
echo "$(cat /tmp/os | grep Windows | wc -l) Window(s) devices"

Вместо 192.168.1.1-255 нужно подставить параметры своей сети. Для выполнения требуется установленный в системе пакет nmap и пользователь должен иметь возможность получать привилегии рута.

P. S. В источнике приведён однострочник, но я разбил строку на три для удобства и читаемости.

Cкрипт определения провайдера сотовой связи

Привожу BASH-скрипт получения оператора номера сотового
(используется сервис http://rosreestr.subnets.ru).

Показать

Допустим, мы хотим получить информацию о мобильном номере +7 900 555-55-50 (или 8 900 555-55-50)... При выполнении команды

curl -s "http://rosreestr.subnets.ru/?get=num&format=xml&num=9005555550" | sed -e 's/<[^>]*>//gm' | sed '/^$/d' | tr -d '\t'

получим в консоли вывод

900
260823
5555550
5555550
1
ООО &quot;СИМ ТЕЛЕКОМ&quot;
5418
Москва и Московская область
1880

где:
900 — DEF-код (мобильные номера всегда начинаются с цифры 9)
260823 — ID диапазона номеров с данным DEF-кодом в реестре Российской системы и плана нумерации
5555550 — начальный номер диапазона номеров
5555550 — конечный номер диапазона номеров
1 — Общая номерная ёмкость в данном диапазоне
ООО "СИМ ТЕЛЕКОМ" — наименование оператора, обслуживающего мобильный номер
5418 — ID оператора
Москва и Московская область — наименование региона, в котором оператор обслуживает мобильный номер
1880 — ID региона в реестре Российской системы и плана нумерации

Разоблачение фокуса...

Командой

curl -s "http://rosreestr.subnets.ru/?get=num&format=xml&num=9005555550"

в вывод консоли сервис возвращает ответ в формате XML:

<?xml version="1.0" encoding="utf-8"?>
<response>
<row>
        <code>900</code>
        <codeID>260823</codeID>
        <from>5555550</from>
        <to>5555550</to>
        <capacity>1</capacity>
        <operator>ООО &quot;СИМ ТЕЛЕКОМ&quot;</operator>
        <operatorID>5418</operatorID>
        <region>Москва и Московская область</region>
        <regionID>1880</regionID>
</row></response>

Команда

sed -e 's/<[^>]*>//gm'

по конвейеру убирает все подстроки, заключённые в угловые скобки < ... >

900
        260823
        5555550
        5555550
        1
        ООО &quot;СИМ ТЕЛЕКОМ&quot;
        5418
        Москва и Московская область
        1880

Затем с помощью команды

sed '/^$/d'

удаляются пустые сроки, оставшиеся после удаления <тегов>:

900
        260823
        5555550
        5555550
        1
        ООО 'СИМ ТЕЛЕКОМ'
        5418
        Москва и Московская область
        1880

а команда

tr -d '\t'

убирает символы табуляции в получившемся выводе

900
260823
5555550
5555550
1
ООО 'СИМ ТЕЛЕКОМ'
5418
Москва и Московская область
1880

N. B.: Скрипту нужен установленный пакет curl, можно заменить wget’ом:

wget -q -O - "http://rosreestr.subnets.ru/?get=num&format=xml&num=9005555550" | sed -e 's/<[^>]*>//gm' | sed '/^$/d' | tr -d '\t'

N. B.: В принципе, можно получать вывод не в формате XML, при опускании в урле параметра

&format=xml

сервис выдаёт plain text.

В планах написать веб-версию, использующую данный сервис.

Слизано с Хабра.

Получение внешнего IP скриптом на BASH’е

Привожу BASH-скрипт получения своего внешнего IP
(использует сервис http://checkip.dyndns.org/dyndns.checkip.html).

wget -q http://checkip.dyndns.org/dyndns.checkip.html -O - | sed -r 's/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\& ]+[\/]?[\>]//g' $1 | cut -d':' -f2 | sed 's/^[ ]*//' -

Показать

Опишу работу скрипта.

С помощью кода

wget -q http://checkip.dyndns.org/dyndns.checkip.html -O -

скрипт получает строку вида

<html><head><title>Current IP Check</title></head><body<Current IP Address: 217.69.139.200</body></html>

на свой вывод, о чём указывает ключ "-O -". Полученный текст с помощью кода

sed -r 's/[\<][\/]?[a-zA-Z0-9\=\"\-\#\.\& ]+[\/]?[\>]//g' $1

очищается от HTML-тегов (значение свойства $1 изменяется при каждом успешном обнаружении заключенного в знаки / .. / шаблона. Шаблон описывает замену любого текста, обрамлённого знаками < (или </) ... > (или />) и содержащего (или нет ) символы a-z, A-Z, цифры от 0 до 9, знаки = (равно), " (двойная кавычка), (минус), # (диез), . (точка), & (амперсанд) и пробел в любом порядке, влючая неограниченное число повторов).

Затем из очищенного таким образом текста вида

Current IP CheckCurrent IP Address: 217.69.139.200

с помощью оператора

cut -d':' -f2

вычленяется вторая часть строки после деления её по символу : (двоеточие). Получаем

217.69.139.200

(с пробелом в начале строки). Его отсекаем командой

sed 's/^[ ]*//' -

убирающей пробел именно в начале строки. Результат

217.69.139.200

Опять про PS1

В дополнению к первому посту о переменной окружения PS1, для себя определился, что у моего пользователя она такая:

а у рута будет лиловенькая:

Показать

И вообще, на всякий случай привожу краткие выдержки конфигурационных файлов моего BASH’a:
Мой ~/.bashrc

PS1='\[\e]0;`if [[ $? = 0 ]]; then echo "\[\033[1;34m\]"; else echo "\[\033[1;31m\]"; fi`\t \[\033[1;32m\]\u\[\033[0;37m\]@\[\033[1;32m\]\H\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

alias sus='sudo -s'

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

export PHANTOMJS_EXECUTABLE=/usr/local/bin/phantomjs

Мой ~/.profile

if [ -n "$BASH_VERSION" ]; then
    if [ -f "$HOME/.bashrc" ]; then
        "$HOME/.bashrc"
    fi
fi

if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

export LANG=ru_RU.UTF-8
export LANGUAGE=ru_RU.UTF-8
export LC_ALL=ru_RU.UTF-8
export PAGER=/usr/bin/most

if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi

/root/.bashrc

PS1='${debian_chroot:+($debian_chroot)}`if [[ $? = 0 ]]; then echo "\[\033[1;34m\]"; else echo "\[\033[1;31m\]"; fi`\t \[\e[0;95m\]\u\[\033[0;37m\]@\[\033[1;32m\]\H\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

export LANG=ru_RU.UTF8
export LC_ALL=ru_RU.UTF8
export PAGER=/usr/bin/most

if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi

/root/.profile

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

mesg n || true

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

Когда Bash вызывается как интерактивная оболочка входа в систему, первым делом он читает и вызывает команды из файла /etc/profile, если этот файл существует. После чтения этого файла, он смотрит следующие файлы в следующем порядке: ~/.bash_profile, ~/.bash_login и ~/.profile, читает и вызывает команды из первого, который существует и доступен для чтения. При выходе bash читает и выполняет команды из файла ~/.bash_logout.

Когда запускается интерактивная оболочка, но не для входа в систему, bash читает и исполняет команды из файлов /etc/bash.bashrc и ~/.bashrc, если они существуют. Это может быть отменено опцией -norc. Опция -rcfile file заставит Bash использовать команды из файла file вместо /etc/bash.bashrc и ~/.bashrc.

2017   BASH   Linux   сисадминство   софт

Переменная PS1 и её сёстры

Всегда хотел узнать, почему у переменной окружения $PS1 (prompt string) в конце цифра 1.

Оказывается — таких переменных аж четыре штуки ($PS1, $PS2, $PS3, $PS4), и все они отображают приглашения ко вводу в различных ситуациях.

Показать

Далее речь идёт о системной оболочке bash.

В моих системах $PSx выглядят так:

$PS1 — приглашение командной строки, используется в оболочке для отображения запроса ввода и отображается тогда, когда консоль готова считать команду.
Значение по умолчанию:

"\u@\h:\w\$ "

или

"\s-\v\$ "

(расшифровку значений спецсимволов bash см. внизу заметки).
$PS2 — вторичное приглашение командной строки, отображается, когда консоль нуждается в дополнительном вводе для завершения команды, которую уже начала считывать.
Значение по умолчанию:

"> "

Очень длинную команду можно разбить с помощью символа ’\’ в конце строки, при этом приглашение изменится на $PS2, ожидая ввода продолжения команды.

$PS3 — третичное приглашение, выводится тогда, когда оператор select ожидает ввода значений.
Значение по умолчанию:

""

хотя в bash’е вроде как

"#?"

$PS4 — приглашение четвертого уровня, выводится в начале каждой строки вывода во время трассировки выполнения (вызывается с ключом -x).
Значение по умолчанию:

"+ "

Во всех переменных можно использовать следующие спецсимволы (напомню, речь идёт об оболочке bash):

\a

символ Bell (звонок) (код 07)

\d

дата в формате «ДеньНедели Месяц Число» (т. е. «Tue May 26»)

\\

символ обратного слеша (обратная косая черта)

\e

символ Escape (код 033)

\h

имя хоста до первой точки

\H

полное имя хоста

\j

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

\l

базовое имя наименования терминального устройства оболочки (в случае входа через ssh-клиент возвращает не полное имя, например pts/3, а только 3)

\n

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

\r

символ возврата каретки

\s

имя оболочки, базовое имя от переменной $0 (после последнего символа /)

\t

текущее время в 24-часовом формате (HH:MM:SS)

\T

текущее время в 12-часовом формате (HH:MM:SS)

\@

текущее время в 12-часовом формате (am/pm)

\A

текущее время в 24-часовом формате (HH:MM)

\u

имя текущего пользователя

\v

версия оболочки bash (например, 2.00)

\V

версия и номер релиза bash (например, 2.00.0)

\w

полный путь текущей директории

\W

базовое имя текущей директории

\!

номер истории зтой команды

\#

номер зтой команды

\$

если UID == 0, то символ ’#’, иначе ’$’

\nnn

символ, соответствующий восмеричному числу nnn

\[

начало последовательности невыводимых символов. Может использоваться для осуществления управления терминалом в приглашении

\]

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

\D{format}

строка format передаётся в strftime(3), результат вставляется строку приглашния оболочки, пустой формат приводит к выводу локального времени. Скобки необходимы.

Ну и напоследок бонус — скрипт генерации таблицы цветов в bash

2017   BASH   Linux   сисадминство   софт

Скрипт подсчёта размера БД MySQL

Понадобилось мне как-то узнать размер таблиц в MySQL-базе данных. Причём узнать в shell script’е. Поискав в сети, наткнулся на чудесный скриптик.

Показать

Допилив его, стал использовать в MRTG. Привожу полностью, без правок/изменений:

#!/bin/bash
# Calculate the storage space used up by all tables in a given MySQL database
# Ben Dowling - www.coderholic.com
database=$1
username=$2
password=$3

if [ ${#database} -eq 0 ]
then
    echo "Usage: $0 &lt;database&gt; [username [password]]"
    exit
fi

if [ "$password" ]
then
   password="-p$password"
fi

mysql="mysql -u $username $password $database"

$mysql -se "USE $database";

tables=$($mysql -se "SHOW TABLES")

totalData=0
totalIndex=0
totalTables=0

for table in $tables
do
   output=$($mysql -se "SHOW TABLE STATUS LIKE \"$table\"\G")
   data=$(echo "$output" | grep Data_length | awk -F': ' '{print $2}')
   dataMegs=$(echo "scale=2;$data/1048576" | bc)
   index=$(echo "$output" | grep Index_length | awk -F': ' '{print $2}')
   indexMegs=$(echo "scale=2;$index/1048576" | bc)
   total=$(($index+$data))
   totalMegs=$(echo "scale=2;$total/1048576" | bc)
   
   echo "$table Data: ${dataMegs}MB Indexes: ${indexMegs}MB Total: ${totalMegs}MB"
   
   totalData=$(($totalData+$data))
   totalIndex=$(($totalIndex+$index))
   totalTables=$(($totalTables+1))
done

dataMegs=$(echo "scale=2;$totalData/1048576" | bc)
indexMegs=$(echo "scale=2;$totalIndex/1048576" | bc)
total=$(($totalIndex+$totalData))
totalMegs=$(echo "scale=2;$total/1048576" | bc)

echo "*** $totalTables Tables | Data: ${dataMegs}MB Indexes: ${indexMegs}MB Total: ${totalMegs}MB ***"

Размеры выводятся в мегабайтах. Пример вывода:

soul@etcetera:~$ ./db.sh somedatabase root ********
wp_comments Data: 6.60MB Indexes: .15MB Total: 6.75MB
wp_links Data: 0MB Indexes: 0MB Total: 0MB
wp_options Data: 1.57MB Indexes: .01MB Total: 1.58MB
wp_postmeta Data: .01MB Indexes: .01MB Total: .02MB
wp_posts Data: .57MB Indexes: .02MB Total: .60MB
wp_term_relationships Data: 0MB Indexes: .01MB Total: .02MB
wp_term_taxonomy Data: 0MB Indexes: 0MB Total: 0MB
wp_terms Data: 0MB Indexes: 0MB Total: 0MB
wp_tla_data Data: 0MB Indexes: 0MB Total: 0MB
wp_tla_rss_map Data: 0MB Indexes: 0MB Total: 0MB
wp_usermeta Data: 0MB Indexes: 0MB Total: 0MB
wp_users Data: 0MB Indexes: 0MB Total: 0MB
*** 12 Tables | Data: 8.78MB Indexes: .25MB Total: 9.03MB ***

Наверх