Всем доброго времени!
Ковыряя свои давние скрипты нашел один скрипт примерно такого содержания
#!/bin/sh
# Скрипт создания архива для пользователя с конфигурационным файлом и сертификатом PKCS
if [ -f /etc/openvpn/ssl/vars ]; then
. /etc/openvpn/ssl/vars >/dev/null
else
echo "Файл /etc/openvpn/ssl/vars не существует"
exit 1
fi
MAILTO="root"
SKIP=$((`cat $0 | awk '/#!/bin/sh/,/^#END/{print}'|wc -l`+1))
Dialog=${Dialog=dialog}
CWD=$(pwd)
cd $KEY_DIR
Files=`ls -1 *.p12`
cd $CWD
Spisok=""
for i in $Files; do
Spisok="$Spisok $i Пользователь-"`basename $i .p12`
done
Choice=`$Dialog --stdout --clear --menu "Выберите файл" 20 71 14 $Spisok`
retval=$?
User=`basename $Choice .p12`
case $retval in
0)
TEMP="/tmp/$User.vpn"
if [ -e $TEMP ]; then
rm -rf $TEMP
fi
mkdir -p $TEMP 2>/dev/null
mkdir -p $TEMP/yyy 2>/dev/null
config="$TEMP/YYY-$User.ovpn"
cat << EOF_CONFIG > $config
client
remote xxxxx
port 1194
proto udp
dev tun
ns-cert-type server
tls-client
reneg-sec 60
mtu-test
cipher AES-256-CBC
comp-lzo
persist-key
persist-tun
keysize 256
nobind
explicit-exit-notify 2
pkcs12 yyy/$Choice
EOF_CONFIG
cp $KEY_DIR/$Choice $TEMP/yyy 2>/dev/null
tail -n +$SKIP $0 | gzip -cd | tar xvf - -C $TEMP >/dev/null
cd $TEMP
tar zcvf ${User}_YYY.tgz `basename $config` `basename $TEMP/Readme-OpenVPN.doc` yyy >/dev/null
.
.
.
.
exit 0
#END
здесь уже идет архив с файлом инструкции в двоичном формате
В принципе скрипт предоставляет меню выбора файла контейнера с отсылает данный файл с инструкцией на указанный адрес. Для того что бы было возможно переносить скрипт на разные сервера и не думать об инструкции, я саму инструкцию вложил в исполняемый скрипт и при выполнении ее оттуда доставал, разархивировал и отправлял. Но заметка сама не о инструкции, а об неоптимальном использовании некоторых команд.
Сама команда которая мне не понравилась и которую я захотел оптимизировать выглядит так
SKIP=$((`cat $0 | awk '/#!/bin/sh/,/^#END/{print}'|wc -l`+1))
В ней мы получаем смещение в строках от начала файла до заархивированных данных в конце файла.
Первое что мне бросилось в глаза это использование cat и awk через pipe. Естественно я сразу переписал на
SKIP=$((`awk '/#!/bin/sh/,/^#END/{print}' $0|wc -l`+1))
Но и этого мне показалось мало. Зачем использовать еще и wc если и так используем awk, который может делать намнго больше. В тоге получилось нечто такое
SKIP=$(awk 'BEGIN{comp_str=0} /#!/bin/sh/,/^#END/{comp_str++} END{print ++comp_str}' $0)
И опять, слишком много символов, и очень трудночитаемо, в результате имеем
SKIP=$(awk '/^#END/{print ++NR}' $0)
Но, здесь не выполняется условие что до первого вхождения символов #END. Хотя меня это устраивает, ради интересе запустив на выполнение скрипт на данных тескта более 500 мегабайт, обнаружил что время выполнения скрипта было примерно около 25 секунд. Я начал искать функцию exit (как мне потом посоветовал читатель oxpa ) на awk, но в тот момент из-за невнимательности я не смог ее заставить работать, как мсешно это не звучит, и я начал смотреть в сторону sed. В итоге получилось вот такое
SKIP=$((`sed -n '/^#END/{=}' $0` + 1))
Проверив на том же файле в 500 мегабайт увидел время выполнение менее 2 секунд. Отлично, но зачем нам смотреть весь файл, да и опять же в первом варианте было условие до первого вхождения в файл. Не сотавалось ничего как переписать на
SKIP=$((`sed -n '/^#END/{=;q;}' $0` + 1))
ну или можно на awk
SKIP=$(awk '/^#END/{print ++NR; exit;}' $0)
Спасибо за внимание!
Автор: mcleod095