Рейтинг
0.00

BASH

6 читателей, 32 топика

Простая "обёртка" для LVMSync

  • BASH
Написал незамысловатый фронтэнд для замечательной утилиты lvmsync, написанной Matt Shed. Спасибо тебе, Шэд, ты единственный человек, который удосужился разумным (т.е. читай: вменяемым) способом решить вопрос синхронизации блочных устройств. Да, только для LVM-томов. Но причина тому банальна до безобразия: LVM-тома — это пока единственный широко распространённый тип блочных устройств, изменения на которых можно отслеживать при посредстве самого механизма записи, а не выявлять каким-то хитрым образом уже пост-фактум, считывая произвольные куски, скурпулёзно высчитывая контрольные суммы и вообще занимаясь какой-то хиромантией. Есть конечно ddsnap от Zumastor'а, и он нашёл своё широкое применение на хранилищах свалок истории, предлагая патчить ядро Linux для решения «в общем виде» той задачи, которая в принципе такого решения иметь не должна.

Читать дальше →

Перенаправления в bash

  • BASH
Перенаправление в bash даёт нам инструмент для тонкой манипуляции потоками ввода/вывода, создания каналов между командами и т.д. Каждый начинающий unix'ойд может сказать, что делает command > file. Однако, допустим, { { ls -l; } 2>&1 >&3 | cat > file; } 3>&1 поставит в ступор, иной раз, даже бывалого. Конечно, эта команда избыточна и представляет собой всего лишь ls -l 2>file, но сколько смысла заложено в этой строчке. Естественно, памяти доверять такой большой багаж знаний нельзя, поэтому я долго искал в рунете полный мануал по перенаправлениям, но… видимо плохо искал… И написал свой, с блэкджеком и шлюхами. Я не претендую на полноту изложения и широту охвата, и не берусь утверждать, что после прочтения можно будет слёту понимать что-то вроде:

{
  {
    cmd1 3>&- |
      cmd2 2>&3 3>&-
  } 2>&1 >&4 4>&- |
    cmd3 3>&- 4>&-

} 3>&2 4>&1


Читать дальше →

BASH Tips&Tricks #000B: Hello ли world? О встроенном в BASH "Эффекте бабочки".

  • BASH
Изучение многих языков программирования начинается с написания с простейшего кусочка кода, выводящего на экран радостно-интернациональное Hello, world!
Теперь давайте представим себе, что мы только начинаем изучать BASH и решили написать нашу первую приветствующую мир программку:

#!/bin/bash
echo "Hello, world!"

Я думаю, вы догадались уже, в чём подвох.
А именно: этот элементарный код не работает…

Читать дальше →

BASH Tips&Tricks #0008: Голову с плеч!

  • BASH
Да-да, забудьте наконец об этой странной утилите, которая ещё и работает «как-то иначе» в некоторых менее популярных, чем Linux, реализациях *nix!
Почему даже одна head вам ни к чему, не говоря уже о двух и более?
Да потому что у нас есть sed, который умеет всё или почти всё, но остаётся при этом простым и чрезвычайно быстрым, что позволяет ему заменять целую тучу атомарных nix'овых утилит.
Ну вот, например…
Хотите первое поле 2-й строки CSV-файла, где разделителем служит (сюрприз!) — запятая?
Да нет ничего проще, чем сделать это одной командой, безо всяких глупых head'ов и медлительных awk, — вот:

sed -n '2{ s/,.*$//; p; q }' FILE

Да, и никогда не забывайте про жадный разбор регулярных выражений и фигурные скобки — данный пример наглядно показывает, чем бывает полезно и то, и другое.

Пожалуй, совсем не очевидным выглядит решение с помощью sed такой элементарной задачи, как «получить первые 5 строк файла»:

sed -n '1,5p; 6q' FILE

— с этим куда лучше справится head -5

Но, например, чуть менее элементарную задачу «вывести строки файла с 3-й по 10-ю, исключая 7-ю», sed решает куда нагляднее и элегантнее, нежели связка из доисторического локомотива head и «прицепного вагона» sed вместе:

sed -n '7b; 3,10p; 11q'


sed не умеет вести «обратный отсчёт» от конца файла, поэтому ему сложно соревноваться с tail в скорости и удобстве, но вот head он заменяет весьма успешно!
Поэтому в следующий раз, когда вы подумаете использовать sed на вагонной сцепке c head, подумайте ещё раз и сделайте «состав» немного короче…

BASH Tips&Tricks #0006: Как делать точно не следует

  • BASH
Наверное, это будет самый короткий пост в серии Tips&Tricks, потому что…

a="t*"
b="/etc/fs*"
c=/proc/1*

— да, вот именно так делать и не следует.
А именно: астериск (символ "*") в двойных кавычках и в присваивании переменной интерпретируется BASH не так, как вам хочется и даже не так, как хочется разработчикам BASH. Попробуйте и убедитесь сами.
Но лучше сразу экранируйте его, а для получения списка файлов пользуйтесь ls.

