Рейтинг
0.00
avatar

BASH

Подробнее ↓

Как собрать в архив все файлы rpm-пакета?

BASH
В продолжение аналогичного поста о dpkg предлагаю использовать следующий «наивный» вариант скрипта, собирающего те файлы, которые были скопированы в систему при установке rpm-пакета. Файлы, созданные автоматически INSTALL-скриптом пакета при этом «подобраны» не будут.

Для запуска скрипта нужно иметь возможность выполнять sudo под суперпользователем: это связано с тем, что немалая часть пакетов устанавливает файлы с эксклюзивным доступом к ним root'а: в таких случаях попытка создать tar-архив провалиться с треском.

Собственно код:

#!/bin/bash
[[ $1 == '-x' ]] && { shift; export TRACE=1; set -x; }
[[ $1 ]] || { echo 'You must specify package name or path to some file installed from the package' >&2; exit 1; }

if [[ ${1:0:1} == '/' ]]; then
        FILE=$1
        if ! PACKAGE=$(rpm -qf $(readlink -e $FILE)) 2>/dev/null || ! [[ $PACKAGE ]]; then
                echo 'Cant determine package name by file name' >&2
                exit 2
        fi
else
        PACKAGE=$1
        if ! PACKAGE=$(rpm -q $PACKAGE); then
                echo "This package seems to be not installed" >&2
                exit 3
        fi
fi

sudo bash <<EOSCRIPT
        tar -cjf "/tmp/${PACKAGE}.tbz2" -T <(
          while read f; do
                  [[ -d \$f ]] || echo "\$f"
          done < <(rpm -ql '${PACKAGE}')
        )
        chown "$(whoami)":"$(id -gn)" "/tmp/${PACKAGE}.tbz2"
        echo "/tmp/${PACKAGE}.tbz2 created" >&2 
EOSCRIPT


UPD: Поправил код скрипта, избавив его от 2-х вызовов sudo и пофиксив ошибки отсутствия присвавивания FILE=$1, а также ошибку сохранения короткого имени пакета, если было передано именно таковое.

Do You Know That? Как раскрывается "${array[@]}" и "${array[*]}"

BASH
Оказывается, в зависимости от режима интерполяции, внутри двойных кавычек массивы раскрываются принципиально по разному:

  • В случае с "${array[*]}" — массив интерполируется в один аргумент (одну строку), представляющий собой результат простой конкатенации всех элементов массива через пробел
  • В случае "${array[@]}" — каждый элемент массива становится отдельным аргументом так, словно каждый элемент взял себе внешние двойные кавычки, что уберегло его от дробления по пробельному символу (точнее, по IFS)

Тестовый пример:

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

Вдогонку к Tips&Tricks'у #10h

BASH
Конечно же, для функции join2 должна быть и комплементарная split.

Учитывая то, что просто split — это «split a file into pieces», а также принимая во внимание тот факт, что split-функция всё-таки будет писать в переменную-массив, а не просто на STDOUT, я добавил к привычному имени циферку 2, дабы получилось у нас «SplitTo (the) arrayName».

Ну а теперь код:

