Сообщество - GNU/Linux

GNU/Linux

1 151 пост 15 633 подписчика

Популярные теги в сообществе:

23

Разбор скрипта для командной строки Linux. Часть 3(заключительная)

Вот и пришло время заключительной части. В 1-ой части мы сделали код более читабельным, во 2-ой части мы избавились от множества регулярных выражений и лишнего кода. В этой части, мы избавимся от временных файлов и распределим вывод.

Во второй части я совсем забыл про не столь критичные, но всё же замечания в комментариях. Так вместо #!/bin/bash советовали #!/usr/bin/env bash и вместо [ ] использовать [[ ]]. Перед началом разбора, применим эти замечания и получим:

#!/usr/bin/env bash

####PART 1####

if [[ -z "$1" ]]; then
echo "Error: missing argument" 1>&2 ; exit 1
fi
f_out="$(mktemp)"
f_tmp="$(mktemp)"
trap "rm -f $f_out $f_tmp" EXIT

####PART 2####

echo "*********************************************"
echo "Get A records from DNS:"
dig +short {www.,}$1 A | tee "$f_out"

####PART 3####

echo "*********************************************"
echo "Get NS records from DNS:"
dig +short $1 NS | while read nsserv
do
nsname=${nsserv:0:-1}
echo "=================================="
echo "NS: $nsname"
dig +short @$nsname $1 A | tee -a $f_out
done

####PART 4####

echo "*********************************************"
echo "Resolve ip range from whois service:"
sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 $f_out | uniq > $f_tmp
rm $f_out
cat $f_tmp | while read ip
do
echo "Get ip range for $ip"
whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out
done

####PART 5####

echo "*********************************************"
echo "Result"
echo "*********************************************"
sort $f_out | uniq | while read range
do
echo "${range:16}"
done

Для начала, хотелось бы сказать, что для больших данных, запись в файл может быть предпочтительнее, чем хранение в переменной. Но в нашем случае информации не так много, поэтому лучше использовать переменные и(или) массивы. Также стоит заменить, что все команды echo, лучше заменить на команду printf.

В 1-ой части кода происходит создание временных файлов, что для нас уже не актуально и можно удалить. Получим:

if [[ -z "$1" ]]; then

printf -- "%s\n" "Error: missing argument" 1>&2 ; exit 1

fi

Далее в каждой из частей происходит выписывание звездочек, заголовка и результата операции. В таком варианте ясно какие шаги выполняет скрипт, но скрипт будет сложнее использовать, т.к. нельзя будет просто записать конечный результат в файл. Поэтому, лучше выписывать промежуточные этапы не на stdout, а на stderr. Так мы улучшим скрипт и не повлияем на функциональность, т.к. всегда можно сделать  2>&1. Cделаем для этого функцию verbose:

function verbose {
printf -- "%s\n" "$1" 1>&2
}

Звездочки с заголовком выписываются в каждой части, поэтому для этого добавим функцию print_header:

function print_header {

verbose "*********************************************"

verbose "$1"

}

Теперь изменим 2-ую часть. Вместо временных файлов запишем результат в перемененную records. Так мы получим:

####PART 2####

print_header "Get A records from DNS:"


records="$(dig +short {www.,}$1 A)"

verbose "$records"

Поработаем над 3-ей частью, пошлём вывод на stderr и добавим новые  ip в переменную records:

####PART 3####
print_header "Get NS records from DNS:"


dig +short $1 NS | while read nsserv
do
nsname=${nsserv:0:-1}
verbose "=================================="
verbose "NS: $nsname"
ns_records="$(dig +short @$nsname $1 A)"
verbose "$ns_records"
records+=ns_records
done

А вот с 4-ой частью возникли проблемы. В данной строке:

whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out

после проведение grep, терялся \n на конце последней строки. В этом примере это не было проблемой, т.к. >> добавлял текст в конец файла и сам ставил новую строку(\n) между старым и новым текстом. Но когда я переписал на переменные, то проблема дала о себе знать и пришлось добавлять символ \n для каждого результата этой команды. Однако появилась одна пустая строка в конце результата, но удалить её было просто:

result="${result%$'\n'}

4-ая часть после изменений:

