Всем доброго времени!
Ковыряя свои давние скрипты, нашел один скрипт примерно такого содержания:
В принципе скрипт предоставляет меню выбора файла контейнера с отсылает данный файл с инструкцией на указанный адрес. Для того что бы было возможно переносить скрипт на разные сервера и не думать об инструкции, я саму инструкцию вложил в исполняемый скрипт и при выполнении ее оттуда доставал, разархивировал и отправлял. Но заметка сама не о инструкции, а об неоптимальном использовании некоторых команд.
Сама команда которая мне не понравилась и которую я захотел оптимизировать выглядит так
В ней мы получаем смещение в строках от начала файла до заархивированных данных в конце файла.
Первое что мне бросилось в глаза это использование cat и awk через pipe. Естественно я сразу переписал на
Но и этого мне показалось мало. Зачем использовать еще и wc если и так используем awk, который может делать намнго больше. В тоге получилось нечто такое
И опять, слишком много символов, и очень трудночитаемо, в результате имеем
Но, здесь не выполняется условие что до первого вхождения символов #END. Хотя меня это устраивает, ради интересе запустив на выполнение скрипт на данных тескта более 500 мегабайт, обнаружил что время выполнения скрипта было примерно около 25 секунд. Я начал искать функцию exit (как мне потом посоветовал хабрачеловек oxpa ) на awk, но в тот момент из-за невнимательности я не смог ее заставить работать, как смешно это не звучит, и я начал смотреть в сторону sed. В итоге получилось вот такое
Проверив на том же файле в 500 мегабайт увидел время выполнение менее 2 секунд. Отлично, но зачем нам смотреть весь файл, да и опять же в первом варианте было условие до первого вхождения в файл. Не оставалось ничего как переписать на такой вариант
ну или можно на awk
Спасибо за внимание!
ЗЫ: от хабрачеловека oxpa (за что ему большое Спасибо!) поступил такой вариант
данный вариант работает в два раза быстрее варианта на sed, конечно речь идет о том если файл большой и метка стоит в конце.
Ковыряя свои давние скрипты, нашел один скрипт примерно такого содержания:
#!/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)
Спасибо за внимание!
ЗЫ: от хабрачеловека oxpa (за что ему большое Спасибо!) поступил такой вариант
SKIP=$(grep -A1 -n "^#END" $0 | tail -1 | cut -f 1 -d -)
данный вариант работает в два раза быстрее варианта на sed, конечно речь идет о том если файл большой и метка стоит в конце.
