BASH Keep counter through reboots - bash

I'm trying to keep a external counter in my bash script.
As most of the script is specific to what it's for, I'm only going to insert the pertinent parts that I can't seem to get working. Everything before does get defined. Also before someone comments about the cat, I tried (< $TMPFILE) as well. The issue appears to be not writing to the file.
#!/bin/bash
TMPFILE="/tmp/nettestnum"
if [ -e "$TMPFILE" ]; then I=$(cat $TMPFILE); else I="1"; fi
nettest_start() {
grep -q "/root/bin/nettest" /etc/rc.local
if [ $? -eq 1 ]; then
sed -i 's|touch /var/lock/subsys/local|touch /var/lock/subsys/local \&\& /root/bin/nettest|' /etc/rc.local 2>&-
echo "Script started at $DATEVAL" >> "$LOGFILE" 2>&1
echo "Script will run every $TIMELb minutes, $LIMIT times"
touch "$TMPFILE"
nettest_run
else
echo "Nettest is already started and will relaunch upon next reboot"
fi
}
nettest_run() {
echo "$DATE : Starting scan" >> "$LOGFILE" 2>&1
#
while [[ "$I" -lt "$LIMIT" ]]
do
echo "$DATE : Starting scan" >> "$LOGFILE" 2>&1
#
HOSTS="$(...)"
for myHost in $HOSTS
do
PING=$(ping -f -c $COUNT "$myHost" |grep 'rtt' | awk '{print $4}')
echo "$myHost / $PING" >> "$LOGFILE" 2>&1
done
echo "$DATEVAL : Finished" >> "$LOGFILE" 2>&1
echo "$DATEVAL : Netstat Start" >> "$STATLOG" 2>&1
netstat -s |egrep -i "dropped|loss|reject|timeout|invalid" >> "$STATLOG" 2>&1
echo "$DATEVAL : Netstat Finished" >> "$STATLOG"G 2>&1
echo "." >> "$LOGFILE" 2>&1
sleep "$TIMEL"
let I++ || true
set +C
echo "$I" > "$TMPFILE"
done
}
Edit 4: re-added } and showing both functions.
I also need to figure out how to write an exit for the loop, but I'm pretty sure that's just a [ $? = 0 ]
Edit:
An example of some of the output I'm seeing when I run a status command (built into the script)..
Nettest is enabled on startup
PID number: 6059
Nettest is actively running in memory
On iteration of 100
iteration shows 1 on the first run.
Edit 2: redid the sample with full example, minus customized commands.

In the end, I got it working by adding 2>&1 to the line needed.
echo "$I" > "$TMPFILE" 2>&1

Try this:
if [ -e "$TMPFILE" ]; then I=`cat $TMPFILE`; else I=1; fi
while [[ $I -lt $LIMIT ]]

A while loop creates a subshell, with a copy of all your current variables.
#!/bin/bash
I=1
CHECK=1 # boolean for demonstration
while CHECK; do
let I++
CHECK=0
done
echo $I # prints 1, not two
This happens because the while subshell gets a copy of the I variable, which it increments. Once the subshell exits, the original variable comes back.
Your I variable is being incremented, and acting as your loop counter. I expect this is causing you all kinds of problems for properly ending your loop, and having other bits of this program see the "right" variable. I see no reason you could not replace the while loop with an equivalent for loop, and avoid all of these problems entirely.

Related

How can I avoid multiple starting of a bash script?