####PART 4####

print_header "Resolve ip range from whois service:"

records="$(sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 <<<"$records" | uniq)"

result=''

while read ip

do

verbose "Get ip range for $ip"

result+="$(whois $ip | grep -E -i "inetnum|route|netrange|cidr")"$'\n'

done <<< "$records"


result="${result%$'\n'}

Немного изменим 5-ую часть:

####PART 5####
print_header "Result:"
sort <<< "$result" | uniq | while read range
do
printf -- "%s\n" "${range:16}"
done

После всех изменений, мы получим:

#!/usr/bin/env bash

function verbose {

printf -- "%s\n" "$1" 1>&2
}

function print_header {

verbose "*********************************************"
verbose "$1"
}

####PART 1####

if [[ -z "$1" ]]; then
printf -- "%s\n" "Error: missing argument" 1>&2 ; exit 1
fi

####PART 2####

print_header "Get A records from DNS:"
records="$(dig +short {www.,}$1 A)"
verbose "$records"

####PART 3####

print_header "Get NS records from DNS:"
dig +short $1 NS | while read nsserv
do
nsname=${nsserv:0:-1}
verbose "=================================="
verbose "NS: $nsname"
ns_records="$(dig +short @$nsname $1 A)"
verbose "$ns_records"
records+=ns_records
done

####PART 4####

print_header "Resolve ip range from whois service:"
records="$(sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 <<<"$records" | uniq)"
result=''
while read ip
do
verbose "Get ip range for $ip"
result+="$(whois $ip | grep -E -i "inetnum|route|netrange|cidr")"$'\n'
done <<< "$records"
result="${result%$'\n'}"

####PART 5####

print_header "Result:"
sort <<< "$result" | uniq | while read range
do
printf -- "%s\n" "${range:16}"
done

Возможно код стал немного хуже читаться, но за-то мы избавились от временных файлов. А стоит ли оно того, решать только вам.

Заключение:

Последняя часть возможно вышла слегка сумбурна, но сказывается то, что на весь разбор ушло значительно больше времени, чем планировалось. Если с глазу на глаз можно быстро объяснить суть ошибок, то данный формат заставляет думать над каждым словом и писать предельно чётко. Однако, вижу что данный разбор, для достаточного для меня количества людей, пришёлся по душе и это радует.


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

Спасибо всем за внимание и поддержку, надеюсь данный разбор оказался для вас полезен!

Показать полностью
2575

13 занимательных лекции на тему GNU/Linux (МГУ)

Для желающих познакомиться с GNU/Linux очень классные лекции, довольно понятно и ясно все рассказывает

Время каждой лекции ~120минут

На канале также есть полезные лекции на тему "Сетевой безопасности"

Показать полностью 12
17

Linux. Bash. Выборочная очистка почтовой очереди.

Окей пикабу!

Так как мой предыдущий пост разнесли в пух и прах (вполне заслуженно), я насуплю ещё раз на эти грабли. Но не для получения по голове, а во имя развития и обучения. Как моего персонально, так и всех в общем. Итак.

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

Учтя предыдущи печальный опыт, я добавил комменты в код.

#!/bin/bash


###############################

# Set Default value #

###############################

date_s=$(date +%s)

printf "Starts at %s %s\n" `date '+%Y/%m/%d %H:%M:%S'`


###############################

# Get messages by pattern #

###############################

# if parameter exists

if [[ -n "$1" ]];

then

# 1) Get queue as JSON string

# 2) Get messages by pattern

# 3-5) Remove garbage

# 6) Loop

postqueue -j | grep -i "$1" | sed "s/\":[\ \"\[\{]*/:/g" | sed -e "s/\",\ \"/\ /g" -e "s/,\ \"/\ /g" | sed "s/recipients\://g" | while read msg

do

recipients=""

for item in ${msg:2:-4};

do

case "$item" in

queue_id\:*) id=${item#*\:} ;;

sender\:*) sender=${item#*\:} ;;

address\:*) recipients=`printf "%s %s" $recipients ${item#*\:}` ;;

esac

done

# Remove garbage from "id" value

id=`printf $id | sed "s/[\@\*]//g"`

