Sometimes, when running 1 bash script repeatedly on several different machines, I found that being able to download and immediately execute a script is very handy.
The following command will download a script and immediately execute it:
bash<(curl -s http://geeklab.info/my-script.sh)
bash <(curl -s http://geeklab.info/my-script.sh)
This command uses Bash's Process Substitution to do it's job. command2 <(command) means for bash to put the output of command in a pipe and then run command2 [tempfile]. So above statement does the same as:
Process substitution is also very useful when you want to know the difference between the output of two commands:
diff<( command1 )<( command2 )
diff <( command1 ) <( command2 )
Furthermore, it's possible to pipe the contents of the temporary file into command2. For instance: bash < <(curl http://geeklab.info/my-script.sh)
would do the same as:
I created some scripts to backup my Samsung Galaxy S2 to my Fedora 16 system without pressing any keys or even touching the mouse. It works like this:
To backup a SGS2, you go to settings > applications > usb tools on the phone, and click the button. You then connect it to a usb cable. At that moment, two removable devices become visible to the Linux system: one for the SD card, one for the built-in memory. But they still contain no media. Only when you press another button on the phone, the "media are inserted in the devices", triggering a "change" action with the udev daemon.
Configuration of the udev daemon
Create a file /etc/udev/rules.d/71-android-backup.rules:
Whenever a (virtual) medium is inserted, a udev change action is triggered. Actually, it gets triggered multiple times, but we only need the one that has the environment variable DISK_MEDIA_CHANGE=1 set.
Action to perform
The action triggered is /usr/local/bin/androidbackup and all parameters are in the environment. So let's create that file. I use a rsnapshot-like operation to backup my data, but without actually using rsnapshot.
#!/bin/bashfunction msg {/usr/bin/logger -t android "$1"DISPLAY=:0 qdbus $dbusRef setLabelText "$1"DISPLAY=:0 qdbus $dbusRef Set "" value $2}if["$1"!= "FORKED"]; then$0 FORKED &exit0fiif[-f/etc/sysconfig/androidbackup ]; then
. /etc/sysconfig/androidbackup
elseecho/etc/sysconfig/androidbackup does not exist
exit0fi#debug disabled:#set > /tmp/android/`date +%s`.$RANDOMdbusRef=`kdialog--display :0--progressbar"Backup android..."100`
msg "Attach $DEVNAME$ACTION$ID_SERIAL"0if[!-e$DESTINATION]; then# I could mkdir -p, but sometimes $DESTINATION could just be a network location that's offline
msg "Android will not be backed up: $DESTINATION is not okay"0exit0fimkdir-p/mnt/android
mount$DEVNAME/mnt/android
rc=$?if[$rc-ne0]; then
msg "Problem mounting $DEVNAME to /mnt/android: $rc "0mount|grep android 2>&1| logger -t androidbackup
exit0fiif["`mount |grep -i /mnt/android`" == ""]; then
msg "Cannot find /mnt/android in mount table"0exit0fi
msg "Remove old backup"8[-e$DESTINATION/backup.30 ]&&rm-rf$DESTINATION/backup.30
msg "Start backup"10for i in`/usr/bin/seq30-12`; doif[-e$DESTINATION/backup.$((i-1))]; then
msg "mv $DESTINATION/backup.$((i-1)) $DESTINATION/backup.$i"11mv$DESTINATION/backup.$((i-1))$DESTINATION/backup.$ifidone
msg "Copy"40[-e$DESTINATION/backup.0 ]&&/bin/cp-al$DESTINATION/backup.0 $DESTINATION/backup.1
mkdir-p$DESTINATION/backup.0/
msg "Start rsync"40/usr/bin/rsync -az--numeric-ids--delete--hard-links/mnt/android/$DESTINATION/backup.0/touch$DESTINATION/backup.0/chown-R$CHOWN$DESTINATION/backup.0
umount/mnt/android
msg "Done"100exit0
#!/bin/bash function msg {
/usr/bin/logger -t android "$1"
DISPLAY=:0 qdbus $dbusRef setLabelText "$1"
DISPLAY=:0 qdbus $dbusRef Set "" value $2
} if [ "$1" != "FORKED" ]; then
$0 FORKED &
exit 0
fi if [ -f /etc/sysconfig/androidbackup ]; then
. /etc/sysconfig/androidbackup
else
echo /etc/sysconfig/androidbackup does not exist
exit 0
fi #debug disabled:
#set > /tmp/android/`date +%s`.$RANDOM dbusRef=`kdialog --display :0 --progressbar "Backup android..." 100` msg "Attach $DEVNAME $ACTION $ID_SERIAL" 0 if [ ! -e $DESTINATION ]; then
# I could mkdir -p, but sometimes $DESTINATION could just be a network location that's offline
msg "Android will not be backed up: $DESTINATION is not okay" 0
exit 0
fi mkdir -p /mnt/android mount $DEVNAME /mnt/android
rc=$?
if [ $rc -ne 0 ]; then
msg "Problem mounting $DEVNAME to /mnt/android: $rc " 0
mount | grep android 2>&1 | logger -t androidbackup
exit 0
fi if [ "`mount |grep -i /mnt/android`" == "" ]; then
msg "Cannot find /mnt/android in mount table" 0
exit 0
fi msg "Remove old backup" 8
[ -e $DESTINATION/backup.30 ] && rm -rf $DESTINATION/backup.30 msg "Start backup" 10
for i in `/usr/bin/seq 30 -1 2`; do
if [ -e $DESTINATION/backup.$((i-1)) ]; then
msg "mv $DESTINATION/backup.$((i-1)) $DESTINATION/backup.$i" 11
mv $DESTINATION/backup.$((i-1)) $DESTINATION/backup.$i
fi
done msg "Copy" 40
[ -e $DESTINATION/backup.0 ] && /bin/cp -al $DESTINATION/backup.0 $DESTINATION/backup.1
mkdir -p $DESTINATION/backup.0/ msg "Start rsync" 40
/usr/bin/rsync -az --numeric-ids --delete --hard-links /mnt/android/ $DESTINATION/backup.0/
touch $DESTINATION/backup.0/ chown -R $CHOWN $DESTINATION/backup.0 umount /mnt/android msg "Done" 100
exit 0
Since that file refers to /etc/sysconfig/androidbackup, let's also make that file:
#next line defines the location of all backupsDESTINATION=/home/geeklab/.androidbackup
#next line defines the owner of all files copiedCHOWN=geeklab
#next line defines the location of all backups
DESTINATION=/home/geeklab/.androidbackup #next line defines the owner of all files copied
CHOWN=geeklab
As I may have mentioned before VMWare Data Recovery is not my favorite backup solution. I'm pleased to report that VDR2.0 is a LOT better than 1.x ever was. Since upgrading, my backups haven't failed once. And it even has a built-in email reporting system.
Unfortunately, this mail system isn't too customizable. Since I'd like my subjects to be clear they need extra attention, I made a little fix. This script is started by socat.
Install socat
Socat handles incoming connections on port 25 for me. rpm -i http://download.fedora.redhat.com/pub/epel/5/x86_64/socat-1.7.1.3-1.el5.x86_64.rpm
Change the outgoing mailserver to localhost and test it. If everything's ok, you'll get a mail with 1 warning and 2 error-message, as the test-mail doesn't contain the fields that indicate no backups failed.
Security
The iptables firewall does not allow incoming connections to port 25, so you will not become an open relay using this script.