这里的lamp中web server用的是nginx而不是apache,但还是用传统的叫法lamp。 环境 CentOS 6.4,我的是64位,但在32位上依然可用。
从StackOverflow下载一个调试bash的脚本lib.trap.sh, 我把它放在本文最后。
使用的版本如下:
source "lib.trap.sh"
username="ryan"
if [[ -z "$username" ]]; then
username=`whoami` #当前用户名
fi
cpu_cores=`cat /proc/cpuinfo | gawk '/cpu cores/{n+=1} END{print n}'` #CPU内核数
if [[ `uname -m` =~ "x86_64" ]]; then
sys64bit="True" #64位系统
else
sys64bit=""
fi
if [[ `id -un mysql` != "mysql" ]]; then
groupadd -f mysql
useradd -r -g mysql mysql
fi
yum install -y gcc gcc-c++ make cmake automake autoconf binutils
yum install -y gawk sed vim wget
yum install -y git httpd-tools
yum install -y zlib-devel ncurses-devel readline-devel
yum install -y bzip2-devel gmp-devel openssl-devel curl-devel freetype-devel
yum install -y libxml2-devel libpng-devel libjpeg-devel libicu-devel libc-client-devel
yum install -y libtool libtool-ltdl-devel
function download()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
if [ ! -d "ngx_http_lower_upper_case" ]; then
git clone https://github.com/replay/ngx_http_lower_upper_case.git
fi
if [ ! -f "pcre-8.32.tar.gz" ]; then
wget http://sourceforge.net/projects/pcre/files/pcre/8.32/pcre-8.32.tar.gz
fi
if [ ! -f "nginx-1.4.1.tar.gz" ]; then
wget http://nginx.org/download/nginx-1.4.1.tar.gz
fi
if [ ! -f "freetds-stable.tgz" ]; then
wget ftp://ftp.astron.com/pub/freetds/stable/freetds-stable.tgz
fi
if [ ! -f "libmcrypt-2.5.8.tar.gz" ]; then
wget -O libmcrypt-2.5.8.tar.gz http://downloads.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz?use_mirror=nchc
fi
if [ ! -f "php-5.4.14.tar.gz" ]; then
wget -O php-5.4.14.tar.gz http://cn2.php.net/get/php-5.4.14.tar.gz/from/this/mirror
fi
if [ ! -f "mysql-5.6.11.tar.gz" ]; then
wget http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.11.tar.gz
fi
}
function ins_mysql()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
rm -rf mysql-5.6.11
tar xzf mysql-5.6.11.tar.gz
cd mysql-5.6.11
#安装全部字符集请使用 -DEXTRAT_CHARSETS=all
#ENABLED_LOCAL_INFILE选项为“允许从本地导入数据”
cmake . \
-DCMAKE_INSTALL_PREFIX=/opt/mysql-5.6.11 \
-DINSTALL_DATADIR=/opt/mysql-5.6.11/data \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRAT_CHARSETS=latin1,gbk \
-DENABLED_LOCAL_INFILE=1
make && make install
#大于半小时的漫长等待中......
cd ..
}
function ini_mysql()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
#必要的软连接和目录
ln -sf /opt/mysql-5.6.11/bin/mysqld_safe /usr/bin/mysqld_safe
ln -sf /opt/mysql-5.6.11/bin/mysql /usr/bin/mysql
ln -sf /opt/mysql-5.6.11/bin/mysqldump /usr/bin/mysqldump
ln -sf /opt/mysql-5.6.11/bin/mysqlimport /usr/bin/mysqlimport
ln -sf /opt/mysql-5.6.11/bin/mysql_config /usr/bin/mysql_config
mkdir -p /var/run/mysqld
chmod -R 777 /var/run/mysqld
chown -R mysql:mysql /opt/mysql-5.6.11/data/
#初始化MySQL
/opt/mysql-5.6.11/scripts/mysql_install_db --user=mysql --basedir=/opt/mysql-5.6.11 --datadir=/opt/mysql-5.6.11/data
#64位Linux
if [ -n "$sys64bit" ]; then
ln -sf /opt/mysql-5.6.11/lib /opt/mysql-5.6.11/lib64
fi
#设置配置文件
if [ ! -f /opt/mysql-5.6.11/my.cnf ]; then
cp /opt/mysql-5.6.11/support-files/my-default.cnf /opt/mysql-5.6.11/my.cnf
fi
rm -f /etc/my.cnf
sed -i '/# basedir =/cbasedir = \/opt\/mysql-5.6.11' /opt/mysql-5.6.11/my.cnf
sed -i '/# datadir =/cdatadir = \/opt\/mysql-5.6.11\/data' /opt/mysql-5.6.11/my.cnf
sed -i '/# port =/cport = 3306' /opt/mysql-5.6.11/my.cnf
#sed -i '/# innodb_buffer_pool_size = 128M/cinnodb_buffer_pool_size = 256M' /opt/mysql-5.6.11/my.cnf
sed -i '$alog-error=/var/log/mysqld.log' /opt/mysql-5.6.11/my.cnf
sed -i '$apid-file=/var/run/mysqld/mysqld.pid' /opt/mysql-5.6.11/my.cnf
sed -i '$G' /opt/mysql-5.6.11/my.cnf
sed -i '$a[mysqld_safe]' /opt/mysql-5.6.11/my.cnf
sed -i '$alog-error=/var/log/mysqld.log' /opt/mysql-5.6.11/my.cnf
sed -i '$apid-file=/var/run/mysqld/mysqld.pid' /opt/mysql-5.6.11/my.cnf
ln -sf /opt/mysql-5.6.11/my.cnf /etc/my.cnf
#设置系统服务
rm -f /etc/init.d/mysql
cp /opt/mysql-5.6.11/support-files/mysql.server /etc/init.d/mysql
sed -i '/^basedir=/cbasedir=\/opt\/mysql-5.6.11' /etc/init.d/mysql
sed -i '/^datadir=/cdatadir=\/opt\/mysql-5.6.11\/data' /etc/init.d/mysql
#重启mysql服务
/etc/init.d/mysql start
}
function ini_mysql_user()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
#或者使用/opt/mysql-5.6.11/bin/mysql_secure_installation
local rootpass=toor
local dbapass=changeme
mysql -u root --password="" mysql << EOD
DELETE FROM \`user\` WHERE User='';
DELETE FROM \`db\` WHERE User='';
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('$rootpass');
SET PASSWORD FOR 'root'@'127.0.0.1'=PASSWORD('$rootpass');
SET PASSWORD FOR 'root'@'::1'=PASSWORD('$rootpass');
SET PASSWORD FOR 'root'@'`hostname`'=PASSWORD('$rootpass');
GRANT ALL PRIVILEGES ON \`db\\_%\`.* TO 'dba'@'localhost' IDENTIFIED BY '$dbapass' WITH GRANT OPTION;
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX ON \`db\\_%\`.* TO 'dba'@'192.168.0.%' IDENTIFIED BY '$dbapass' WITH GRANT OPTION;
FLUSH PRIVILEGES;
UPDATE user SET File_priv='Y' WHERE User='dba';
FLUSH PRIVILEGES;
GRANT FILE ON *.* TO 'dba'@'localhost';
GRANT FILE ON *.* TO 'dba'@'192.168.0.%';
FLUSH PRIVILEGES;
EOD
#手工停止
/opt/mysql-5.6.11/bin/mysqladmin --password="$rootpass" shutdown
/etc/init.d/mysql start
#更新
/opt/mysql-5.6.11/bin/mysql_upgrade --password="$rootpass"
#手工启动
#mysqld_safe --user=mysql &
/etc/init.d/mysql restart
}
function ins_php_pre()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
rm -rf freetds-0.91
rm -rf libmcrypt-2.5.8
if [ ! -d "/opt/freetds-0.91" ]; then
tar xzf freetds-stable.tgz
cd freetds-0.91
./configure --prefix=/opt/freetds-0.91 --with-tdsver=8.0 --enable-msdblib
make && make install
cd ..
#64位系统下(CentOS 6.3有这个问题,其他发行版不知道是不是也这样),还需要
if [ -n "$sys64bit" ]; then
ln -sf /opt/freetds-0.91/lib /opt/freetds-0.91/lib64
fi
fi
if [ ! -e "/usr/local/lib/libmcrypt.so.4" ]; then
tar xzf libmcrypt-2.5.8.tar.gz
cd libmcrypt-2.5.8
./configure
make && make install
cd ..
if [ -n "$sys64bit" ]; then
ln -sf /usr/local/lib/libmcrypt.so.4.4.8 /usr/lib64/libmcrypt.so.4
else
ln -sf /usr/local/lib/libmcrypt.so.4.4.8 /usr/lib/libmcrypt.so.4
fi
fi
}
function ins_php()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
rm -rf php-5.4.14
#如果configure报错Note that the MySQL client library is not bundled anymore.
#请将/opt/mysql-5.6.11/lib 建立软连接 /opt/mysql-5.6.11/lib64
#64位Linux
if [ -n "$sys64bit" ]; then
ln -sf /opt/mysql-5.6.11/lib /opt/mysql-5.6.11/lib64
gnu_x86_64="--build=x86_64-redhat-linux-gnu --host=x86_64-redhat-linux-gnu --with-libdir=lib64"
else
gnu_x86_64=""
fi
tar xzf php-5.4.14.tar.gz
cd php-5.4.14
#注意:$gnu_x86_64两边不要加引号或双引号
./configure --prefix=/opt/php-5.4.14 \
--with-mysql=/opt/mysql-5.6.11 --with-mysqli=/opt/mysql-5.6.11/bin/mysql_config \
--with-pdo-mysql=/opt/mysql-5.6.11 --with-mysql-sock=/tmp/mysql.sock \
--with-mcrypt=/usr/local --with-zlib \
--with-pic --with-curl=shared --with-freetype-dir --with-png-dir \
--with-gettext=shared --with-gmp=shared --with-iconv --with-jpeg-dir --with-png-dir \
--with-openssl --with-libxml-dir --with-pcre-regex \
--with-kerberos --with-imap --with-imap-ssl \
--with-pear --with-gd --enable-gd-native-ttf --enable-calendar=shared \
--enable-exif --enable-ftp --enable-sockets --enable-bcmath=shared \
--enable-pcntl --enable-intl --enable-mbstring \
--enable-zip --with-bz2=shared \
--enable-sysvsem --enable-sysvshm --enable-sysvmsg \
--without-unixODBC --enable-mbregex --enable-embed \
--enable-tokenizer --disable-phar --with-sqlite3 \
--enable-fpm --with-fpm-user="$username" --with-fpm-group="$username" \
--with-layout=GNU --with-mssql=/opt/freetds-0.91 $gnu_x86_64
make && make install
cd ..
}
function ini_php()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
#建立软连接
rm -rf /usr/sbin/php-fpm
rm -rf /usr/bin/pear
rm -rf /usr/bin/pecl
rm -rf /usr/bin/php*
ln -s /opt/php-5.4.14/bin/php /usr/bin/php
ln -s /opt/php-5.4.14/bin/phpize /usr/bin/phpize
ln -s /opt/php-5.4.14/bin/pear /usr/bin/pear
ln -s /opt/php-5.4.14/bin/pecl /usr/bin/pecl
ln -s /opt/php-5.4.14/bin/php-config /usr/bin/php-config
ln -s /opt/php-5.4.14/sbin/php-fpm /usr/sbin/php-fpm
#配置文件
mkdir -p /var/run/php-fpm/
cp php-5.4.14/php.ini-production /opt/php-5.4.14/etc/php.ini
cp /opt/php-5.4.14/etc/php-fpm.conf.default /opt/php-5.4.14/etc/php-fpm.conf
#修改配置
sed -i '/^max_execution_time/cmax_execution_time = 600' /opt/php-5.4.14/etc/php.ini
sed -i '/^error_reporting/cerror_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE' /opt/php-5.4.14/etc/php.ini
sed -i '/^display_errors/cdisplay_errors = On' /opt/php-5.4.14/etc/php.ini
sed -i '/^display_startup_errors/cdisplay_startup_errors = On' /opt/php-5.4.14/etc/php.ini
sed -i '/^track_errors/ctrack_errors = On' /opt/php-5.4.14/etc/php.ini
sed -i '/^upload_max_filesize/cupload_max_filesize = 20M' /opt/php-5.4.14/etc/php.ini
sed -i '/^;date.timezone/cdate.timezone = Asia/Shanghai' /opt/php-5.4.14/etc/php.ini
#修改php-fpm的进程数
sed -i "/^;daemonize/cdaemonize = yes" /opt/php-5.4.14/etc/php-fpm.conf
sed -i "/^listen = /clisten = /var/run/php-fpm/php-fpm.sock" /opt/php-5.4.14/etc/php-fpm.conf
sed -i '/^pm.max_children/cpm.max_children = 30' /opt/php-5.4.14/etc/php-fpm.conf
sed -i '/^pm.start_servers/cpm.start_servers = 2' /opt/php-5.4.14/etc/php-fpm.conf
sed -i '/^pm.min_spare_servers/cpm.min_spare_servers = 2' /opt/php-5.4.14/etc/php-fpm.conf
sed -i '/^pm.max_spare_servers/cpm.max_spare_servers = 30' /opt/php-5.4.14/etc/php-fpm.conf
mkdir -p /etc/php5/fpm/
ln -s /opt/php-5.4.14/etc/php.ini /etc/php5/fpm/php.ini
ln -s /opt/php-5.4.14/etc/php-fpm.conf /etc/php5/fpm/php-fpm.conf
}
function ins_php_ext()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
#添加常用扩展
if [ ! -f "/opt/php-5.4.14/lib/php/20100525/apc.so" ]; then
printf "\n" | pecl install apc
sed -i '1aextension=apc.so' /opt/php-5.4.14/etc/php.ini
fi
if [ ! -f "/opt/php-5.4.14/lib/php/20100525/xdebug.so" ]; then
pecl install xdebug
#ThreadSafe版本,带有_ts
sed -i '1azend_extension_ts=xdebug.so' /opt/php-5.4.14/etc/php.ini
fi
if [ ! -d "/opt/php-5.4.14/share/pear/PHPUnit" ]; then
pear upgrade pear && pear install phpunit
fi
if [ ! -f "/opt/php-5.4.14/bin/phing" ]; then
pear channel-discover pear.phing.info
pear install phing/phing
ln -sf /opt/php-5.4.14/bin/phing /usr/bin/phing
fi
}
function ins_nginx()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
rm -rf pcre-8.32
rm -rf nginx-1.4.1
tar xzf pcre-8.32.tar.gz
tar xzf nginx-1.4.1.tar.gz
cd nginx-1.4.1
./configure --prefix=/opt/nginx-1.4.1 --with-pcre=../pcre-8.32 --add-module=../ngx_http_lower_upper_case
make && make install
cd ..
}
function ini_nginx()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
cd /opt/nginx-1.4.1/conf/
#替换主配置
sed -i "/^#user/cuser $username;" nginx.conf
sed -i "/^worker_processes/cworker_processes $cpu_cores;" nginx.conf
sed -i "s/^#pid/pid/" nginx.conf
sed -i "/^[[:space:]]*#log_format/{N;N;s/\([[:space:]]*\)#/\1/g;h;s/main/sess/;s/'\;$/ \"\$var_sessid\"'\;/;G}" nginx.conf
sed -i '/^[[:space:]]*#gzip/c\ gzip on;\n gzip_min_length 1k;' nginx.conf
sed -i '/^[[:space:]]* server {/,$d' nginx.conf
sed -i '$a\ include sites/*.conf;\n}' nginx.conf
#增加一个PHP配置
mkdir sites authes
touch sites/test.conf
#将最后面的site配置文件写入上面的文件
chmod -R 777 sites
cd -
ln -sf /opt/nginx-1.4.1/sbin/nginx /usr/sbin/nginx
}
function ini_nginx_site()
{
echo ""
echo ""
echo "$FUNCNAME start ......"
cat > /opt/nginx-1.4.1/conf/sites/template.conf.bak << EOD
server {
listen 80;
server_name test.example.com;
charset utf-8;
root /home/ryan/projects/test;
# case insensitive
#lower \$lower_uri "\$uri";
#try_files \$uri \$lower_uri;
set \$var_sessid "-";
if ( \$http_cookie ~* "PHPSESSID=(\S+)(;.*|\$)")
{
set \$var_sessid \$1;
}
access_log logs/test.access.log main;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root html;
#}
if (\$request_uri ~* ^.*\\.(svn|git|hg|bzr|cvs).*\$) {
return 404;
}
location ~* ^.+\\.(css|js|jpg|png|gif|ico|swf|pdf|txt|xlsx)\$ {
access_log off;
expires 30d;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location / {
#auth_basic "Restricted";
#auth_basic_user_file authes/test;
try_files \$uri \$uri/ /index.php?\$query_string;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
}
#location ~* /\$ {
# index index.html;
#}
}
EOD
chkconfig mysql on
}
softdir="/home/$username/soft/"
mkdir -p $softdir
cd $softdir
download
[ -d "/opt/mysql-5.6.11" ] || { ins_mysql; ini_mysql; ini_mysql_user; }
[ -d "/opt/php-5.4.14" ] || { ins_php_pre; ins_php; ini_php; ins_php_ext; }
[ -d "/opt/nginx-1.4.1" ] || { ins_nginx; ini_nginx; ini_nginx_site; }
exit 0
lib_name='trap'
lib_version=20121026
stderr_log="/dev/shm/stderr.log"
#
# TO BE SOURCED ONLY ONCE:
#
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
if test "${g_libs[$lib_name]+_}"; then
return 0
else
if test ${#g_libs[@]} == 0; then
declare -A g_libs
fi
g_libs[$lib_name]=$lib_version
fi
#
# MAIN CODE:
#
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
set -o pipefail # trace ERR through pipes
set -o errtrace # trace ERR through 'time command' and other functions
set -o nounset ## set -u : exit the script if you try to use an uninitialised variable
set -o errexit ## set -e : exit the script if any statement returns a non-true return value
exec 2>"$stderr_log"
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
#
# FUNCTION: EXIT_HANDLER
#
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
function exit_handler ()
{
local error_code="$?"
test $error_code == 0 && return;
#
# LOCAL VARIABLES:
# ------------------------------------------------------------------
#
local i=0
local regex=''
local mem=''
local error_file=''
local error_lineno=''
local error_message='unknown'
local lineno=''
#
# PRINT THE HEADER:
# ------------------------------------------------------------------
#
# Color the output if it's an interactive terminal
test -t 1 && tput bold; tput setf 4 ## red bold
echo -e "\n(!) EXIT HANDLER:\n"
#
# GETTING LAST ERROR OCCURRED:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
#
# Read last file from the error log
# ------------------------------------------------------------------
#
if test -f "$stderr_log"
then
stderr=$( tail -n 1 "$stderr_log" )
rm "$stderr_log"
fi
#
# Managing the line to extract information:
# ------------------------------------------------------------------
#
if test -n "$stderr"
then
# Exploding stderr on :
mem="$IFS"
local shrunk_stderr=$( echo "$stderr" | sed 's/\: /\:/g' )
IFS=':'
local stderr_parts=( $shrunk_stderr )
IFS="$mem"
# Storing information on the error
error_file="${stderr_parts[0]}"
error_lineno="${stderr_parts[1]}"
error_message=""
for (( i = 3; i <= ${#stderr_parts[@]}; i++ ))
do
error_message="$error_message "${stderr_parts[$i-1]}": "
done
# Removing last ':' (colon character)
error_message="${error_message%:*}"
# Trim
error_message="$( echo "$error_message" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )"
fi
#
# GETTING BACKTRACE:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
_backtrace=$( backtrace 2 )
#
# MANAGING THE OUTPUT:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
local lineno=""
regex='^([a-z]{1,}) ([0-9]{1,})$'
if [[ $error_lineno =~ $regex ]]
# The error line was found on the log
# (e.g. type 'ff' without quotes wherever)
# --------------------------------------------------------------
then
local row="${BASH_REMATCH[1]}"
lineno="${BASH_REMATCH[2]}"
echo -e "FILE:\t\t${error_file}"
echo -e "${row^^}:\t\t${lineno}\n"
echo -e "ERROR CODE:\t${error_code}"
test -t 1 && tput setf 6 ## white yellow
echo -e "ERROR MESSAGE:\n$error_message"
else
regex="^${error_file}\$|^${error_file}\s+|\s+${error_file}\s+|\s+${error_file}\$"
if [[ "$_backtrace" =~ $regex ]]
# The file was found on the log but not the error line
# (could not reproduce this case so far)
# ------------------------------------------------------
then
echo -e "FILE:\t\t$error_file"
echo -e "ROW:\t\tunknown\n"
echo -e "ERROR CODE:\t${error_code}"
test -t 1 && tput setf 6 ## white yellow
echo -e "ERROR MESSAGE:\n${stderr}"
# Neither the error line nor the error file was found on the log
# (e.g. type 'cp ffd fdf' without quotes wherever)
# ------------------------------------------------------
else
#
# The error file is the first on backtrace list:
# Exploding backtrace on newlines
mem=$IFS
IFS='
'
#
# Substring: I keep only the carriage return
# (others needed only for tabbing purpose)
IFS=${IFS:0:1}
local lines=( $_backtrace )
IFS=$mem
error_file=""
if test -n "${lines[1]}"
then
array=( ${lines[1]} )
for (( i=2; i<${#array[@]}; i++ ))
do
error_file="$error_file ${array[$i]}"
done
# Trim
error_file="$( echo "$error_file" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )"
fi
echo -e "FILE:\t\t$error_file"
echo -e "ROW:\t\tunknown\n"
echo -e "ERROR CODE:\t${error_code}"
test -t 1 && tput setf 6 ## white yellow
if test -n "${stderr}"
then
echo -e "ERROR MESSAGE:\n${stderr}"
else
echo -e "ERROR MESSAGE:\n${error_message}"
fi
fi
fi
#
# PRINTING THE BACKTRACE:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
test -t 1 && tput setf 7 ## white bold
echo -e "\n$_backtrace\n"
#
# EXITING:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
test -t 1 && tput setf 4 ## red bold
echo "Exiting!"
test -t 1 && tput sgr0 # Reset terminal
exit "$error_code"
}
trap exit_handler EXIT # ! ! ! TRAP EXIT ! ! !
trap exit ERR # ! ! ! TRAP ERR ! ! !
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
#
# FUNCTION: BACKTRACE
#
###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
function backtrace
{
local _start_from_=0
local params=( "$@" )
if (( "${#params[@]}" >= "1" ))
then
_start_from_="$1"
fi
local i=0
local first=false
while caller $i > /dev/null
do
if test -n "$_start_from_" && (( "$i" + 1 >= "$_start_from_" ))
then
if test "$first" == false
then
echo "BACKTRACE IS:"
first=true
fi
caller $i
fi
let "i=i+1"
done
}
return 0