printf "Delete meessage (ID=%s): from %s to %s\n" $id $sender $recipients

postsuper -d $id

done

fi


###############################

# Get relayed messages #

###############################

postqueue -j | grep -viE "server1.com|server2.ru" | sed "s/\":[\ \"\[\{]*/:/g" | sed -e "s/\",\ \"/\ /g" -e "s/,\ \"/\ /g" | sed "s/recipients\://g" | while read msg

do

recipients=""

for item in ${msg:2:-4};

do

case "$item" in

queue_id\:*) id=${item#*\:} ;;

sender\:*) sender=${item#*\:} ;;

address\:*) recipients=`printf "%s %s" $recipients ${item#*\:}` ;;

esac

done

id=`printf $id | sed "s/[\@\*]//g"`

printf "Delete meessage (ID=%s): from %s to %s\n" $id $sender $recipients

postsuper -d $id

done


###############################

# Finish #

###############################

printf "Ends at %s %s\n" `date '+%Y/%m/%d %H:%M:%S'`

let "date_r = `(date +%s)` - date_s"

printf "Runtime: %s %s\n" `date -u -r $date_r +%T`

Что делает скрипт?

1) Подготовка. Вывожу время запуска и запоминаю его (в секундах)

2) Если есть параметр, то начинаю искать.

3) В любом случае ищу сообщения, не имеющие отношение к моим серверам (например, server1.com и server2.ru). Сделал просто так... Для примера... Кто в себе уверен - удаляйте.

4) Вывожу время окончание и время работы.

Как происходит поиск?

Я воспользовался выводом postqueue в формате JSON. Почему именно так? потому что результат возвращается в одну (!) строчку за сообщение и я легко могу найти любое "попадание" по шаблону.

Так, как формат JSON древовидный, то приходится очищать вывод от разных символов: всяческие скобки, запятые и подгонять под удобные для обработки формат.

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

При вызове указать параметр (адресант, адресат или текст сообщения(??)). Либо ничего не указывать. =) Конечно же, запуск от имени root и иже с ним, так как postsuper требует повышения прав.

К тухлым помидорам морально готов =(.

P.S. Скрипт отчасти на коленке. То есть: очередь находит корректно, удалять мне (к счастью) пока нечего. Да и в куске

id=`printf $id | sed "s/[\@\*]//g"`

может быть затык. Добавил этот костыль, так как помню, что в очереди могут быть сообщения, начинающиеся с символов @ и *

Показать полностью
18

Разбор скрипта для командной строки Linux. Часть 2

В прошлой части разбора нам удалось сократить и сделать код более читабельным. В этой части, мы попробуем изучить используемые в скрипте инструменты и сделать код ещё лучше.


Хоть скрипт теоретически был рассчитан на любые доменные имена. На деле, проверка на доменной имя pikabu.ru, дала следующий результат:

91.228.152.0 - 91.228.155.255
MNT-FIRSTCOLO
91.228.152.0/22

Как видим, 2-я строчка тут явно лишняя. Из этого делаем вывод, что скрипт не работает правильно для всех доменов. В вопросе нахождения сетей, которые принадлежат домену, я увы недостаточно компетентен. Поэтому моей целью будет лишь добиться схожего результата и разобрать общие проблемы, которые актуальны для большинства скриптов.

И так, код который мы получили в конце первой части:

#!/bin/bash

####PART 1####

if [[ -z "$1" ]]; then
echo "Error: missing argument" 1>&2 ; exit 1
fi

f_out="$(mktemp)"

f_tmp="$(mktemp)"

trap "rm -f $f_out $f_tmp" EXIT

####PART 2####

echo "*********************************************"
echo "Get A records from DNS:"
# Octet regex
o_re="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
# IP regex
ip_re="$o_re\.$o_re\.$o_re\.$o_re"

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"

dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

####PART 3####

echo "*********************************************"
echo "Get NS records from DNS:"
dig $1 NS | grep "^$1" | awk {'print $NF}' | while read nsserv
do
nsname=${nsserv:0:${#nsserv}-1}
echo "=================================="
echo "NS: $nsname"
dig @$nsname $1 A | grep "^$1" | grep -o -E "$ip_re" | tee -a $f_out
done
####PART 4####
echo "*********************************************"
echo "Resolve ip range from whois service:"
sort -h $f_out | uniq > $f_tmp
rm $f_out
cat $f_tmp | while read ip
do
echo "Get ip range for $ip"
whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out
done


####PART 5####

echo "*********************************************"

echo "Result"
echo "*********************************************"
sort $f_out | uniq | while read range
do
echo "${range:16}"
done

Плюс ко всему, код был разделён на 5 частей, для лучшей навигации.

Для начала, вернемся ко 2-ой части кода. А конкретно к этим строкам:

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"
dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

Лишь на данном моменте тут была замечена ошибка. Предположительно, автор хотел получить данные как по доменному имени vk.com, так и www.vk.com, однако забыл дописать это программе dig. Внесем правки:

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"
dig www.$1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

Далее было замечено, что программа dig умеет принимать множество доменных имен, воспользуемся этим:

dig {www.,}$1 A | grep -E "^(www.|)$1" | grep -o -E "$ip_re" | tee "$f_out"

Уже лучше, вместо 2-ух строк, теперь лишь одна.


Программа dig выписывает множество лишней информации:

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> vk.com A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10732
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1280
;; QUESTION SECTION:
;vk.com. IN A
;; ANSWER SECTION:
vk.com. 33 IN A 87.240.131.118
vk.com. 33 IN A 87.240.131.117
vk.com. 33 IN A 87.240.131.120
;; Query time: 0 msec
;; SERVER: 192.168.3.1#53(192.168.3.1)
;; WHEN: Fri Jun 24 16:27:13 CEST 2016
;; MSG SIZE rcvd: 83

Автор дальнейшими действиями извлекает из этого вывода ip адреса. Но если посмотреть мануал к программе dig, то мы увидим что есть опция +short, которая выписывает лишь ip адреса, без лишней информации. Так, мы можем сократить команду, всего до:

dig +short {www.,}$1 A | tee "$f_out"

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

Теперь можем перейти к 3-ей части, начнем с первых команд:

dig $1 NS | grep "^$1" | awk {'print $NF}'

Снова используя параметр +short, получится:

dig +short $1 NS

Далее, результат с этой команды посылается в цикл while:

dig +short $1 NS | while read nsserv
do
nsname=${nsserv:0:${#nsserv}-1}
echo "=================================="
echo "NS: $nsname"
dig @$nsname $1 A | grep "^$1" | grep -o -E "$ip_re" | tee -a $f_out
done

Думаю сразу видно, что к последней команде в цикле можно применить опцию +short:

dig +short @$nsname $1 A | tee -a $f_out

Так мы опять избавились от лишних действий.


Но вернемся к перемененной nsname, тут автор хочет удалить точку на конце переменной. В коде это было сделано без внешних программ(sed,awk,...), что очень хорошо, но можно ещё проще:

nsname=${nsserv:0:-1}

Подробнее о всех возможностях работы со значениями переменных, можете прочитать на bash-hackers.org.

В 4-ой части кода, есть не очень красивые решения, которые связаны с временными файлами, мы исправим это во время избавления от временных файлов. Так же не понятно, зачем в sort был использован параметр -h(human-numeric-sort). Т.к. sort использован только для дальнейшего uniq, то можно использовать sort  без параметров. Но мы будем использовать более правильную сортировку ip адресов:

sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 $f_out | uniq > $f_tmp

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

5-я часть кода, это только вывод результата, возможно я бы по другому выписал сети, т.к. выписывание после 16 символа, это не самый лучший вариант, но это не столь важно.


Переменные o_re и ip_re, нам уже ни к чему, поэтому можем их удалить.


После всех правок код выглядит следующим образом:

#!/bin/bash


####PART 1####

if [[ -z "$1" ]]; then

echo "Error: missing argument" 1>&2 ; exit 1

fi


f_out="$(mktemp)"

f_tmp="$(mktemp)"


trap "rm -f $f_out $f_tmp" EXIT


####PART 2####

echo "*********************************************"

echo "Get A records from DNS:"


dig +short {www.,}$1 A | tee "$f_out"


####PART 3####

echo "*********************************************"

echo "Get NS records from DNS:"

dig +short $1 NS | while read nsserv

do

nsname=${nsserv:0:-1}

echo "=================================="

echo "NS: $nsname"

dig +short @$nsname $1 A | tee -a $f_out

done


####PART 4####

echo "*********************************************"

echo "Resolve ip range from whois service:"

sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 $f_out | uniq > $f_tmp

rm $f_out

cat $f_tmp | while read ip

do

echo "Get ip range for $ip"

whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out

done


####PART 5####

echo "*********************************************"

echo "Result"

echo "*********************************************"

sort $f_out | uniq | while read range

do

echo "${range:16}"

done


В следующей(заключительной) части, мы избавимся от временных файлов и немного поработаем с выводом. А пока подумайте, почему лучше не использовать echo в скриптах? И ради примера, есть задачка на echo в комментариях.


Спасибо за внимание, надеюсь данный пост окажется для вас полезным.


P.s. если был непонятен как-то шаг или конструкция в коде, то жду ваших вопросов в комментариях.

Показать полностью
40

Разбор скрипта для командной строки Linux. Часть 1

Недавно в сообществе GNU/Linux появился пост с программой для Shell-а от PetRiot. В комментариях началось обсуждение целесообразности самой программы, но этот вопрос мне не интересен в полной мере, а вот качество самого кода хотелось бы улучшить. Поэтому я решил проанализировать код скрипта и дать пару советов как можно улучшить и сократить код. Надеюсь данный разбор будет полезен как для автора скрипта, так и для остальных читателей.

Начнем с первой строчки:

#!/bin/sh

Shell(sh) - самый старый интерпретатор командной строки, увы у него отсутствует множество возможностей, поэтому лучше использовать /bin/bash.


Данный код работает и в sh, но в дальнейшем мы будем использовать bash:

#!/bin/bash

Далее идет создание(запись названия файлов в переменные) временных файлов:

f_out=.get_ip_ranges
f_tmp=.ips

О том, что эти файлы временные, нам говорит то, что в конце их удаляют:

rm $f_out
rm $f_tmp

Тут сразу бы хотелось отметить несколько вещей:

1) создание временных файлов не всегда хорошо само по себе

2) названия могут конфликтовать с другими файлами, так мы можем случайно затереть важный файл с таким же названием

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


Первый пункт слишком спорный, поэтому я его проигнорирую.

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


Для решения второго пункта, я бы посоветовал использовать команду mktemp:

f_out="$(mktemp)"
f_tmp="$(mktemp)"

Теперь временные файлы однозначно уникальные, но нужно обеспечить их удаление в конце работы программы(в конце работы программы != в конце кода программы).


Для решения 3 пункта, используем команду trap:

trap "rm -f $f_out $f_tmp" EXIT

Команда trap запустит посланный ей код сразу после завершения программы, тем самым мы можем быть уверенны что файлы будут удалены. Также мы добавили параметр -f команде rm, который нужен для игнорирования ошибок и убирает вопросы о удалении.

Перед тем как перейти к следующей части, хотелось бы добавить ещё одну важную деталь в скрипт - проверку входных параметров.


Автор забыл упомянуть, что для запуска скрипта нужно обязательно послать один аргумент - название сайта. Если этого не сделать, то работа программы будет не очевидна. Добавим в начало проверку:

if [ -z "$1" ]; then
echo "Error: missing argument" 1>&2 ; exit 1
fi

Если первый аргумент пустой, то выписывается текст ошибки на stderr и программа завершается. В дальнейшем данное решение можно улучшить, создав функцию для ошибок.

Теперь начало кода выглядит так:

#!/bin/bash


if [ -z "$1" ]; then
echo "Error: missing argument" 1>&2 ; exit 1
fi


f_out="$(mktemp)"
f_tmp="$(mktemp)"
trap "rm -f $f_out $f_tmp" EXIT

Идем дальше:

dig $1 A | grep "^$1" | grep -o -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"

dig $1 A | grep "^$1" | grep -o -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" > $f_out
dig $1 A | grep "^www.$1" | grep -o -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
dig $1 A | grep "^www.$1" | grep -o -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" >> $f_out

Тут начинаются любимые всеми регексы. Увы читабильность кода плохая, поэтому попробуем это исправить:

# Octet regex

o_re="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"

# IP regex

ip_re="$o_re\.$o_re\.$o_re\.$o_re"


dig $1 A | grep "^$1" | grep -o -E "$ip_re"

dig $1 A | grep "^$1" | grep -o -E "$ip_re" > $f_out

dig $1 A | grep "^www.$1" | grep -o -E "$ip_re"

dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" >> $f_out

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


Теперь код короче, но можно сократить ещё:

# Octet regex

o_re="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
# IP regex
ip_re="$o_re\.$o_re\.$o_re\.$o_re"


dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"
dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

Используя команду tee мы выписали результат команды в командную строку и одновременно в файл $f_out.

Исправив с учетом этого остальную часть кода и получим:

#!/bin/bash


if [ -z "$1" ]; then

echo "Error: missing argument" 1>&2 ; exit 1

fi


f_out="$(mktemp)"

f_tmp="$(mktemp)"


trap "rm -f $f_out $f_tmp" EXIT


echo "*********************************************"

echo "Get A records from DNS:"

# Octet regex

o_re="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"

# IP regex

ip_re="$o_re\.$o_re\.$o_re\.$o_re"


dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"

dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"


echo "*********************************************"

echo "Get NS records from DNS:"

dig $1 NS | grep "^$1" | awk {'print $NF}' | while read nsserv

do

nsname=${nsserv:0:${#nsserv}-1}

echo "=================================="

echo "NS: $nsname"

dig @$nsname $1 A | grep "^$1" | grep -o -E "$ip_re" | tee -a $f_out

done


echo "*********************************************"

echo "Resolve ip range from whois service:"

sort -h $f_out | uniq > $f_tmp

rm $f_out

cat $f_tmp | while read ip

do

echo "Get ip range for $ip"

whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out

done


echo "*********************************************"

echo "Result"

echo "*********************************************"

sort $f_out | uniq | while read range

do

echo "${range:16}"

done


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


Спасибо за внимание, надеюсь данный пост окажется для вас полезным.

P.s. прошу прощение за орфографические ошибки, мне бы точно не помешал разбор моего текста с орфографической точки зрения :)

Показать полностью
25

Вышел nano 2.6.0, проект откололся от GNU.

Вышла новая версия простого консольного текстового редактора nano — 2.6.0 под кодовым названием «Rubicon».


В новой версии:


*Добавлена функция для быстрого закомментирования и раскомментирования строк кода (по умолчанию Alt+3).

*Улучшен поиск текста, ускорен поиск без учёта регистра.

*Исправлено более 50 багов.

*Различные улучшения пользовательского интерфейса.

*Начиная с этого выпуска разработчики nano перестали считать проект частью GNU. *Редактор больше не называется «GNU nano», все материалы и загружаемые файлы перенесены на собственный сайт nano, но репозиторий кода пока остаётся на https://savannah.gnu.org/ (ведутся работы по переходу на https://savannah.nongnu.org/).


В сообщении о выпуске разработчики не прокомментировали этот шаг, написав только: «Мы покинули стадо, всего наилучшего и спасибо за траву» (отсылка к роману Дугласа Адамса), но можно установить ход событий из открытой переписки разработчиков. Основатель и руководитель проекта Крис Аллегретта хочет оставить свой пост из-за недостатка времени, но не может найти себе на замену человека, который согласился бы оформить передачу авторских прав Free Software Foundation и был бы готов работать с хостингом кода GNU Savannah, а все популярные хостинги кода не соответствуют этическим критериям GNU. Кроме того, по факту проект во многом не следовал правилам GNU, в частности, в последнее время не проверял, подписывали ли авторы патчей соглашение с FSF.


Новый руководитель, впрочем, ещё не найден. Более того, некоторые из главных разработчиков хотя и поддержали решение о выходе из GNU, но не считают необходимым уходить с Savannah и полностью отвергают переход на Github, причём, как и FSF, из этических соображений.


nano остаётся свободным программным обеспечением под GNU General Public License версии 3.

Показать полностью
Отличная работа, все прочитано!