I wrote a little bash script called "wp", which upload files to an ftp server. It uses the wput utility. It takes the list of files from a text file. When uploading is ready it comments out the line with a double cross in the text file. The success of the upload is detected according to the last line in the logfile. My question is how can I avoid multiple starting of my script? I am trying to detect with pgrep if the instance is running, but doesn't work correctly:
#!/bin/bash
if [ "$(pgrep ^wp$|wc -l)" -eq "2" ]
then
echo "$(pgrep ^wp$)"
echo "$(pgrep ^wp$|wc -l)"
echo "wp script is starting..."
else
echo "$(pgrep ^wp$)"
echo "$(pgrep ^wp$|wc -l)"
echo "wp script is already running!"
exit
fi
server="ftp://username:password#ftp.ftpserver.com"
logfile=~/uploads.log
listfile=~/uploads.txt
list_backup=~/uploads_bak000.txt
while read f;
do
ret=""
if [ "${f:0:1}" = "#" -o "$f"1 = 1 ]
then
if [ "$f"1 = 1 ]
then
:
#echo "invalid string: "$f
else
#first character is remark sign # then empty command -> :
echo "remark line skipped: "$f
fi
else
#while string $ret is empty
while [ -z "$ret" ]
do
wput "$f" --tries=-1 "$server" 2>&1|tee -a $logfile #> /dev/null
ret=$(tail -n 1 "$logfile"|grep "FINISHED\|Nothing\|Skipped\|Transfered")
done
if [ -n "$ret" ]
then
cat $listfile > $list_backup
awk -v f="$f" '{if ($0==f && $0!~/#/) print "#" $0; else print $0;}' $list_backup > $listfile
fi
fi
done < $listfile
There are quick-n-dirty solutions that use ps with grep (don't do this).
It is better to use a lock file as a "mutex". A nice way of doing this is by using a directory as a lock file (http://mywiki.wooledge.org/BashFAQ/045).
I would also suggest taking a look at:
http://mywiki.wooledge.org/ProcessManagement#How_do_I_make_sure_only_one_copy_of_my_script_can_run_at_a_time.3F
, which mentions use of setlock(http://cr.yp.to/daemontools/setlock.html) that abstracts the lock file handling for you.

Bash about repeat until

I want to know about that syntax is correct or not. I cant test it right now sorry, but its important for me. Its an FTP script. The file name is a.txt, I would like to create a script that will upload a file until it is successful. It will works or not? Anyone can help me to build the correct one pls
LOGFILE=/home/transfer_logs/$a.log
DIR=/home/send
Search=`ls /home/send`
firstline=`egrep "Connected" $LOGFILE`
secondline=`egrep "File successfully transferred" $LOGFILE`
if [ -z "$Search" ]; then
cd $DIR
ftp -p -v -i 192.163.3.3 < ../../example.script > ../../$LOGFILE 2>&1
fi
if
egrep "Not connected" $LOGFILE; then
repeat
ftp -p -v -i 192.163.3.3 < ../../example.script > ../../$LOGFILE 2>&1
until
[[ -n $firstline && $secondline ]];
done
fi
example.script contains:
binary
mput a.txt
quit
Does ftp not return a reasonable result? It would be easiest to write:
while ! ftp ...; do sleep 1; done
If you insist on searching the log file, do something like:
while :; do
ftp ... > $LOGFILE
grep -qF "File successfully transferred" $LOGFILE && break
done
Or
while ! test -e $LOGFILE || grep -qF "Not connected" $LOGFILE; do
ftp ... > $LOGFILE
done
It will works or not?
No, it won't work. According to §3.2.4.1 "Looping Constructs" of the Bash Reference Manual, these are the kinds of loops that exist:
until test-commands; do consequent-commands; done
while test-commands; do consequent-commands; done
for name [ [in [words …] ] ; ] do commands; done
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
You'll notice that none of them begins with repeat.
Additionally, these two lines:
firstline=`egrep "Connected" $LOGFILE`
secondline=`egrep "File successfully transferred" $LOGFILE`
run egrep immediately, and set their variables accordingly. This command:
[[ -n $firstline && $secondline ]]
will always give the same return-value, because nothing in the loop will ever modify $firstline and $secondline. You need to actually put an egrep command inside the loop.

bash: running cURLs in parallel slower than one after another

We have to cache quite a big database of data after each upload, so we created a bash script that should handle it for us. The script should start 4 paralel curls to the site and once they're done, start the next one from the URL list we store in the file.
In theory everything works ok, and the concept works if we run the run 4 processes from our local machines to the target site.
If i set the MAX_NPROC=1 the curl takes as long as it would if the browser hits the URL
i.e. 20s
If I set the MAX_NPROC=2 the time request took, triples.
Am I missing something? Is that an apache setting that is slowing us down? or is this a secret cURL setting that I'm missing?
Any help will be appreciated. Please find the bash script below
#!/bin/bash
if [[ -z $2 ]]; then
MAX_NPROC=4 # default
else
MAX_NPROC=$2
fi
if [[ -z $1 ]]; then
echo "File with URLs is missing"
exit
fi;
NUM=0
QUEUE=""
DATA=""
URL=""
declare -a URL_ARRAY
declare -a TIME_ARRAY
ERROR_LOG=""
function queue {
QUEUE="$QUEUE $1"
NUM=$(($NUM+1))
}
function regeneratequeue {
OLDREQUEUE=$QUEUE
echo "OLDREQUEUE:$OLDREQUEUE"
QUEUE=""
NUM=0
for PID in $OLDREQUEUE
do
process_count=`ps ax | awk '{print $1 }' | grep -c "^${PID}$"`
if [ $process_count -eq 1 ] ; then
QUEUE="$QUEUE $PID"
NUM=$(($NUM+1))
fi
done
}
function checkqueue {
OLDCHQUEUE=$QUEUE
for PID in $OLDCHQUEUE
do
process_count=`ps ax | awk '{print $1 }' | grep -c "^${PID}$"`
if [ $process_count -eq 0 ] ; then
wait $PID
my_status=$?
if [[ $my_status -ne 0 ]]
then
echo "`date` $my_status ${URL_ARRAY[$PID]}" >> $ERROR_LOG
fi
current_time=`date +%s`
old_time=${TIME_ARRAY[$PID]}
time_difference=$(expr $current_time - $old_time)
echo "`date` ${URL_ARRAY[$PID]} END ($time_difference seconds)" >> $REVERSE_LOG
#unset TIME_ARRAY[$PID]
#unset URL_ARRAY[$PID]
regeneratequeue # at least one PID has finished
break
fi
done
}
REVERSE_LOG="$1.rvrs"
ERROR_LOG="$1.error"
echo "Cache STARTED at `date`" > $REVERSE_LOG
echo "" > ERROR_LOG
while read line; do
# create the command to be run
DATA="username=user#server.com&password=password"
URL=$line
CMD=$(curl --data "${DATA}" -s -o /dev/null --url "${URL}")
echo "Command: ${CMD}"
# Run the command
$CMD &
# Get PID for process
PID=$!
queue $PID;
URL_ARRAY[$PID]=$URL;
TIME_ARRAY[$PID]=`date +%s`
while [ $NUM -ge $MAX_NPROC ]; do
checkqueue
sleep 0.4
done
done < $1
echo "Cache FINISHED at `date`" >> $REVERSE_LOG
exit
The network is almost always the bottleneck. Spawning more connections usually makes it slower.
You can try to see if parallel'izing it will do you any good by spawning several
time curl ...... &

how to use a nested if and perform correct file checks in unix

Need some shell scripting help, especially with my if-then-else logic. I want to combine both conditions, but not sure if the file checks will work the same? Should I be doing something like a nested if?? My script uses the if statements to do file checks to see if they exist, then do something..
There is probably a better way to do file checks part too.
Any help, critique would be appreciated. Thanks.
Here's my code, it sort of works.
if [ $# != 1 ]; then
echo "Usage: getlogs.sh <remote-host>" 2>&1
exit 1
fi
#Declare variables
STAMP=`date '+%Y%m%d-%H:%M'`
REMOTE_MYCNF=/var/log/mysoft/mysoft.log
REMOTE_GZ=/var/log/mysoft/mysoft.log.1.gz
REMOTE_DIR=/var/log/mysoft/
BACKUP_DIR=/home/mysql/dev/logs/
NEWLOG="foo-temp.log"
export REMOTE_MYCNF STAMP SHORTNAME
export REMOTE_DIR REMOTE_GZ
#Copy file over
echo "START..." 2>&1
test -f $BACKUP_DIR$1.mysoft.log
if [ $? = 0 ]; then
echo "Local log file exists, clean up for new copy..." 2>&1
/bin/rm $BACKUP_DIR$1.mysoft.log
exit 0
else
echo "File does not exist, getting a new copy..." 2>&1
fi
echo "Checking remotely in $1 for foo logfile $REMOTE_MYCNF $STAMP" 2>&1
if [ ! -f $REMOTE_MYCNF ]; then
echo "File exists remotely, creating new logfile and copy here...." 2>&1
ssh $1 "zcat $REMOTE_GZ >> $REMOTE_DIR$NEWLOG"
ssh $1 "cat $REMOTE_MYCNF >> $REMOTE_DIR$NEWLOG"
/usr/bin/scp $1:$REMOTE_DIR$NEWLOG $BACKUP_DIR$1.mysoft.log
echo "end remote copy" 2>&1
echo "Cleaning up remote files" 2>&1
ssh $1 "rm $REMOTE_DIR$NEWLOG"
exit 0
else
echo "Unable to get file" 2>&1
exit 0
fi
Updated code using help:
if [ -f $BACKUP_DIR$1.mysoft.log ]; then
echo "Local log file exists, clean up for new copy..." 2>&1
/bin/rm $BACKUP_DIR$1.mysoft.log
exit 0
else
echo "File does not exist, getting a new copy..." 2>&1
echo "Checking remotely in $1 for foo logfile $REMOTE_MYCNF $STAMP" 2>&1
if [ ! -f $REMOTE_MYCNF ]; then
echo "File exists remotely, creating new logfile and bring a copy here...." 2>&1
ssh $1 "zcat $REMOTE_GZ >> $REMOTE_DIR$NEWLOG"
ssh $1 "cat $REMOTE_MYCNF >> $REMOTE_DIR$NEWLOG"
/usr/bin/scp $1:$REMOTE_DIR$NEWLOG $BACKUP_DIR$1.mysoft.log
echo "end remote copy" 2>&1
echo "Cleaning up remote files" 2>&1
ssh $1 "rm $REMOTE_DIR$NEWLOG"
exit 0
else
echo "Unable to get file" 2>&1
exit 0
fi
fi
The file test can be combined into one statement like this:
if [ -f $BACKUP_DIR$1.mysoft.log ]; then
At a glance, it doesn't look like you need to export any of the variables.
If you intend for the if [ ! -f $REMOTE_MYCNF ]; then block to be executed within the else of the previous if, just move it within it.
if ...
then
foo
else
if ...
then
bar
else
baz
fi
fi
If you need to check two things:
if [ "$foo" = "bar" && "$baz" = "qux" ]
Always quote your variables.
In a short script it's fine to use positional parameters such as $1 directly, but it makes a longer script easier to understand if a variables with meaningful names are assigned their values near the top.
remote_host=$1
When you want to echo errors to stderr do it this way:
echo "Message" >&2
The way you have it, you're echoing the message and any errors the echo itself may produce (pretty rare) to stdout.

How can a bash script write out a binary file, without using uudecode?

I've got a little puzzler here for the bash scripting experts... I have a bash script that needs to create a small (80 byte) binary file when it runs. The contents of the file need to be contained inside the script itself (i.e. I don't want to just package the file along with the script).
My script currently does it like this:
echo 'begin-base64 644 dummy.wav' > /tmp/dummy.uu
echo 'UklGRkgAAABXQVZFZm10IBAAAAADAAEAAHcBAADcBQAEACAAZmFjdAQAAAAAAAAAUEVBSxAAAAAB' >> /tmp/dummy.uu
echo 'AAAAQDYlTAAAAAAAAAAAZGF0YQAAAAA=' >> /tmp/dummy.uu
echo '====' >> /tmp/dummy.uu
uudecode -o /tmp/dummy.wav /tmp/dummy.uu
rm /tmp/dummy.uu
... after the above runs, I have my file /tmp/dummy.wav. But I just found out that the computer this script is to run on does not have uudecode installed (and I'm not allowed to install it), so I need to find some other way to create this file. Any ideas?
Some installers do something similar to this:
#!/bin/bash
tail -n +4 $0 | tar xvzf -
exit
<tgz file appended here><newline>
If the target computer has perl available:
perl -ne 'print unpack("u",$_)' > dummy.wav <<EOD
M4DE&1D#```!7059%9FUT(!`````#``$``'<!``#<!0`$`"``9F%C=`0`````
C````4$5!2Q`````!````0#8E3```````````9&%T80``````
EOD
That's using the non-base64 format you get from just doing uuencode dummy.wav < dummy.wav on your original computer.
Failing that, you can always do this:
echo -ne '\x52\x49\x46\x46\x48\x00\x00\x00' > dummy.wav
echo -ne '\x57\x41\x56\x45\x66\x6d\x74\x20' >> dummy.wav
echo -ne '\x10\x00\x00\x00\x03\x00\x01\x00' >> dummy.wav
echo -ne '\x00\x77\x01\x00\x00\xdc\x05\x00' >> dummy.wav
echo -ne '\x04\x00\x20\x00\x66\x61\x63\x74' >> dummy.wav
echo -ne '\x04\x00\x00\x00\x00\x00\x00\x00' >> dummy.wav
echo -ne '\x50\x45\x41\x4b\x10\x00\x00\x00' >> dummy.wav
echo -ne '\x01\x00\x00\x00\x40\x36\x25\x4c' >> dummy.wav
echo -ne '\x00\x00\x00\x00\x00\x00\x00\x00' >> dummy.wav
echo -ne '\x64\x61\x74\x61\x00\x00\x00\x00' >> dummy.wav
This little bit of bash was generated with:
$ hexdump -e '"echo -ne '\''" 8/1 "x%02x" "'\'' >> dummy.wav\n"' dummy.wav | sed 's;x;\\x;g;1s/>/ /'
Edited to add:
As pointed out in a reply here, something like this is also a possibility:
xargs -d'\n' -n1 echo -ne > dummy.wav <<EOD
\x52\x49\x46\x46\x48\x00\x00\x00\x57\x41\x56\x45\x66\x6d\x74\x20
\x10\x00\x00\x00\x03\x00\x01\x00\x00\x77\x01\x00\x00\xdc\x05\x00
\x04\x00\x20\x00\x66\x61\x63\x74\x04\x00\x00\x00\x00\x00\x00\x00
\x50\x45\x41\x4b\x10\x00\x00\x00\x01\x00\x00\x00\x40\x36\x25\x4c
\x00\x00\x00\x00\x00\x00\x00\x00\x64\x61\x74\x61\x00\x00\x00\x00
EOD
(the -d argument is important to turn off xargs's own backslash processing)
You can also turn the 8/1 in my hexdump command into 80/1 and have a single long echo line.
Put an exit at the end of your script, append the file to the end of the script, and use tail -c 80 to get at the contents. This will work as long as you don't need to worry about newline conversion issues.
This is another example to decode radix 64 formatted data, it runs slow, but it is functional.
#!/bin/bash
exec<$0
while read line ; do if [ "$line" = "#payload" ] ; then break; fi; done
r64='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
i=0; while [ $i -lt 256 ] ; do tab[$i]=-1 ; let i=$i+1 ;done
i=0; while [ $i -lt 64 ] ; do tab[`printf "%d" "'${r64:$i:1}"`]=$i ; let i=$i+1; done
bi=0
while read -n 1 x
do
in=${tab[`printf "%d" "'$x"`]}
if [ $in -ge 0 ]; then case $bi in
0 ) out=$(($in<<2)); bi=6 ;;
2 ) out=$(($out|$in)); printf \\$(printf '%03o' $(($out&255)) ); bi=0 ;;
4 ) out=$(($out+($in>>2))); printf \\$(printf '%03o' $(($out&255)) );
bi=0; out=$(($in<<6)); bi=2 ;;
* ) out=$(($out+($in>>4))); printf \\$(printf '%03o' $(($out&255)) );
bi=0; out=$(($in<<4)); bi=4 ;;
esac fi
done
exit
#payload
dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2XmAgICAte3Z2dnZ2dnZ2dnZ2dnZ2dgp2dnZ2dnZ2dnZ2dnZ2dnZ2PiAg
ICAgIC4gLXZ2dnZ2dnZ2dnZ2dnZ2CnZ2dnZ2dnZ2dnZ2dnZ2dn0gICAgICAgPT4gLXZ2dnZ2dnZ2dnZ2
dnYKdnZ2dnZJdnZJdnZJdnZJOyAgICAgICAtICAgPXZJdkl2dkl2dkl2dgp2dnZ2SXZ2dnZ2dnZ2dnZg
ICAgICAgICAgICAgbnZ2dnZJdnZ2dnZ2CnZ2dnZ2dnZ2SXZJdnZJdiAgIC4gICAgICwgICA8dnZ2SXZ2
dkl2dkkKdnZ2SXZ2SXZ2dnZ2SXZJIF9zOyAgX3VvLyAgID12dnZ2dnZ2dnZJdgp2dnZ2dkl2dnZJdnZ2
dnYgdyRtICBtQCRtICAgPXZ2dnZJdnZJdnZ2CnZ2dnZJdnZ2dnZ2dkl2SSBmPTQuO1cgYFE7ICA9dnZ2
dnZ2dnZ2dnYKdnZ2SXZ2dnZJdnZJdnZ2IHQtM3MlJiAgbWAgID12dnZ2SXZJdnZJdgp2dnZ2dnZ2SXZ2
dnZ2dnYgXWlvWjZYYXVQICAgPXZ2dnZ2dnZ2SXZ2CnZ2dkl2dkl2dnZJdnZJdi4pbVojWlojWlMgICAu
dnZ2SXZJdnZ2dnYKdnZ2dnZ2dnZ2dnZ2SXZ2OjNYWlpaI1pTWCAgICB7dnZ2dnZ2dkl2dgp2dnZ2SXZ2
SXZ2SXZ2dnY7PFNYWlhTZFhuIC5pLj12dnZJdnZJdnZ2CnZ2dkl2dnZ2dkl2dnZ2dmBdJVhYWlhubW0+
IC1gIHZ2dnZ2dnZ2dnYKdnZ2dnZ2SXZ2dnZ2SXYlIGptdklud1FXUW0gICAgPHZ2SXZ2SXZ2SQp2dnZJ
dnZ2dkl2dkl2dmAuUVFvWG1tUVFRUWMgICAge0l2dnZ2dnZ2CnZ2dnZ2dkl2dnZ2dnYrIGpRV1FtV1FR
UVFRayAgICAtdnZ2dkl2dkkKdnZ2dkl2dnZ2SXZJPiBfUVFRUVFRUVFRUVFRLiAgICA9dkl2dnZ2dgp2
dnZJdnZ2SXZ2dmwgIF1RUVFRV1FRUVdXOCRMICAgICA8dnZ2SXZ2CnZ2dnZ2dnZ2dnZ2OyAgbm1RUVFt
UVFRbXdvb20gLiAgIC1JdnZ2dnYKdnZ2SXZ2SXZ2SX0gID1RV1FRUVFRUVFRUVFtMlsgLSAgID12dkl2
dgp2dnZ2dnZ2dkl2Oy4gZFFRUVFRUVFRUVFRUVFRcSAgLiAgIEl2dnZ2CnZ2dnZJdkl2dnZgLjxRUVFR
UVFRUVFRUVFRUVdRKC4uLiAgPEl2dnYKdnZ2SXZ2dnZ2PiAgZFFRUVFRUVFRUVFRUVFRUVFbICAuICAg
dnZ2SQp2dnZ2dnZ2dnYnIC5RUVFRUVFRUVFRUVFRUVFRUWsgIC4gICB7dnZ2CnZ2dkl2dkl2PiAuXVFR
UVFRV1dXUVFRUVFRUVFRbSAgICAgIClsdnYKdnZ2dnZ2dnZgIDpqUVFRUVEjUVdRUVFRUVFRUVFXICAu
ICAgOnZ2SQp2dnZ2SXZ2bCAgOmpXUVFRUUVXV1FRUVFRV1FRUVcgIGAgICA6dnZ2CnZ2dkl2dnZJLl86
alFRUVFRRVdRUVFRUVFRUVFRVyAuIC4uID12dnYKdnZ2dnZ2dnZkIzYvUVdRUVFFUVFRUVFRUVFRV1dM
LiAgIDogKXZ2dgp2dnZJdnZJMyNaWkwtJFFRUVFRV1FRUVFRUVFCWiNgICAgLmRvdnZ2CnZ2dnZ2SXZa
IyMjWj4tNFFRUVdRUVFRUVFRUUVaay4gICBqWlh2dnYKdnZ2dndvbVgjWiNaIy4gNFFRUVFRUVFRUVdX
MVpYc189dVhaaHZ2dgp2dnZaWiNaI1VVWiNaTCAgXVFRUVFRUVFRUVdlWFpYcVhtWiNVenZ2CnZ2SVgj
I1ojWiMjWiNaLyAuUVFRUVFRUVFRVzEzI1paWlojWiMjb3YKdnZ2ZFVaIyNVWiMjVVVoX2FRUVFRUVFR
UVFQOlhaIyNVI1ojVVojaAp2dklkIyNaI1ojI1ojWlpaV1FRUVFRUVFXUCA9ZFojWiNaIyNaIyNaCnZ2
dlojWiMjVVVaI1ojWlpKUVFRUVFXUF4gIClYIyNaI1VVWiNVWjEKdnZ7WlojWlVaIyNaIyNaVXMtIT8i
fiAgICAgdlgjWiMjWiNaWF5sdgp2bCBZWFhYWFpaVVUjWlpaMS4gICAgICAgICB2WFojWiNaWCIgIDx2
CnZzICAtfiJJMVhYWFpaWm8xICAgICAgICAgIEluWFhaU31gICAgPHYKdnY7ICAgICAtLTwxMjIxbGAg
ICAgICAgICAgPElubjF9ICAgICB2SQp2dmwsICAgICAgICB+Kz5gICAgICAgICAgICAgfnwrfiAgICAu
JUl2CnZ2dnZpLiAgICAgICAgICAgIF9pc2ksICAgICAgICAgICAgX3ZJdnYKdnZ2dnZ2c19fXy4uLi5f
XyV2dnZ2SXZpLCxfLiAuLl9fPnZ2dnZ2dgp2dnZ2SXZ2dm52dnZ2dnZudnZ2dnZ2dnZubnZ2dnZ2dnZ2
dnZ2dnZ2Cg==
#!/bin/bash
# Define usage help
usage () {
echo -e "USAGE:\n\t$0 <file to create> <dir to tar> <name of script or command to run>\n"
exit 0
}
# check commandline arguments
if [ "$1" = "-h" ]; then usage; fi
if [ -z $1 ]; then usage; fi
if [ -z $2 ]; then usage; fi
if [ -z $3 ]; then usage; fi
# test for the directory and if it exists, create the bin file using tar
if [ -d "$2" ]; then
cat >$1<<EOF
#!/bin/sh -e
sed -e '1,/^exit$/d' "\$0" | tar xzf - && "./$2/$3"
exit
EOF
tar czf - $2 >> $1
else
echo "$2 does not exist, aborting!"
exit 1
fi
# make the new file executable and exit
chmod +x $1
exit 0
I would use base64 encoding, as that seems to be the general replacement for uu encoding, and operates on very similar principles.
From my point of view uuencode and uudecode are essential, but
that's only my opinion.
Without creating temporary files you could also do something
like this (uudecode.sh):
#!/bin/bash
# --
# -- Uudecoding without using a regular temporary file
# --
# -- Create a named pipe:
mknod /tmp/.dummypipe p
# -- Starting uudecoding on that pipe in the background:
uudecode -o dummy.txt /tmp/.dummypipe &
# -- Push base64-uuencoded content into the named pipe:
cat <<END_DUMMY > /tmp/.dummypipe
begin-base64 644 dummy.txt
VGhpcyBpcyB0aGUgdXVkZWNvZGVkIHRleHQuCg==
====
END_DUMMY
# -- Remove the named pipe
rm /tmp/.dummypipe
Just encode the binary data in base64 and do something like this:
#! /bin/bash
cat <<EOF | base64 -d > wherever-it-goes.bin
UtEOtUaZcUCrEJtPJrA34BH8Wdpxb1/DtfMo5syiE/h+moNyApEkg2ZwA2/jTDdfl4WijnNbMzvZ
RrF3i7X353AjmTjLBz1NcOOJJhRPYLJ4WQYONyYj/fAhnXQd+s4SHaNponOWKj1AAzdlJY1VLWaX
P8QBJQcn2FTL4pJ3N04=
EOF

Resources