1

Say I have this script file called pma.sh:

#!/bin/bash

apt-get install phpmyadmin -y

function uninstpma {

apt-get purge phpmyadmin -y

}

uninstpma ()

To run the entire script with at I could do ./pma.sh | at 'now + 2 minuts'. But I don't want it for the entire script; Rather, only for the function inside the script. So:

How could I schedule only the function with the at utility?

1 Answers1

0

If you can, move the function definitions into a separate "library" file.

If it is acceptable to edit the script, then the best solution is probably to move the function definitions from the script out into a separate file. That file, containing function definitions, will then be sourced by the script (as well as removing the functions from the script, you'll have to add a command to the script that does this), and also by whatever other script or commands you are running with at.

For example, right now your pma.sh looks something like:

!#/bin/bash

apt-get install phpmyadmin -y

function uninstpma { apt-get purge phpmyadmin -y }

uninstpma

(Your original script was formatted differently and also had uninstpma () as its last line. Argument lists, empty or otherwise, are not enclosed in parentheses in Bourne-style shells. And, at least in bash 4.3.46 on my system, this is not accepted as an alternate syntax. So I've assumed the () was an error and removed it.)

You could create a new file called something like pma_funcs.sh -- you can call it whatever you like -- that contains:

function uninstpma {
    apt-get purge phpmyadmin -y
}

It can also contain additional function definitions.

That has no #!/bin/bash hashbang line, and it doesn't need to be marked executable either, because this will not be executed as a self-contained script. Instead it will in effect be used as a library for other scripts.

All callers will first source the file with the function definitions.

Suppose you put pma.sh in a /opt/pma-helpers directory. (I'm not saying that's where you should put it -- it very likely isn't the best place -- I just had to pick something.) You would then modify pma.sh:

!#/bin/bash

. /opt/pma-helpers/pma_funcs.sh

apt-get install phpmyadmin -y

uninstpma

The . builtin sources your script, which is to say it causes the shell to execute all the commands in the file passed as its argument (/opt/pma-helpers/pma_funcs.sh). Since a subshell is not created to run them (see this question and that one), commands that define new variables and functions take effect for the caller. (That caller is the script that ran ., not whatever script ran it, if any, unless that other script used . too.)

Then, when you need to modify a function, you have only one copy to edit -- the one in pma_funcs.sh. The new version will be defined in shell instances that have . /opt/pma-helpers/pma_funcs.sh since pma_funcs.sh was updated.

You must source the file that contains the function definitions before you use the function, but you don't have to do so at the very top of your script (unless the next line uses one of them).

To call one of these functions when running at, you'll source the script in the code run by at.

Your example code needs bash, but at runs commands with sh.

In this particular case, however, there is the additional complication that at runs scripts with /bin/sh, which in Ubuntu is provided by dash, not bash, but your script uses a Bash-specific feature not supported by the more basic of the POSIX shells like Dash.

(The feature is the function name compound-command syntax for defining functions. Like all POSIX-compliant shells, Dash does support functions, but only with the standard name () compound-command syntax. Bash supports that too, so if that's the only Bash-specific feature you're using, then you could just switch to the standard syntax. I'm guessing it isn't the only one you plan to use, though, since Bash offers a number of other handy extensions that are less trivial to replace.)

Therefore, you should strongly consider making a Bash script and scheduling that script with at. Suppose you made this at-job script /opt/pma-helpers/pma_job. (Again, I have no reason to think this is a reasonable place to put it on your system. You should put it somewhere that makes sense for what you're doing.) This file could contain:

#!/bin/bash
# any commands here must not use the functions; they're not sourced yet
. /opt/pma-helpers/pma_funcs.sh
# you can put commands here if you want
uninstpma
# you can put commands here, too, if you want

Mark the script executable (chmod u+x /opt/pma-helpers/pma_job, assuming the at job is to be run as the owner of the script). Then, when you want to schedule it, you'll make an at job consisting of a single command that runs that script:

at 'now + 2 minutes' <<<'/home/ek/source/pma_job'

(I've used a here string in the command that invokes at.)

The job doesn't have to go in a dedicated script file if you really don't want it to.

Your Bash script will be able to source and run all the shell functions written in Bash. However, if for some reason you really don't want to run a separate script, then you do have other options. Anything ensuring your bash-dependent shell functions are defined and used in a bash shell is sufficient.

For example, you could use nested here documents:

at now <<'EOF'
bash - <<'EOF_BASH'
# any commands here must not use the functions; they're not sourced yet
. /opt/pma-helpers/pma_funcs.sh
# you can put commands here if you want
uninstpma
# you can put commands here, too, if you want
EOF_BASH
EOF

That's a little complicated. You're likely better off having that additional pma_job script.

Eliah Kagan
  • 117,780