Get the directory a bash script file is in - bash

How can I get the directory a bash script file is in, when that script file is included from another (which makes it different from this question)?
/script1.sh
. /dir2/script2.sh
/dir2/script2.sh
# echoes "/dir2"
echo whatevergetsthatdir
This is the script I'm trying to "fix"
/etc/init.d/silvercar-gameserver (unique for every instance)
#!/bin/bash
#
# /etc/rc.d/init.d/silvercar-gameserver
#
# Initscript for silvercar game server
#
# chkconfig: 2345 20 80
# description: lalalalala
#CONFIG
BIN=/opt/silvercar-gameserver # Want to get rid of this
CONF=/etc/opt/silvercar-gameserver
. /etc/init.d/functions
. $BIN/gameserver.sh.inc
exit 0
/opt/silvercar-gameserver/gameserver.sh.inc (not to be changed for each install. is in svn)
# Meant to be included from a script in init.d
# Required input:
# CONF (e.g. /etc/opt/silvercarserver)
# -- Installation config (must provide JSVC, JAVA_HOME)
. $BIN/localconf.sh
# -- Instance config (must provide ASUSER, ASWORK)
. $CONF/conf.sh
PIDFILE=$ASWORK/running.pid
LOGDIR=$ASWORK/log
CLASS=tr.silvercar.gameserver.runner.DaemonGameServer
ARGS=$CONF
start() {
echo "Going to start Gameserver..."
export JAVA_HOME
cd $BIN
$JSVC -jvm server -procname silvercar-gameserver -pidfile $PIDFILE -user $ASUSER -outfile $LOGDIR/stdout -errfile $LOGDIR/stderr \
-cp `cat classpath` -Dlogroot=$LOGDIR $CLASS $ARGS
echo "Gameserver started!"
}
stop() {
echo "Going to stop Gameserver..."
$JSVC -stop -pidfile $PIDFILE $CLASS
echo "Gameserver stopped!"
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: /etc/init.d/silvercar-gameserver {start|stop|restart}"
exit 1
;;
esac

If you have bash 3.0 or newer, you can use BASH_SOURCE to get exactly what you need without relying on the calling program to set any environment variables for you. See below for an example:
#test.sh
source some_directory/script2.sh
#some_directory/script2.sh
echo $BASH_SOURCE
echo $(dirname $BASH_SOURCE)
The output will be:
$ ./test.sh
some_directory/script2.sh
some_directory

In order to source the file, the parent script obviously knows the path where the child script is. Set it as a variable, then in the child script check for that variable. If it is available you know it's been sourced and you can use that path, otherwise use the normal trick in the question you linked.
# script1.sh
RESOURCE_DIR=/dir2
source $RESOURCE_DIR/script2.sh
# script2.sh
if [ -z "$RESOURCE_DIR"]; then
echo $RESOURCE_DIR
else
echo $(dirname $0)
fi

Related

error :- test: ing: unary operator expected

below is my script to run some sub commands. When i am running the script with ./test.sh sub_cmd $APP it is running fine. But when i ran it like test sub_cmd $APP it throwing an error.
I want to run the script without using ./
error :- test: ing: unary operator expected
#!/bin/bash
ProgName=$(basename $0)
APP=${2?Need chart name}
sub_help(){
echo "Usage: $ProgName <subcommand> [options]\n"
}
sub_dep(){
echo "Running 'dep' command."
vi some_path/${APP}/templates/deployment.yaml
}
sub_ing(){
echo "Running 'ing' command."
vi some_path/${APP}/templates/ingress.yaml
}
sub_svc(){
echo "Running 'ing' command."
vi some_path/${APP}/templates/service.yaml
}
subcommand=$1
case $subcommand in
"" | "-h" | "--help")
sub_help
;;
*)
shift
sub_${subcommand} $#
if [ $? = 127 ]; then
echo "Error: '$subcommand' is not a known subcommand." >&2
echo " Run '$ProgName --help' for a list of known subcommands." >&2
exit 1
fi
;;
esac
You need to run "test.sh" not "test".
test sub_cmd $APP
What you are actually running is the test command which lives in one of the lib directories on your path.
If you type
which test
you can see which command/script/program that will be run.
When you prefix the command with a relative path (such as ./) or an absolute path (ie.e starting with a /) then bash will look in that specific folder for the command. If you omit the path then it will search the directories listed in the environment variable $PATH and execute the first one it comes across. The which command does the same thing, but just lists the script/program instead of executing it.

How can I export function in a function in bash?