Всё!

BASH Tips&Tricks #0001: Распахнём "запахнутые" окна! :)

  • BASH
Надоело восстанавливать сессию screen при каждом заходе по ssh?
Впишите в .bash_profile:

if [[ $PS1 && $(</proc/$PPID/cmdline) =~ ^sshd ]] && { which screen || alias -p screen; } &>/dev/null ; then
  screenSessMaxPID=$(screen -ls | sed -nr 's%^\s+([0-9]+)\..*\((At|De)tached\)$%\1%p' | sort -n | tail -1) && \
   screen -dr $screenSessMaxPID 2>/dev/null
fi

UPD[02/09/2015]
— добавил возможность указания screen'а в виде алиаса
— убрал флуд screen'а при старте

UPD[29/02/2016]
«Интерактивная» версия:

if [[ $PS1 && $(</proc/$PPID/cmdline) =~ ^sshd ]] && { which screen || alias -p screen; } &>/dev/null; then
        declare -a lstScreens=( $(screen -ls | sed -nr 's%^\s+([0-9]+)\..*\((At|De)tached\)$%\1%p' | sort -rn) )
        declare -i nScreens=${#lstScreens[@]}
        if (( nScreens )); then
                if [[ $nScreens>1 && -t 1 ]]; then
                        echo -e 'Warning: there are more than one active screen sessions running simultaneously!\nPlease, choose what session to load' >&2
                        select screenSessID in ${lstScreens[@]}; do [[ $screenSessID ]] && break; done
                else
                        screenSessID=${lstScreens[0]}
                fi
                screen -dr $screenSessID 2>/dev/null
        else
                if [[ -t 1 ]]; then
                        echo 'Info: The are no screens to attach, creating new session' >&2
                        sleep 1
                fi
                screen
        fi
fi

Пример преобразования форматов на BASH 4

  • BASH
Если кто-нибудь скажет Вам, что BASH — это какой-то недостойный внимания недоязык для написания циклов из командочек, киньте ему ссылку на данный пример.

Пример совсем несложный, я только что написал его для StackOverflow (где, к сожалению, люди всё ещё живут в криогенных камерах, не ведая о существовании BASH 4-й версии):

#!/bin/bash
inFile=$1
outFile=$2

join () {
 local del=$1
 shift
 IFS="$del"
 source <(
        cat <<SOURCE
 echo "\${$1[*]}"
SOURCE
 ) 
 unset IFS
}

declare -a CSV=('"Module Name","Module Group","Module Version"')
declare -a keysAccepted=('Name' 'Group' 'Version')

declare -i nMandatoryKeys=${#keysAccepted[@]}
declare -A KeyFilled
rxKeysAccepted='('$(join '|' keysAccepted)')'
while read line; do
        [[ $line =~ \<strong\>Module\ $rxKeysAccepted:\</strong\>[[:space:]]*([^<]+)\</p\> ]] || continue
        key=${BASH_REMATCH[1]}
        val=${BASH_REMATCH[2]}
        KeyFilled[$key]=$val
        if (( ${#KeyFilled[@]} == nMandatoryKeys )); then
                unset csvLine
                for k in ${keysAccepted[@]}; do
                        csvLine+=${csvLine:+,}${KeyFilled[$k]}
                done
                KeyFilled=()
                CSV+=($csvLine)
        fi
done <"$inFile"

(( ${#CSV[@]} > 1 )) || exit 1

join $'\x0a' CSV >"$outFile"


BASH-скрипт состоит из sed'ов, awk и grep'ов?
Давайте подсчитаем количество вхождений того, другого и третьего в данном примере!

Не спорю, тот же самый код на Perl, лучшем языке для работы с текстами, получился бы и короче намного, и быстрее.

Но, например, не нагляднее (Perl немного провоцирует писать супер-лаконичную абракадарбру). А является ли свойством BASH как языка программирования его действительно порой раздражающая медлительность — это ещё большой вопрос.

BASH Tips&Tricks #000C: Lets try it now!

  • BASH
Давайте попробуем это сейчас! Да-да, именно вот этот чудесный кусочек кода выполним, а он нам взрыхлит почву, посеет нужные семена. А потом следующий за ним код, ещё более великолепный в своём совершенстве, даст сочные зелёные побеги. И уже в завершение всего этого благолепия наш скрипт пожнёт плоды, свяжет снопы и сложит стога…
Жаль, что вся этя идиллия оказывается досадной фикцией, когда наш трудолюбивый созидательный код вдруг помещают в условия неблагоприятного марсианского климата: в результате мало того, что ничегошеньки не всходит, так ещё и скрипт с оглушительным треском рушится. А может статься и того хуже: как ни в чём ни бывало начнёт выполняться следующий код, мерно перепахивающий красные марсианские пески в задумчивом цикле без конца и края…
Всё ещё не слишком ясно, о чём таком внеземном у нас сегодня пойдёт речь?
ОК, я немного увлёкся научной фантастикой, так что постараюсь теперь пояснить ближе к реалиям повседневного скриптотворчества.
Вот смотрите: вы, я, он, она и они — то есть «все мы», — часто пишем скрипты с мимимальными проверками на корректность завершения команд. И это, в принципе, не особо-то и плохо: ведь в BASH, к сожалению, нет такой волшебной палочки-выручалочки, как возможность устанавливать собственные обработчики исключительных ситуаций. Проверять же код возврата каждого grep'а или sed'а было бы откровенно глупо. С другой стороны, аварийное завершение скрипта или его продолжение после того, как произошла непредвиденная ошибка — часто бывает в равной мере нежелательно, а иногда просто катастрофично.
Посему выполнение наиболее критичных участков кода обязательно необходимо контролировать на предмет возможного возникновения ошибок, при этом исключая самопроизвольное «падение» скрипта. Как это сделать?
Читать дальше →

BASH Tips&Tricks #0005: О том, что остаётся за скобками. За двойными.

  • BASH
BASH, сам по себе весьма мощный интерпретатор команд с очень широкими возможностями (в т.ч. и для написания кода, который не понимает даже его автор сразу после сохранения файла скрипта), становится просто кладезем интересных возможностей тогда, когда вы открываете для себя круглые, но в то же время такие многогранные, — (( двойные+скобки ))!

Дело в том, что выражения, заключенные в круглые двойные скобки, ведут себя так, словно их написали на одном из многочисленных диалектов языка Си (Perl-программисты, цыц, это не про вас!).
Вот, например, как преображаются циклы с использованием этой «super cow power» из мира си-подобных языков:

max_i=12
for ((i=1; i<=max_i; i++)); do
 date -d "2012-$i-01" +%B
done

Выражения, заключенные в «тёплые ладони» двойных круглых скобок помогают избавиться от уродливой конструкции ${} вокруг элементов массива. И вообще как только мы попадаем в чудесный мир Си-подобных кострукций за «двойным ограждением», у нас пропадает всякая необходимость постоянно писать $VAR или уж тем более ${VAR}. Узрите истину!
Читать дальше →

Bash script для обновления данных на бесплатном dnsdynamic.org

  • BASH
Есть отличный ДНС сервис для динамических АйПи. dnsdynamic.org. В больших городах Rоссии это не актуально, а вот мне, как филиппинцу, да еще и не столичному, кроме АДСЛ ничего не светит еще долго… поэтому приходится выкручиваться. На сайте прилагается клиент и настройка…

Ho тут несколько раз не сработал перловый ddclient, и я решил упростить дело и написал на баше, благо API позволяет. может кому и сгодится… юзернэйм и пароль испойзуйте те, с которыми логинетесь на сайт
#!/bin/bash
IP=`/usr/bin/GET https://myip.dnsdynamic.org`
USER="USER@gmail.com"
PASSWD="SECRET"
sleep 10
    for i in `cat /var/scripts/dnsdynamic.org.lst`;
        do /usr/bin/GET -C ${USER}:${PASSWD} https://www.dnsdynamic.org/api/?hostname=$i\&myip=${IP};
        echo "Update domain $i to IP address ${IP}";
        sleep 5;
    done;

добавьте в фаил /var/scripts/dnsdynamic.org.lst свои домены. Каждый домен с новой строки:

echo "asterisk-63.voip01.com" >> dnsdynamic.org.lst
echo "yourdomain.http01.com" >> dnsdynamic.org.lst

но неплохо бы и проверку valid IP производить перед циклом. может кто подскажет?

BASH Tips&Tricks #0002: Форматируем вывод ldapsearch

  • BASH
Если вам случалось писать на BASH скрипты, работающие с LDAP, то вы наверное уже в курсе, что клиентская утилита ldapsearch, входящая в поставку OpenLDAP, а потому имеющаяся в комплекте большинства дистрибутивов Linux, из каких-то своих соображений (оказывается, это требование RFC 2045) выводит результирующий LDIF со строками, длина которых не превышает 78 символов. Соответственно, те строки, что оказываются длиннее 78-и символов, попросту разбиваются по правилам формата LDIF: в начале продолжения предыдущей строки ставится один пробельный символ.
Анализ такого LDIF на языке оболочки bash может быть затруднительным, гораздо удобнее, когда значение атрибута умещается в одной строке.
Читать дальше →

Если пробел встал у вас на пути. Как правильно перейти в каталог (рас|место)положения скрипта?

  • BASH
Вы всё ещё делаете это так?


cd $(dirname $(readlink -e $0))


Это ленивый вариант, который работает «в большинстве случаев». Однако же он не является верным, поскольку пути (пусть это не покажется вам странным) в общем случае могут содержать пробельные символы.

Надо бы вот так:

cd "$(eval "readlink -e '$0'" | sed -r -e 's%(^|/)[^/]+$%%' -e 's%([^/])/+$%\1%')"


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