Sometimes you want to temporarily disable signals like Interrupt (CTRL-C). The solution:
trap '' INT # Disable interruptions # Do whatever you want here which must be uninterruptible sleep 10 trap - INT # Restore normal function of the interrupt signal
To do a cleanup or similar after the user hits CTRL-C:
trap "rm the_temporary_file; exit;" INT TERM sleep 10 # Do lots of nifty stuff here trap - INT TERM
Place test.cgi in a directory which is supposed to be configured to run CGI scripts and test with browser.
function print_error ()
{
echo "Parameter 1: $1"
echo "Parameter 2: $2"
}print_error "First param" "Second param"
You can't really return values in a function in bash, however you can echo text and then catch output with backticks.
function return_a_string ()
{
echo "This is the return value"
}RETURN_VALUE=`return_a_string()` echo $RETURN_VALUE
To save a text file, create the following HTML file:
<form action="/cgi-bin/post.sh" method="post"
enctype="multipart/form-data">
<input name="file" file">
<input type="submit" value="Submit">
</form>Then, in your cgi-bin, create a shellscript with the following lines:
#!/bin/sh
while read var
do
echo $var >> outputfile
doneecho "Content-type: text/plain" echo "" echo "Thanks!"
Of course, stuff gets pasted by the browser around the text. And this is a security hole to leave it wide open like this. So don't.
To save a binary or text file, create the HTML file like mentioned in the previous example. Then, in your cgi-bin, create a shellscript with the following lines:
boundary=$(export | \
sed '/CONTENT_TYPE/!d;s/^.*dary=//;s/.$//')
filename=$(echo "$QUERY_STRING" | \
sed -n '2!d;s/\(.*filename=\"\)\(.*\)\".*$/\2/;p')
file=$(echo "$QUERY_STRING" | \
sed -n "1,/$boundary/p" | sed '1,4d;$d')The uploaded file is now contained in the $file variable.
Debugging is easiest done by writing to stderr. When the script is run through CGI, this ends up in the web server's error log:
echo "This is a debugging message" >&2
Before printing the Content-type, set a cookie with:
value="some value" echo Set-Cookie: name=$value
SERVER_SOFTWARE = Apache/2.0.52 (Fedora) SERVER_NAME = localhost SERVER_PORT = 80 REQUEST_METHOD = GET SCRIPT_NAME = /~b.kuik/cgi-bin/test.cgi QUERY_STRING = name=value1&name2=value2 REMOTE_HOST = REMOTE_ADDR = 127.0.0.1 REMOTE_USER = AUTH_TYPE = CONTENT_TYPE = CONTENT_LENGTH =
To parse parameters and cookies, include Bashlib like this:
. ./bashlib
Then, read cookies and parameters like this:
sender=`param sender` recipient=`cookie recipient`
And test whether they're actually passed with:
if [ -z $sender ]; then
echo "Sender param not passed!" >&2
fiThe HTML looks like this :
<input type="submit" value="Save" name="button1">
Then test like this:
button1=`param button1`
if [ "x$default" != "x" ]; then
# do the default
fiProblem: you want to start a process in the background, but want your CGI script to finish:
#!/bin/sh process_that_takes_a_long_time >/dev/null 2>&1 & echo Content-type: text/plain echo echo Finished!
This doesn't work. The reason is that the started process keeps its stdout and stderr open, it's just redirected to the null device. Use the following syntax to close them:
process_that_takes_a_long_time >&- 2>&- &
Your script will immediately finish.
trap "stty echo ; exit" 1 2 15 stty -echo read password stty echo trap "" 1 2 15
If the user press Ctrl+C in the password prompt, the normal stty mode will be restored
To run a single command as another user in a script run by root:
su mysql -c mysql_install_db
If you want to run multiple commands, a HERE document is very useful:
su - mysql <<HERE execute some commands as user HERE
Be careful though; environment variables are taken from the environment outside of the su statement, not the user that was switched to. Take, for example, the following script:
#!/bin/sh
su - nobody << HERE
echo "User is: $USER"
echo "Output of id: ${ID}"
HEREWhen running as root, this will print:
User is: root
Backticks also seem problematic, better not use them inside the su HERE block.
Sometimes, you need to put a password in a shell script. There are several methods to hide passwords from the unintentional glance by those who you trust. And you need to trust them, since the password can easily be recovered.
$ echo secret_password | rot13 frperg_cnffjbeq
In the shell script, do something like:
PASSWORD=`echo frperg_cnffjbeq | rot13` # Colleagues, please don't look at this password
To bring up a dialog box through a shellscript in X, use the xdialog package:
Xdialog --msgbox "Don't forget your coffee" 10 50
The safest method is to use mktemp:
TMPFILE=`mktemp` echo "Very important data" > $TMPFILE
The mktemp command creates a unique file in /tmp and prints the name. The backticks catch the name and put it in the TMPFILE variable.
If you need a directory, add the -d option.
If you need a prefix, pass a template where the row of capital X'en is replaced by a unique string:
TMPFILE=`mktemp -t hello_XXXXXXXXXX` || exit 1 echo "Very important data" > $TMPFILE
# If we're logging in through SSH, write this down
if [ -n "$SSH_CLIENT" ]; then
LOGFILE=".ssh/.mylog"
# The variable SSH_CONNECTION has the form
# FROM_IP FROM_PORT TO_IP TO_PORT
if [ -e $LOGFILE ]; then
echo "`date`: SSH_CONNECTION $SSH_CONNECTION" >> $LOGFILE
else
echo "`date`: SSH_CONNECTION $SSH_CONNECTION" > $LOGFILE
fi # Alternative settings
SRON0311="172.16.140.14"
FROM=`echo $SSH_CLIENT | cut -f1 -d" "`
case $FROM in
*$SRON0311)
export TMOUT=180 #Logout after 3 minutes
;;
esac
fi