Dash -x fails with Bad substitution error - shell

I'm trying to learn how to write portable shell scripts, to do so I'm starting to migrating my personal utilities from bash to sh (dash on my system). There is however a error I'm getting in all cases when I try to run the scripts in debugging mode $ dash -x script
For instance, on this script:
#!/bin/sh
echo hi
If I run it as: $ dash script, I get the 'hi' string, however if I run it as: $ dash -x script or if I add the set -x command before echo:
#!/bin/sh
set -x
echo hi
It fails with the error:
script.sh: 3: script.sh: Bad substitution
this makes very difficult to debug my scripts. I'm running ubuntu 12.04 with dash 0.5.7-2ubuntu2

Just by the time I finished writing my question I realized I was using a personalized PS4 (which is used in xtrace mode), my PS4 was defined as:
>>(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }
I changed temporarily as PS4=">>" and everything went ok, I can now debug my scripts on dash. Hope this helps someone.

Related

"Set echo" doesn't seem to show code in tcsh script

Please nothing in the realms of "Why are you using TCSH?". I have my reasons.
I'm trying to debug a tcsh script, but using the options "set echo" and "set verbose" don't actually seem to show the code that I'm trying to debug.
Per this question, I tried "set echo" and "set verbose" in tcsh. I then ran this script 'test.tcsh':
echo "Hello world"
foo=1
bar=2
foobar=$(expr $foo + $bar)
echo $foobar
It returns the following output:
test.tcsh
test.tcsh
Hello world
3
history -S
history -M
So it shows clearly the output of the code. However, what I want to see is the code itself - the echo, the call to expr and so on. In bash, set -xv would do what I want, but it's seemingly not working here.
Anything I'm missing?
To be sure your script is run by the tcsh shell and to get it showing the code, simply add the following line as the first line of your script :
#!/bin/tcsh -v
This will make your script run by tcsh shell and set the tcsh shell to echo each script commands.
For reference, your actual script in the question doesn't seem to be a tcsh script, see comment under your question.
EDIT: To debug without altering the script, you can also simply launch the tcsh shell with the -v parameter followed by the script filename :
$ /bin/tcsh -v test.tcsh

How to debug a tcsh script and put the debugged output in a file?

I want to debug my tcsh script. Like in sh script if we add set command with -x then it prints the execution of script.
#! /bin/sh
set -x
exec 2>/usr/bin/error.log
#My script code
And I tried this as explained here . But still don't know how to print in a file? I am writing below code:
#! /bin/tcsh
set echo
exex 2>/usr/bin/error.log
I am getting permission denied error.I have also tried running as root still same error. But that can be the error in my script. So I want to check in error.log where does the error occur. But after I run script the error.log file is not getting generated. Is there any other way to write stderror for tcsh? Can we use exec command in tcsh?
Also are tcsh and csh both same things or different?

How can I capture the raw command that a shell script is running?

As an example, I am trying to capture the raw commands that are output by the following script:
https://github.com/adampointer/go-deribit/blob/master/scripts/generate-models.sh
I have tried to following a previous answer:
BASH: echoing the last command run
but the output I am getting is as follows:
last command is gojson -forcefloats -name="${struct}" -tags=json,mapstructure -pkg=${p} >> models/${p}/${name%.*}_request.go
What I would like to do is capture the raw command, in other words have variables such as ${struct}, ${p} and ${p}/${name%.*} replaced by the actual values that were used.
How do I do this?
At the top of the script after the hashbang #!/usr/bin/env bash or #!/bin/bash (if there is any) add set -x
set -x Print commands and their arguments as they are executed
Run the script in debug mode which will trace all the commands in the script: https://stackoverflow.com/a/10107170/988525.
You can do that without editing the script by typing "bash generate-models.sh -x".

Shell script: unexpected `(' [duplicate]

I have written the following code:
#!/bin/bash
#Simple array
array=(1 2 3 4 5)
echo ${array[*]}
And I am getting error:
array.sh: 3: array.sh: Syntax error: "(" unexpected
From what I came to know from Google, that this might be due to the fact that Ubuntu is now not taking "#!/bin/bash" by default... but then again I added the line but the error is still coming.
Also I have tried by executing bash array.sh but no luck! It prints blank.
My Ubuntu version is: Ubuntu 14.04
Given that script:
#!/bin/bash
#Simple array
array=(1 2 3 4 5)
echo ${array[*]}
and assuming:
It's in a file in your current directory named array.sh;
You've done chmod +x array.sh;
You have a sufficiently new version of bash installed in /bin/bash (you report that you have 4.3.8, which is certainly new enough); and
You execute it correctly
then that should work without any problem.
If you execute the script by typing
./array.sh
the system will pay attention to the #!/bin/bash line and execute the script using /bin/bash.
If you execute it by typing something like:
sh ./array.sh
then it will execute it using /bin/sh. On Ubuntu, /bin/sh is typically a symbolic link to /bin/dash, a Bourne-like shell that doesn't support arrays. That will give you exactly the error message that you report.
The shell used to execute a script is not affected by which shell you're currently using or by which shell is configured as your login shell in /etc/passwd or equivalent (unless you use the source or . command).
In your own answer, you say you fixed the problem by using chsh to change your default login shell to /bin/bash. That by itself should not have any effect. (And /bin/bash is the default login shell on Ubuntu anyway; had you changed it to something else previously?)
What must have happened is that you changed the command you use from sh ./array.sh to ./array.sh without realizing it.
Try running sh ./array.sh and see if you get the same error.
Instead of using sh to run the script,
try the following command:
bash ./array.sh
I solved the problem miraculously. In order to solve the issue, I found a link where it was described to be gone by using the following code. After executing them, the issue got resolved.
chsh -s /bin/bash adhikarisubir
grep ^adhikarisubir /etc/passwd
FYI, "adhikarisubir" is my username.
After executing these commands, bash array.sh produced the desired result.

How can I monitor a bash script?

I am running a bash script that takes hours. I was wondering if there is way to monitor what is it doing? like what part of the script is currently running, how long did it take to run the whole script, if it crashes at what line of the script stopped working, etc. I just want to receive feedback from the script. Thanks!!!
from man page for bash,
set -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.
add these to the start of your script,
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
Example,
#!/bin/bash
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
echo Hello World
Result,
+{helloworld.sh:6} echo Hello World
Hello World
Make a status or log file. For example add this inside your script:
echo $(date) - Ok >> script.log
Or for a real monitoring you can use strace on linux for see system call, example:
$ while true ; do sleep 5 ; done &
[1] 27190
$ strace -p 27190

Resources