📜 ⬆️ ⬇️

cat, awk and sed

All the good time!

Picking up my old scripts, I found one script similar to the following:

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

In principle, the script provides a menu for selecting a container file and sends the file with an instruction to the specified address. In order to be able to transfer the script to different servers and not to think about the instructions, I put the instructions in the executable script and when executing it I took it out, unzipped it and sent it. But the note itself is not about the instructions, but about the non-optimal use of some commands.
The very team that I did not like and that I wanted to optimize looks like this
 SKIP=$((`cat $0 | awk '/#!\/bin\/sh/,/^#END/{print}'|wc -l`+1)) 

In it we get the offset in the lines from the beginning of the file to the archived data at the end of the file.
The first thing that caught my eye was the use of cat and awk through a pipe. Naturally, I immediately rewrote to
 SKIP=$((`awk '/#!\/bin\/sh/,/^#END/{print}' $0|wc -l`+1)) 

But this seemed to me a little. Why use wc also if you use awk, which can do more than that. In toga something happened
 SKIP=$(awk 'BEGIN{comp_str=0} /#!\/bin\/sh/,/^#END/{comp_str++} END{print ++comp_str}' $0) 

And again, too many characters, and very hard to read, as a result we have
 SKIP=$(awk '/^#END/{print ++NR}' $0) 

But, here the condition is not satisfied that before the first occurrence of #END characters. Although it suits me, for the sake of interest, having run the script on the test data for more than 500 megabytes, I found that the script execution time was about 25 seconds. I started to look for the exit function (as I was advised by the habrechelok oxpa ) on awk, but at that moment due to inattention I couldn’t get it to work, how funny it doesn’t sound, and I started looking towards sed. The result was this
 SKIP=$((`sed -n '/^#END/{=}' $0` + 1)) 

Checking on the same file in 500 megabytes saw the execution time less than 2 seconds. Great, but why do we need to watch the entire file, and again, in the first version, there was a condition before the first entry into the file. There was nothing like to rewrite this option
 SKIP=$((`sed -n '/^#END/{=;q;}' $0` + 1)) 

well, or awk
 SKIP=$(awk '/^#END/{print ++NR; exit;}' $0) 

Thanks for attention!

PS: from habrachelovek oxpa (for which he thanks a lot!) Did this option
 SKIP=$(grep -A1 -n "^#END" $0 | tail -1 | cut -f 1 -d -) 

This option works twice as fast as the version on sed, of course, it’s about if the file is large and the label is at the end.

')

Source: https://habr.com/ru/post/152183/


All Articles