Разбор скрипта для командной строки 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

1K постов15.5K подписчиков

Добавить пост

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

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

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