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, который хотя-бы вкратце, но можно будет разобрать. Поэтому новые посты будут и надеюсь достаточно скоро, но в комментариях буду отвечать регулярно.

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

GNU/Linux

1.2K постов15.6K подписчиков

Правила сообщества

Все дистрибутивы хороши.

Будьте людьми.

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества