5

I created the following script to install and then uninstall PHPmyadmin on Ubuntu 16.04...

My aim is to use this script each time I want to use PHPmyadmin, and then, after some time like 2 hours, delete it. This install-use-uninstall method is used from security reasons (keeping MySQL inaccessible as possible and accessed only locally for very short periods of time).

bash /dev/fd/15 15<< 'EOF0'    

#!/bin/bash -x

# Install commands:

sudo apt-get install phpmyadmin
sudo phpenmod mcrypt
sudo phpenmod mbstring
cat << EOF1 >> /etc/apache2/apache2.conf

Include /etc/phpmyadmin/apache.conf
EOF1
sudo service apache2 restart

# Unnstall commands:

sleep 2h    
sudo phpdismod mcrypt mbstring
sudo apt-get purge phpmyadmin
sudo service apache2 restart
sed -i 's/Include \/etc\/phpmyadmin\/apache.conf/ /g /etc/apache2/apache2.conf

EOF0

As noted in the comments by Jeff (and as I edited the code example) I could use the sleep command, but sleep, in its classical form requires that the session will keep open, and the window might close sometimes from whatever reason, so a cannonical answer is needed that shows how to give this 2 hour suspension but in such a way that even if I mistakenly/intentionally close the window, or my PC rebooted from any reason, or there was a power outage --- The suspension and all commands after it will keep running on the VPS, without any interference from my end.

So, how could I execute the uninstall-commands 2 hours after the install-commands, but in a session-independent way?

9 Answers9

9

You can achieve it with the utility at.

For a single command, do:

at 'now + 2 hours' -f /path/to/uninstall.sh

For multiple commands, serve your script to the shell via cat heredocument:

cat << EOF | at 'now + 2 hours'
command1
command2
........
EOF

Alternatively, you could achieve that with a systemd solution (again, if you have it installed)

systemd-run --on-active=2h -- /bin/bash /path/to/uninstall.sh
apricot boy
  • 1,153
  • 7
  • 11
  • Hi, deep thanks. Please let me understand something, are you suggesting that I would create a script inside a script? (that is, the code example I gave in the question is already inside a script). –  Dec 27 '16 at 20:39
  • @Benia it doesn't have to really be a script inside a script, just as long as that script exists, you can do at 'now + 2 hours' -f uninstall.sh or systemd-run --on-active=2h -- /bin/bash uninstall.sh.

    If you'd like to entirely avoid creating another script, you can do the cat heredoc piped to at, or systemd-run .... /bin/bash -c 'sudo phpdismod mcrypt mbstring; sudo apt-get purge phpmyadmin; .....'

    – apricot boy Dec 27 '16 at 23:29
  • I noted a problem with this method here: http://unix.stackexchange.com/questions/333201/how-to-make-at-or-sleep-utilities-to-popup-stdout-on-highest-bash-session –  Dec 28 '16 at 06:52
  • This didn't work for me in WSL but should work on native Linux system, hence I give the bounty. Thank you Apricot boy. –  Dec 31 '16 at 02:51
2

As I can see you have sudo access and could start services. So you could use atd service and at command to schedule your task:

echo 'touch $HOME/`date -j +%s`.txt' | at + 2 minutes

And for more than one command you have two options:

  1. Combine echo commands:

    (echo "command1"
     echo "command2"
     echo "command3" ) | at + 2 hours
    
  2. Use temp file for commands list:

     tmp_file=$(mktemp --tmpdir uninstall_commands.XXXX)
     echo "command1" >> ${tmp_file}
     echo "command2" >> ${tmp_file}
     echo "command3" >> ${tmp_file}
     at -f ${tmp_file} + 2 hours
     rm -f -- ${tmp_file}
    
  • So if I have say 5 uninstall commands I could just add | at + 2 minutes after each one ? Any why to add this to a whole block of commands instead for each one? Thanks! –  Dec 27 '16 at 19:51
  • 1
    I've editted my answer and add two options for a list of commands – Fedor Dikarev Dec 27 '16 at 20:10
  • Thank you!, I believe that if you combine echos in parenthesis you should server these stdin data inside a cat heredocument, as these are multiline and not singleline. –  Dec 27 '16 at 21:15
  • I noted a problem with this method here: http://unix.stackexchange.com/questions/333201/how-to-make-at-or-sleep-utilities-to-popup-stdout-on-highest-bash-session –  Dec 28 '16 at 06:52
1

Assuming two scripts (Do One Thing; Do It Well):

install.sh

#!/bin/sh -eu
sudo apt-get install phpmyadmin
sudo phpenmod mcrypt mbstring
printf 'Include /etc/phpmyadmin/apache.conf' >> /etc/apache2/apache2.conf
sudo service apache2 restart

uninstall.sh

#!/bin/sh -eu
sudo phpdismod mcrypt mbstring
sudo apt-get purge phpmyadmin
sudo service apache2 restart
sed -i 's/Include \/etc\/phpmyadmin\/apache.conf/ /g /etc/apache2/apache2.conf

The simplest answer I can think of that does exactly what you want is

./install.sh && sleep 2h && ./uninstall.sh >>/var/log/mylog.log 2>&1

where each script additionally includes an ssh command to connect to your server. This approach is resilient to the server power cycling - but not your terminal machine.

As an alternative I would simplify this answer mostly because of the bizarre behaviour of where atd puts its output and instead use

nohup sleep 2h && ./uninstall.sh >>/var/log/mylog.log 2>&1 &

Once executed, you now have approximately 2 hours to do whatever it is you want to do, and after the time is up, the uninstall process will happen. This approach is not resilient to the server power cycling.

This answer avoids dependencies and enables diagnostic/debugging by sensibly capturing and logging relevant output.

Edd
  • 141
  • 1
    This will fail across a reboot – Chris Davies Dec 27 '16 at 23:49
  • I noted a problem with this method here: http://unix.stackexchange.com/questions/333201/how-to-make-at-or-sleep-utilities-to-popup-stdout-on-highest-bash-session –  Dec 28 '16 at 06:51
  • @roaima How do the details in my answer about reboots fail to capture what your comment is trying to communicate? – Edd Dec 28 '16 at 16:42
  • Your answer doesn't solve the problem the OP is asking, which is to cope with unexpected power outages and other unintended reboots. – Chris Davies Dec 28 '16 at 18:08
1

First of all, you should structure your code into two scripts, or at least into two separate functions within the same script: the first one for installing, the second one for purging. So you can run either script/function when necessary. Both scripts/functions should also be idempotent, i.e. they should skip installing/purging in case it's already done.

Then, you could simply create a cronjob to call the purging script every 2h, or create a more periodic cronjob that calls the purging script if-and-only-if the installation is at least 2h old. This would survive a reboot of the server, so the package will always be purged.

Robin479
  • 335
0

I am not sure if this solution could fit your requirements, but you can give a try.

If for a moment forget about PC shutdown/reboot , then the following works in bash without trapping terminal (you can try it as one line command for test):

sleep 10 && yad --text="10 seconds passed" && exit &

Above command , although i didn't expect so , works even if i close my terminal window.

PS: If you combine it with nohup will keep the command running even if you log out.

As a workaround you could split your initiall script in two smaller scripts; one script for installation one script for removal, something like this:

#script_to_install.sh  
sudo apt-get install phpmyadmin
sudo phpenmod mcrypt mbstring
printf 'Include /etc/phpmyadmin/apache.conf' >> /etc/apache2/apache2.conf
sudo service apache2 restart
sleep 7200 && path/to/script_to_remove.sh &
exit #exit the first script to free terminal (or even close the terminal)
#end of script_to_install.sh

#script_to_remove.sh
#Optionally you can use xterm -e (or similar) to bring up a terminal window automatically to see the output of the commands
sudo phpdismod mcrypt mbstring
sudo apt-get purge phpmyadmin
sudo service apache2 restart
sed -i 's/Include \/etc\/phpmyadmin\/apache.conf/ /g /etc/apache2/apache2.conf
exit
#end of script_to_remove.sh

Coming back to the PC reboot part, i think that this can be solved by writing the start time to a temp log file, and once you reboot, you could monitor that temp file (i.e using inotify tools) to determine time period elapsed (not tested).

0

In bash, add your script with the sleep statement to your ~/.bash_logout file. In csh, it would be .logout.

I also liked someone's suggestion of using at. You may also want to consider writing a script that acts as a 'police' type function via cron.

I found this on this site which may be useful: How to run a script during Gnome log out

sleepyweasel
  • 1,013
0

IMHO, this approach of temporarily installing and purging phpmyadmin is an ugly hack. You could simply ssh -L3307:localhost:3306, i.e. you would create a listener on a local port (-L3307) that tunnels and connects to a remote port (localhost:3306). Then, if you would want to talk to the remote MySQL database you would simply use localhost:3307 on the local machine. You wouldn't need to install anything remotely, the tunnel would immediately die on disconnect, and you could use whatever MySQL tool locally (e.g. MySQL Workbench or SQirreL).

Robin479
  • 335
0

There are better ways.

  1. Install phpMyAdmin on a dedicated virtual host with a port you only know (say 56887).

  2. Setup knockd to open that port upon your request, for your IP only.

    [phpMyAdmin]
      sequence      = 2000,3000,4000
      seq_timeout   = 15
      start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 56887 -j ACCEPT
      cmd_timeout   = 7200
      stop_command  = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 56887 -j ACCEPT
    
  3. Use handy knock to open the port:

    knock myserver.example.com 2000 3000 4000 
    

That's all! No reinstallation needed. No files moved.

Usual security through obscurity caveats apply. Insecurely configured phpMyAdmin may not be sufficiently protected by any such hack. You must configure it properly no matter what. But if you do, these hacks become unnecessary.

sanmai
  • 1,426
0

I was able to combine timeout (sleep), external heredoc, internal heredoc(s), nohup, background-level processing, and tty-stdout in the following script.

It's good if you need a fast way to install something and then auto-delete it after some time:

bash /dev/fd/5 5<< 'EOF0'
#!/bin/bash -x

apt-get install SOME_UTILITY1 -y

cat << EOF1 > ~/utility.sh
sleep 1h
apt-get purge SOME_UTILITY1 -y
EOF1

chmod 755 ~/utility.sh &
nohup ~/utility.sh &

EOF0

Press return (Enter) when you get the following message, to keep working normally in Bash (the message will appear the moment the script reaches nohup:

nohup: appending output to ‘/USER_LOCATION/nohup.out’

  • This solution is good only if the utility you install doesn't prompt an installation screen above the tty. If it is, then because nohup redirects stdout to ~/nohup.out, it just won't work. See: http://unix.stackexchange.com/questions/333927/redirect-nohup-heredoc-stdout-to-stdin-to-execute-directly –  Dec 31 '16 at 02:50