split2 () {
        local arrName=$1
        [[ $arrName =~ ^[0-9_A-Za-z]+$ ]] || return 1
        local delim=$2
        shift 2
        local args
        while (( $# )); do
         args+=${args:+$delim}$1
         shift
        done  
        readarray -t $arrName < <(echo -n "${args//$delim/$'\x0a'}")
        return $?
}


Пример использования:

split2 dir '/' '/usr/share/doc/LaTeX' 'a/b' 'c/d/e f g/h'
declare -p dir
# OUTPUT:
# declare -a dir='([0]="" [1]="usr" [2]="share" [3]="doc" [4]="LaTeX" [5]="a" [6]="b" [7]="c" [8]="d" [9]="e f g" [10]="h")'


Enjoy! :)

BASH Tips&Tricks #0010: И на BASH'е будут join'иться массивы!

BASH
Когда я пишу на Perl, у меня буквально всё под рукой. Кое-что даже мешается и заставляет постоянно проверять кусочки кода в командной строке (perl -e или perl -E), дабы сделать полёт моей фантазии более комфортным и безопасным для здоровья разрабатываемой софтины.

Когда я пишу на BASH, мне, конечно же, многого не хватает: необъятные возможности работы с текстом в Perl'е накладывают свой отпечаток на отношение к другим языкам. Кое-что приходится терпеть, но многое вполне можно исправить, предоставив самому себе привычное окружение, пусть и несколько… задумчивое («бытует мнение», что в случае с BASH скоростью работы обычно можно пренебречь).

Так случилось и с функцией join, которой мне всегда так не хватало в BASH. Я, конечно же, говорю не о той join, которая «join lines of two files on a common field», а об одноимённой функции Perl, «склеивающей» элементы массива (если быть точным, то всё-таки «вектора») в строку.

Я долго терпел сие неудобство и всячески его игнорировал, но… в какой-то момент терпение моё лопнуло, и я решился на сотворение мира в атомарных масштаба. По итогам краткого ознакомления с бесплодными исканиями на StackOverflow и захватывающе познавательного обсуждения join-вопросов с умными людьми © на linux.org.ru, мною был исторгнут приведённый ниже код:

join2 () {
 (( $# == 2 || $# == 3 )) || return 1
 local delim=$1
 local arrName=$2
 local join2var=$3
 local v
 for v in ${join2var:+join2var} arrName; do
  [[ ${!v} =~ ^[_0-9A-Za-z]+$ ]] || return 2
 done
 [[ $join2var ]] || join2var='v'
 source <(
        cat <<SOURCE
         printf -v $join2var "%s${delim}" "\${$arrName[@]}" || return \$?
         [[ \$delim ]] && $join2var=\${$join2var:0:-${#delim}}
SOURCE
 )
 (( $# == 2 )) && echo "$v"
 return 0
}


Бесспорно, он (код) как всегда великолепен и безупречен… пока мною же не будет доказано обратное :)

Квинтэссенция сути функции join2 (звучит как «Join To») заключается в том, что встроенная команда BASH printf понимает конструкцию ${arr[@]} не как уже интерполированную строку из элементов массива, объединённых абы чем (пробелами), но как именно набор элементов. Что эта белиберда значит? А то, что если какой-либо элемент массива уже содержит пробелы, а его объединят пробелом с элементом соседним, printf всё равно «увидит» каждый элемент в отдельности.

Пользоваться join2 можно двояко:
  1. 
    declare -a arr=('a b c' 'd e f' 'g h i')
    join2 '///' arr
    

    — и в этом случае результат конкатенации элементов массива будет «выведен на экран», то есть отправлен на STDOUT, где его легко подобрать так:
    str=$(join2  '///' arr)


    ИЛИ… (барабанная дробь, фанфары!)
  2. 
    declare -a arr=('a b c' 'd e f' 'g h i')
    join2 '///' arr str
    echo "$str"
    

    — а в этом случае название функции окажется весьма неслучайным, поскольку результат join'а запишется сразу в переменную str.

Cакральное знание об особенностях работы printf с массивами в BASH нагло сп скромно почёрпнуто из Yet Another BASH FAQ'а.

Пример преобразования форматов на 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 4

BASH
При написании BASH-скриптов распространённой практикой является считывание любой информации о процессах с помощью утилиты ps в сочетании с awk. В большинстве случаев это делается не ради кроссплатформенности (ps весьма ограниченно кроссплатформенна), а просто в силу непонимания возможностей BASH и принципиального отсутствия желания писать на нём более-менее «традиционный» код вместо нагромождения pipe'ов.

В данном посте я покажу, что код на BASH может оперировать вполне «традиционными» собственными структурами данных — и при этом с минимальным использованием внешних утилит.

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

Как собрать все файлы deb-пакета в tar-архив?

BASH
Если у вас есть устанволенный deb-пакет и хочется аккуратно собрать все его файлы в архив TAR, то сделать это можно вот так:


PACKAGE='libmysqlclient-dev'
tar -cjf /tmp/$PACKAGE.tbz2 -T <(while read f; do [[ -d $f ]] || echo "$f"; done < <(dpkg -L $PACKAGE))


Бывает, что права root'а недоступны, пакеты deb вы нормальным образом установить не сможете (в том числе и любые инструменты сборки из исходников) и тогда подобный «перенос в tar-архивах» становится единственной возможностью для работы в сильно стеснённых условиях. При этом если вы оставите все пересённые tar-архивы на целевой системе, то сможете с помощью опции -t получить список файлов архива и, соответственно, при необходимости вычистить ненужное.

Этакая эмуляция «пакетной системы» Slackware получается :)

P.S.
Думаю, несложно догадаться, что приведённый ниже скрипт соберёт в архив все файлы, установленные из rpm-пакета, в котором был /usr/sbin/zabbix_proxy:


FILE=/usr/sbin/zabbix_proxy
PACKAGE=$(rpm -qf $(readlink -e $FILE))
[[ $? == 0 && $PACKAGE ]] && \
    sudo bash -c 'tar -cjf /tmp/'$PACKAGE'.tbz2 -T <(while read f; do [[ -d $f ]] || echo "$f"; done < <(rpm -ql '$PACKAGE')); echo "/tmp/'$PACKAGE'.tbz2 created"'

Генерация случайного числа в диапазоне от min до max

BASH

min=121
max=257
v=$(( min + ($RANDOM*(max-min))>>15 ))


Работает по принципу:

v=min+rnd/32768*(max-min)

Но вместо деления используются побитовые сдвиги.
Недостаток неочевиден, но он есть: v никогда не сможет быть равным max, поскольку в действительности $RANDOM принимает значения от 0 до 32767, а v=max только если бы $RANDOM=32768. Причём если зазор между max и min значительный, то кроме самого max не смогут быть «достигнуты» и зачения меньше max в ближайшей окрестности.
Тем не менее, это самый простой и самый эффективный генератор случайных чисел в заданном диапазоне, недостатки которого, как водится, напрямую вытекают из его достоинств, а уж вам выбирать, что важнее. Для диапазонов, по размаху значительно меньше 32768, погрешность не должна быть критична.

Скажи мне "да" или "нет" и дай мне свой ответ! :)

BASH
Поскольку люди, которые на BASH'е пишут многословно и ужасно, уже откровенно (достали), предлагаю свой вариант элементарной функции чтения односложного ответа пользователя.

read_yn () {
 local yn dflt='Y'  
 if [[ ${#1} == 1 && ${1^} =~ ^[YN]$ ]]; then   
  shift           
  dflt=${1^}
 fi
 while :; do
  echo -en "$@"
  read yn; yn=${yn:0:1}; yn=${yn^}
  if [[ $yn =~ ^[NY]$ || ! $yn ]]; then
   yn=${yn:-$dflt}
   break
  fi
 done
 echo -n $yn
 [[ $yn == 'Y' ]]
 return $?
}


Большинство людей почему-то думают, что BASH-это какой-то примитивный язык, из которого можно только «командочки запускать», нечто вроде продвинутого языка командных сценариев DOS. Безусловно, право каждого думать как ему угодно и каждый сам себе злой Буратино, поскольку как правило хреново написанный код на BASH не переживает просмотра первым же вменяемым Perl-программистом, поскольку у того просто ломается мозг и он всё переписывает по-своему. Но хотя бы ради мира на Земле — не ленитесь, читайте man bash перед сном и во время ритуальной чистки зубов. Это очень помогает не писать какую-то «ребячливую» чушь вместо кода на добротном, пусть и специализированном, языке программирования.

BASH Tips&Tricks #000F: Ваша перловка, сэр!

BASH
Я часто использую ассоциативные массивы BASH, и все, даже те, кому это было не очень интересно, уже успели познакомиться с этим истинным предметом моего обожания. Иногда я даже генерирую эти ассоциативные массивы, они же «хэши», и складываю их в отдельные include-файлики «на память». Разумеется, это совсем не связано с тем, что реализация «хэшей» в BASH очень медленная и сама по себе их генерация может отнимать столько же процессорного времени, сколько потребовалось бы для получения числа «пи» с точностью до 1000-ного знака после запятой.
Но случается иногда с BASH-программистами казус (не имеющий отношение к глубокоуважаемому Кукоцкому), когда в их наработанное годами упорного труда тёплое скриптовое счастье врывается злобный Perl и требует переписать всё с нуля. Почему? Ну хотя бы потому что гладиолус. Шутка. На самом деле BASH действительно безумно медлителен, так что в какой-то момент и у крутых серверных железок, и у вас может банально не хватить терпения, после чего и возникнет вот эта самая поистине революционная идея: а давайте перепишем всё на Perl!
Читать дальше

BASH Tips&Trick #000E: Немного мутный источник

BASH
Я думаю, вы уже догадались о том, что речь пойдёт о встроенной в BASH команде source. Сегодня она мне доставила массу хлопот, позволив опытным путём найти то, что подробно описано в документации, а именно в man bash-builtins. Поскольку документацию мы, бывалые nix-админы, привычно читаем только тогда, когда уже совсем нет иного разумного выхода, я всё-таки поделюсь плодами своих изысканий.
Дело в том, что source оказался отдалённым подобием «интеллектуального» include в «больших» языках программирования, так что в частности эта команда умеет искать в «путях». Звучит вроде бы обыденно, но из этого вытекает 2 потенциально «неприятных» момента:
      1) Если вы хотите сделать source файла в текущем каталоге, вам нужно явным образом указать путь к нему, содержащий «слэш»: ./file.inc
      2) Не вполне очевидным образом для поиска файлов «без слэша», будет использована переменная PATH
В конечном итоге всё это означает, что если у вас в текущем каталоге есть include.inc и он же есть в одном из каталогов, перечисленных в PATH, будет в действительности подключен именно тот файл, что лежит в PATH.
К счастью, есть один простой способ избавиться от нелогичного поведения source: использовать директиву shopt -u sourcepath до команды source, — это отменит бессмысленный поиск по всем каталогам, указанным в переменной окружения, которая по идее к include-файлам не должна иметь ни малейшего отношения!

BASH Tips&Trick #000D: Нули начинают и проигрывают истинным bash-маньякам

BASH
Нули выбиваются в лидеры. Так бывает часто в этой жизни, потому что мир полон несправедливости © К.О.
И с этим, безусловно, необходимо бороться как минимум ради достижения всеобщей гармонии.
Почему достижение подобного рода гармонии так важно в BASH? Потому что в его вольной интерпретации все переменные — это строки если не указано иное. Таким образом, вы не можете просто положиться на то, что в качестве параметра вам придёт долгожданное число, а не абракадабра или строка, выглядящая как число, но с миллионом-другим нулей в начале.
Проверить, пришло ли нам число или же нечто несуразное можно множеством способов (TIMTOWTDI в терминологии создателей Perl'а :)). Я, например, предпочитаю делать так:
Читать дальше

Перенаправления в 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 #000C: Lets try it now!

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

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

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

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

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

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

BASH Tips&Tricks #000A: Генерация числовых последовательностей

BASH
Для генерации числовых последовательностей в BASH удобно пользоваться командой seq.
Попробую подкрепить справедливость данного утверждения соответствующими примерами.
Итак, чтобы сгенерировать простейшую последовательность от 1 до 12-ти, выполните:

seq 12

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

seq 0 12

И вдвойне приятно, что можно указать даже шаг последовательности (в примере шаг будет равен 3-м):

seq 0 3 12

А вдруг нам нужно сгенерировать выровненную по количеству знаков последовательность, в которой более «короткие» числа будут дополнены соотв. количеством нулей слева?
Нет ничего проще: используйте опцию -w!

seq -w 0 3 12

Если же должна быть жёстко фиксирована символьная «ширина» генерируемых чисел, при этом «ширина» максимального из них совсем не обязательно должна быть равна фиксированной (запросто может быть и меньше), то делаем так:

seq -f '%04g' 0 3 12

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

0000
0003
0006
0009
0012


Thats all i want to say :)

P.S. Настоятельно не рекомендую использовать seq с параметром -f при не дефолтном IFS. Вернее, даже так: если уж вы меняете IFS, то старайтесь восстановить его значение как можно скорее.

BASH Tips&Tricks #0009: Простенький модуль для логирования

BASH
Программа, ведущая подробные логи своей работы, не только удобна в отладке, но и зело приятна в сопровождении, поскольку по сути является самодокументируемой даже без комментариев.
В BASH-скриптах часто хочется вести журналирование в простом и понятном формате, но не всегда есть под рукой соотв. функции.
Собственно, именно для тех, у кого их нет, предлагаю следующий (почти совсем) немудрёный код:

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

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 #0007: Организуем "многозадачное" сжатие

BASH
К сожалению, утилита xz до сих пор не умеет и уже, как видно, никогда не научится сжимать в несколько потоков (см. соотв комментарий в man-странице). 7z с некоторыми типами алгоритмов, в т.ч. с горячо любимым мной PPM, тоже не умеет распараллеливаться (во всяком случае ключ -mmt не даёт желаемого результата).
Но ведь можно осуществить сжатие нескольких файлов параллельно несколькими процессами! Единственная «хитрость» здесь будет заключаться в том, что для получения определённого гарантированного результата («всё сжалось»), нужно всё-таки подождать, чтобы все процессы завершились к моменту дальнейшей обработки файлов или к моменту, когда скрипт должен завершиться.

Всё это делается примерно в таком стиле:

for f; do
 xz $f &
 pids+=" $!"
done

for pid in $pids; do
 wait $pid
done


Время выполнения последнего цикла будет соответствовать времени выполнения самого «длительного» процесса сжатия, а для тех процессов, которые уже завершатся к моменту, когда до них дойдёт очередь «ожидания», команда wait просто отработает как NOP (no-operation в intel assembler :)).
Заметьте, что между двумя циклами можно вставить практически всё, что угодно, так что одновременно со сжатием можно делать и ещё что-нибудь полезное.

Простой загрузчик таблицы маршрутизации, он же "пример на массивы"

BASH
Да, я в курсе, что есть некие другие средства для того, чтобы делать тоже самое.
Тем не менее, есть у меня некое подозрение, что мой скрипт делает это наиболее наглядным, прямолинейным и безопасным способом.
Собственно, он даже и вовсе ничего не меняет, он ведь просто «печатает» команды, которые нужно выполнить для того, чтобы привести текущую таблицу маршрутизации в полное соответствие с сохранённой. Сами команды пишутся на STDOUT, редкие отладочные сообщения — на STDERR.
Читать дальше