cat, awk и все таки sed

в 11:32, , рубрики: linux, Программирование

Всем доброго времени!

Ковыряя свои давние скрипты нашел один скрипт примерно такого содержания

#!/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

Поделиться

* - обязательные к заполнению поля