I am learning bash. And I would like to make a function which wrap another function in a temporal script file and execute it with sudo -u command in sub-shell.
The problem I encountered is the generated script cannot find the wrapped function although it is exported in the wrap function.
I append test cords below. Someone who finds problems, please let me know. Thank you very much.
main.sh
source "./display.sh"
source "./sudo_wrap.sh"
display_func "load success"
sudo_wrap_func '' 'display_func' '3' '4 5'
output, display.sh, sudo_wrap.sh and generated temporal file are appended below,
output
display_func : load success
export -f display_func
30481: line 5: display_func: command not found
display.sh
function display_func() {
echo "display_func : $#"
}
sudo_wrap.sh
function sudo_wrap_func() {
local sudo_user="${1:-root}"
local function_name="${2:?'function_name is null string.'}"
shift 2
local func_augs=( "$#" )
local script
# *** script : header ***
script="#!/bin/bash\n"
script="${script}\n"
# *** script : making augments for function ***
script="${script}augs=("
for aug in "${func_augs[#]}"
do
if [[ "${aug}" =~ [[:blank:]] ]]; then
script=" ${script} \"${aug}\""
else
script=" ${script} ${aug}"
fi
done
script="${script})\n"
local tmp_script_file="${RANDOM}"
echo -e "${script}" >> "${tmp_script_file}"
# *** script : calling function with augments ***
echo -e "${function_name} \"\${augs[#]}\"\n" >> "${tmp_script_file}"
echo "export -f "${function_name}"" >&2
export -f "${function_name}"
sudo -u"${sudo_user}" bash "${tmp_script_file}"
rm "${tmp_script_file}"
}
temporally generated file (in this case, file name is 30481)
#!/bin/bash
augs=( 3 "4 5")
display_func "${augs[#]}"
As I said in a comment, the basic problem is that sudo cleans its environment (including both variables and functions) before running the command (/script) as another user. This can be overridden with sudo -E, but only if it's explicitly allowed in /etc/sudoers.
But the problem is not insoluble; you just have to include the definition of the function in the script, so it gets recreated in that environment. bash even has a convenient command, declare -f display_func, that prints the function definition in the appropriate form (and declare -p variable does the same for variables). So you can use those to add the appropriate definitions to the script.
Here's a script I wrote to do this. I made a few other changes vs. your script: I take -u username to specify a different user to run as (so you don't have to pass '' as the first argument if you don't want to specify a different user). I also added -f functionname and -v variablename to "export" additional function and variable definitions into the script (in case the main function depends on them). I also create the temp script file in /tmp, and change ownership if necessary so it'll be readable by the other user.
#!/bin/bash
me="$(basename "$0")"
usage() {
echo "Usage: $me [-u user] [-f otherfunction] [-v variablename] function [args...]" >&2
}
tmp_script_file=$(mktemp "/tmp/${me}.XXXXXXXXXXXX") || {
echo "Error creating temporary script file" >&2
exit 1
}
echo "#!/bin/bash" > "$tmp_script_file" # Not actually needed, since we'll run it with "bash"
# Parse the command options; "-u" gets stored for later, but "-f" and "-v" write
# the relevant declarations to the script file as we go.
sudo_user=""
while getopts u:f:v: OPT; do
case "$OPT" in
u)
sudo_user="$OPTARG" ;;
f)
declare -f "$OPTARG" >>"$tmp_script_file" || {
echo "Error saving definition of function $OPTARG" >&2
exit 1
} ;;
v)
declare -p "$OPTARG" >>"$tmp_script_file" || {
echo "Error saving definition of variable $OPTARG" >&2
exit 1
} ;;
?) usage; exit 1 ;;
esac
done
shift $(($OPTIND-1))
if (( $# == 0 )); then # No actual command specified
usage
exit 1
fi
# Write the main function itself into the script
declare -f "$1" >>"$tmp_script_file" || {
echo "Error saving definition of function $1" >&2
exit 1
}
# Then the command to run it, with arguments quoted/escaped as
# necessary.
printf "%q " "$#" >>"$tmp_script_file"
# the printf above won't write a newline, so add it by hand
echo >>"$tmp_script_file"
# If the script will run as someone other than root, change ownership of the
# script so the target user can read it
if [[ -n "$sudo_user" ]]; then
sudo chown "$sudo_user" "$tmp_script_file"
fi
# Now launch the script, suitably sudo'ed
sudo ${sudo_user:+ -u "$sudo_user"} bash "$tmp_script_file"
# Clean up
sudo rm "$tmp_script_file"
Here's an example of using it:
$ foo() { echo "foo_variable is '$foo_variable'"; }
$ bar() { echo "Running the function bar as $(whoami)"; echo "Arguments: $*"; foo; }
$ export -f foo bar # need to export these so the script can see them
$ export foo_variable='Whee!!!' # ditto
$ # Run the function directly first, so see what it does
$ bar 1 2 3
Running the function bar as gordon
Arguments: 1 2 3
foo_variable is 'Whee!!!'
$ # Now run it as another user with the wrapper script
$ ./sudo_wrap.sh -f foo -v foo_variable -u deenovo bar 1 2 3
Running the function bar as deenovo
Arguments: 1 2 3
foo_variable is 'Whee!!!'
Note that you could remove the need to export the functions and variables by either running the script with source or making it a function, but doing that would require changes to how $me is defined, the usage function, replacing all those exits with returns, and maybe some other things I haven't thought of.

how to run and stop a bash script in a init.d process?

i have a process script and i want it to run and stop (if already running) a bash script.
I've tried pkill -x test but it doesn't seem to work. in any case i believe i need a if statement, to see if test.sh is running..
EDIT: in the stop i added for i inps ax | grep 'test' | awk '{print $1}'; do kill -9 $i; done
that seems to fix it.. need to do some more testing
here is the code:
#!/bin/bash
# chkconfig: 2345 20 80
# description: Description comes here....
# Source function library.
. /etc/init.d/functions
prog="test"
NEWLINE=$'\n'
start() {
STR=$"Starting $prog ${NEWLINE}"
echo "$STR"
/var/www/html/test.sh
# code to start app comes here
# example: daemon program_name &
}
stop() {
STR=$"Stopping $prog ${NEWLINE}"
echo "$STR"
pkill -x test
# code to stop app comes here
# example: killproc program_name
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
${0} stop
sleep 1
${0} start
;;
status)
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
esac
exit 0
any ideas?
Maybe if the script test.sh puts a file in /var/run with it's pid. You can use the variable $$ for that.
Then you could look for for the process with the pid with ps and grep in the init script and killing it easy.

ksh --> is it possible to run a command on the parent shell (main shell) from within a subshell?

#!/usr/bin/ksh
if [ $# -ne 1 ]; then
echo "[*]\t Please see usage..."
echo "[*]\t Usage: $0 <store_number>"
exit 1
fi
if [ -z "$1" ]; then
echo "[*]\t Please see usage..."
echo "[*]\t Usage: $0 <store_number>"
exit 1
fi
Store_Number=$1
EPS_Directory="/apps/epsadmin_90000"$Store_Number"/EPS"
cd $EPS_Directory
I am trying to write a simple script that will change my directory in my main shell.
I have it working to change directory within the sub-shell (shown above), but obviously when the script is done running it kicks me back out to the outer shell and I am back in my original directory.
Is it possible to pass a command to the outer shell, from within a sub-shell? Can I pass a cd command to the outer shell?
For example if I run:
./cd.sh 2001
I would like my directory to be:
/apps/epsadmin_900002001/EPS
Once I return to the outer shell.
No, this is not possible.
Instead, you can make a function:
mycd() {
if [ $# -ne 1 ]; then
echo "[*]\t Please see usage..."
echo "[*]\t Usage: $0 <store_number>"
return 1
fi
if [ -z "$1" ]; then
echo "[*]\t Please see usage..."
echo "[*]\t Usage: $0 <store_number>"
return 1
fi
Store_Number=$1
EPS_Directory="/apps/epsadmin_90000$Store_Number/EPS"
cd "$EPS_Directory"
}
... and store it in a file of its own and source it:
. $HOME/.fun/mycd.sh
Shell functions run in the main process, unlike scripts which run in subprocesses.
Thanks for all your help! This is my solution.
# create dj file in /users/(YOUR_NUID) directory
# paste the dj function into this file. (vi dj) (hit i to enter edit mode) (right click to paste) (hit esc) (type :wq)
# source the dj file containing dj() functon by adding this to .profile:
# . $HOME/dj
# reload .profile by typing . ./.profile
# then to run the function simply type dj <storenumber> to jump between EPS directory folders.
dj(){
Store_Number=$1
EPS_Directory="/apps/epsadmin_90000"$Store_Number"/EPS"
if [ -e $(echo $EPS_Directory) ]; then
cd $EPS_Directory
echo "You are now in directory: $EPS_Directory"
else
echo "Directory $EPS_Directory does not exist."
fi
}

fedora 13 init.d script, can't stop

I wrote init.d script that suppose to run java CLI proccess.
The problem is that when i stop it, i get [failed] and the proccess is still running.
thanks
#!/usr/bin/env bash
#
# chkconfig: 345 97 03
#
# processname: quotes-srv
#
#
# source function library
. /etc/rc.d/init.d/functions
NAME=quotes-srv
start() {
echo -n $"Starting $NAME: "
daemon +19 java -Dlog4j.configuration="file:/opt/quotes/properties/log4j/log4j.properties" -Dproperties_folder="/opt/quotes/properties/app/" -jar /opt/quotes/trade-0.0.1-SNAPSHOT-jar-with-dependencies.jar &
touch /var/lock/subsys/$NAME
}
stop() {
echo -n $"Stopping $NAME: "
killproc $NAME
echo
rm -f /var/lock/subsys/$NAME
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|force-reload|reload)
restart
;;
condrestart|try-restart)
[ -f /var/lock/subsys/$NAME ] && restart
;;
status)
status $NAME
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
exit 1
esac
exit 0
killproc will terminate programs in the process list which match the name $NAME
Strictly speaking this is in your case java .
If it is the only java process you can go and put java in $NAME
If you run other java services you have to find another way to stop your java process, e.g. putting the PID in the /var/lock/subsys/$NAME file and then killing the process using the pid.
On at least debian there is a nice tool which helps with this, but I am not sure it exists for
redhat.

Resources