Clean the '-x option' inside a script - linux

I've been using "set -x" inside bash scripts in order to help me debug some functions, and it has been working very well for me
-x After expanding each simple command, for command, case command,
select command, or arithmetic for command, display the expanded
value of PS4, followed by the command and its expanded arguments or
associated word list.
However I'd like to be able to clear it before I leave the function
Eg:
#/bin bash
function somefunction()
{
set -x
# some code I'm debugging
# clear the set -x
set ????
}
somefunction

Quoting the manual:
Using + rather than - causes these flags to be turned off.
So it's set +x what you are looking for.

Consider a function like
foo () {
set -x
# do something
set +x
}
The problem is that if the -x option was already set before foo was called, it will be turned off by foo.
If you want to restore the old value, you'll have to test whether it was enabled already using $-.
foo () {
[[ $- != *x* ]]; x_set=$? # 1 if already set, 0 otherwise
set -x
# do something
(( x_set )) || set +x # Turn off -x if it was off before
}

For some more info always refer to the basic guide. This clearly gives you the answer :
http://www.tldp.org/LDP/Bash-Beginners-Guide/html/Bash-Beginners-Guide.html
set -x # activate debugging from here
w
set +x # stop debugging from here

Related

although export gg I got unbound variable gg

include.sh
#!/bin/bash -
export gg
f() {
for i in "${gg[#]}"
do
echo $i
done
}
run.sh
#!/bin/bash -
set -o nounset
. include.sh || exit 1
f
I get this error
scripts/include.sh: line 5: gg[#]: unbound variable
Isn't export keyword supposed to make gg global and available anywhere?
If not, how to make gg available everywhere from include.sh ?
UPDATE
Environment:
$ cat /etc/*-release
NAME="SLES"
VERSION="11.4"
VERSION_ID="11.4"
PRETTY_NAME="SUSE Linux Enterprise Server 11 SP4"
Legacy Unix shells don't support () arrays. You should invoke the scripts with bash and they'll run as expected.
As written in the updated question, you need to define gg before exporting it:
gg=()
export gg
I tested the patch and it works fine.
If you source a file (equivalent to .), the commands are executed in the current shell context, therefore there is no need for export. However, using unset/empty array will cause bash to terminate your script if you are using set -o nounset. Either assign some values to your array:
gg=(value1 value2) #can be assigned in both run.sh and/or include.sh
f() {
for i in "${gg[#]}"; do
echo "$i"
done
}
Or use parameter expansion to handle this:
f() {
for i in ${gg[#]+"${gg[#]}"}; do
echo "$i"
done
}
${parameter+word} will expand to word only if parameter is set, otherwise nothing is substituted. If you want to read more about how this works with arrays: wiki.bash-hackers.org.
As mentioned by #CharlesDuffy, in bash 4.4 empty array doesn't become an error. There is no error even without assignment array=(). For more information, see:
BashFAQ #112.

What does `set -x` do?

I have a shell script with the following line in it:
[ "$DEBUG" == 'true' ] && set -x
set -x enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x: printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.
set +x disables it.
set -x
Prints a trace of simple commands, for commands, case commands, select
commands, and arithmetic for commands and their arguments or
associated word lists after they are expanded and before they are
executed. The value of the PS4 variable is expanded and the resultant
value is printed before the command and its expanded arguments.
[source]
Example
set -x
echo `expr 10 + 20 `
+ expr 10 + 20
+ echo 30
30
set +x
echo `expr 10 + 20 `
30
Above example illustrates the usage of set -x. When it is used, above arithmetic expression has been expanded. We could see how a single line has been evaluated step by step.
First step expr has been evaluated.
Second step echo has been evaluated.
To know more about set → visit this link
when it comes to your shell script,
[ "$DEBUG" == 'true' ] && set -x
Your script might have been printing some additional lines of information when the execution mode selected as DEBUG. Traditionally people used to enable debug mode when a script called with optional argument such as -d
-u: disabled by default. When activated, an error message is displayed when using an unconfigured variable.
-v: inactive by default. After activation, the original content of the information will be displayed (without variable resolution) before the
information is output.
-x: inactive by default. If activated, the command content will be displayed before the command is run (after variable resolution, there
is a ++ symbol).
Compare the following differences:
/ # set -v && echo $HOME
/root
/ # set +v && echo $HOME
set +v && echo $HOME
/root
/ # set -x && echo $HOME
+ echo /root
/root
/ # set +x && echo $HOME
+ set +x
/root
/ # set -u && echo $NOSET
/bin/sh: NOSET: parameter not set
/ # set +u && echo $NOSET

Aliasing with variables in bash profile

Here's a very simple question about my vim bash profile.
I would like to create an alias where I type "activate (variable)", and my virtual env immediately gets activated by running this command:
$ source foldername/bin/activate
As you can see, foldername will be the variable in this case, so I figured, I should write a function instead of a static one liner to set this alias. I tried something likes this:
activate(something){
source something/bin/activate
}
Ideally, what I would like is to type:
$ activate f1
and this command gets run:
$ source f1/bin/activate
It would also be nice to have a default. So calling "activate" would also work.
Thanks for the help.
You could update your shell environment, using a function like this:
function activate () {
if [ $# -eq 0 ]; then
# no arguments passed to the function (default case)
source f1/bin/activate
elif [ $# -eq 1 ]; then
# one argument passed to the function
source "$1"/bin/activate # argument value read from $1
fi
}

How to properly debug a bash script

I am using the following code in a bash script in order to trace the code
#!/bin/bash
function trace()
{
echo "TRACE" \
"${BASH_SOURCE[1]}:${BASH_LINENO[0]}:${FUNCNAME[1]}:" \
"$BASH_COMMAND"
}
set -o functrace
shopt -s extdebug
trap trace DEBUG
# Remainder of code here
exit 0
But when I run it, it eats my variables.
Some clue?
The best way is to use set -xv. The set -v will echo a line before it is executed. The set -x will output the line after the shell script interpolates the variables and expressions in that line.
As part of this, you can also create an environment variable called PS4 which will be the prompt printed each time your shell scripts outputs the line being executed. Most people set it to something like PS="\$LINENO: " which will print out the line number for the line being executed.
Once you're finished, you can turn off debugging by setting set +xv.
#
# Somewhere in this part of my script, I am having problems....
#
export PS4="\$LINENO> " # Now, I'll see the line numbers while debugging
set -xv # Debugging is turned on
....
#
# Done with debugging
#
set +xv # Debugging is turned off
Here are a few recommendations:
You can always echo line in your shell script to see what's going on.
You can also use set -xv to help you debug a shell script. Simply put set -xv before the part you want to debug, and set +xv to turn off the debug. You can also use export PS4="\$LINENO> " to print out the line number in your shell script.
Here's how your script will look with the set -xv. It's a really nice tool for debugging shell scripts.
The following setup will enable printing of the line number and function name for each command (assuming you later put set -x in front of the code you're debugging):
set -o functrace
shopt -s extdebug
PS4='+ line ${LINENO-}, in ${FUNCNAME-}(): '
Here's some code to test the above:
foo() { echo "now in $FUNCNAME"; bar; }
bar() { echo "now in $FUNCNAME"; baz; }
baz() { echo "now in $FUNCNAME"; }
set -x
foo

Bash config file or command line parameters

If I am writing a bash script, and I choose to use a config file for parameters. Can I still pass in parameters for it via the command line? I guess I'm asking can I do both on the same command?
The watered down code:
#!/bin/bash
source builder.conf
function xmitBuildFile {
for IP in "{SERVER_LIST[#]}"
do
echo $1#$IP
done
}
xmitBuildFile
builder.conf:
SERVER_LIST=( 192.168.2.119 10.20.205.67 )
$bash> ./builder.sh myname
My expected output should be myname#192.168.2.119 and myname#10.20.205.67, but when I do an $ echo $#, I am getting 0, even when I passed in 'myname' on the command line.
Assuming the "config file" is just a piece of shell sourced into the main script (usually containing definitions of some variables), like this:
. /etc/script.conf
of course you can use the positional parameters anywhere (before or after ". /etc/..."):
echo "$#"
test -n "$1" && ...
you can even define them in the script or in the very same config file:
test $# = 0 && set -- a b c
Yes, you can. Furthemore, it depends on your architecture of script. You can overwrite parametrs with values from config and vice versa.
By the way shflags may be pretty useful in writing such script.

Resources