How to execute tcl scripts in tchsh with arguments - shell

Normally I invoke my tcl script under shell like this.
> tclsh8.5 mytest.tcl -opt1 foo -opt2 bar
In case need to launch gdb to debug due to some modules implemented in C++. I have to launch tclsh via gdb. So the question is how to execute my script in tcl sh with arguments.
I need something like:
tclsh> run mytest.tcl -opt1 foo -opt2 bar
Using exec is not ideal as it folks another process and losses my breakpoints settings.
tclsh> exec mytest.tcl -opt1 foo -opt2 bar

I would think something like the following should work for you:
set argv [list -opt1 foo -opt2 bar]
set argc 4
source mytest.tcl
So set argv and argc to get the arguments correct and then just source in your Tcl code to execute.
Alternatively the gdb run command allows you to pass command line arguments to the executable to be debugged. So if your debugging tclsh then the what is the problem with the run command as follows?
run mytest.tcl -opt1 foo -opt2 bar
For example under cygwin I'm able to do the following:
$ tclsh test.tcl
This is a test
$ gdb -q tclsh.exe
(no debugging symbols found)
(gdb) run test.tcl
Starting program: /usr/bin/tclsh.exe test.tcl

If you are running tclsh within a gdb session and set arguments, you do something like this ($ is a shell prompt, (gdb) is a gdb prompt, and I've left out all the messages that get printed by gdb):
$ gdb tclsh
(gdb) set args mytest.tcl -opt1 foo -opt2 bar
(gdb) ... set some breakpoints ...
(gdb) run
You might also need set env FOO=bar to set up the environment, depending on what is going on in your script. Tcl's own build files use techniques like this to pass in arguments when debugging the running of the test suite.

Why do not just run
gdb --args tclsh8.5 mytest.tcl -opt1 foo -opt2 bar
when you need to debug your application?

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

Strange stack bash error: --: command not found

I have very simple haskell project with only executable my-exec. All it does is printing "Hello, world!" to console.
I want to create the script file bin/setup.sh which will run my executable and also do some echo
#!/usr/bin/env stack
-- stack exec bash
echo Echo printing
my-exec
When I run it I get
$ ./bin/setup.sh
./bin/setup.sh: line 2: --: command not found
Echo printing
Hello, world!
And I don't understand what is the issue with this file and why it says --: command not found but still working as expected.
I understand that in this simple example I could write it in much easier form, but in my real situation I have to make like 10 of non trivial exec calls and don't want to duplicate stack exec multiple times.
So what can I do to get rid of this error?
Here's the problem. The first line:
#!/usr/bin/env stack
is interpreted by your operating system (e.g., the Linux kernel) as indicating that the script should be invoked using the equivalent of the shell command:
$ /usr/bin/env stack setup.sh
or, since env is just there to search the path for stack, the equivalent of:
$ stack setup.sh
If you run this manually, you'll get the same error. That's because, when stack is invoked this way, it reads the indicated file, searching for a line of the form:
-- stack blah blah whatever blah blah
after the first #! line. Normally, this line looks something like:
-- stack --resolver lts-10.0 script
which tells stack to run the script as if you had run the shell command:
$ stack --resolver lts-10.0 script hello.sh
which interprets hello.sh as a Haskell program, instead of a shell script, but runs it using the lts-10.0 resolver, and all is well.
However, you've told stack to use the command stack exec bash, so stack invokes your script with the equivalent of:
$ stack exec bash hello.sh
which is basically the same as running:
$ bash hello.sh
after setting up the stack paths and so on.
FINALLY, then, the shell bash is running your script. Bash ignores the first line, because it starts with # character that indicates a shell comment. But when Bash tries to interpret the second line, it's as if you entered the following command at the shell prompt:
$ -- stack exec bash
Bash looks for a program named -- to run with arguments stack exec bash, and you get an error message. The script keeps running, though, so the echo and my-exec lines get run as expected.
Wow.
Here's one way that may work for you. You can use:
#!/bin/bash
exec stack exec bash <<EOF
echo Echo printing
./hello
EOF
This shell script will invoke stack exec bash using a so-called "here doc", basically passing everything up to the EOF as a script file for stack exec bash to run.

How do retrieve output from a bashscript that you run from a tcl script <- (modulefile script)

In my home dir, I have sub directories (CentOS, Ubuntu, etc) all for specific nodes I have access to.
Each OS will hold their own copy of programs, one of which is Python:
$HOME/{CentOS, Ubuntu, ...}/{python2,python3}
I am using environment modules so that when I ssh into a different computer (COMP), Python aliases will be set for that specific (COMP). For example:
COMP1 is CentOS
when I ssh into COMP1, "python3" should point to $HOME/Centos/python3/bin/python3
COMP2 is Ubuntu
when I ssh into COMP2 "python2" should point to $HOME/Ubuntu/python2/bin/python2
I can retrieve the OS name in bash using lsb_release -si, but I am working with modulefiles which are written in tcl, and haven't found something like lsb_release. Can I have a bash script that outputs lsb_release -si when called from a tcl script?
I tried doing this but no luck:
BASH SCRIPT:
#!/bin/bash
OS=$(lsb_release -si)
echo $OS
MODULEFILE SCRIPT:
#%Modulefile1.0
set OS [catch {exec bash /path/to/bash_file} output]
puts $OS
This doesn't do much.
Option A: export the variable in bash and access the environment variable in tcl.
#!/bin/bash
OS=$(lsb_release -si)
export OS
somescript.tcl
#!/usr/bin/tclsh
puts $::env(OS)
Option B: Use the platform package that comes with tcl.
#!/usr/bin/tclsh
package require platform
puts [platform::identify] ; # detailed OS-CPU
puts [platform::generic] ; # more generic OS-CPU
References: env platform
Your code mostly doesn't look obviously wrong.
But following the [catch {exec ...} output] the value that you are looking for should be in the output variable; the OS variable will have a code indicating effectively whether the bash script produced any output to stderr. Since you're definitely not interested in that debugging output which might be produced for reasons not under your easy control, you can probably do this:
catch {exec bash /path/to/bash_file 2>/dev/null} output
puts $output
Also make sure your bash script has an explicit exit at the end. Might as well ensure that it stops correctly. That's the default behaviour, but it's better to be explicit here as this is a (small) program.

bash show output only during runtime

I am trying to write a script that displays its output to the terminal only while it's running, much like the 'less' or 'ssh' commands.
When I launch said script, it would take over the whole terminal, print what it needs to print, and then when I exit the script, I would return to my terminal where the only record that my script has run will be the line that shows the command itself. When I scroll up, I don't want to see what my script output.
[snoopdougg#machine /home/snoopdougg/logs]$ ls
alog.log blog.log clog.log myScript.sh
[snoopdougg#machine /home/snoopdougg/logs]$ whoami
snoopdougg
[snoopdougg#machine /home/snoopdougg/logs]$ ./myScript.sh
[snoopdougg#machine /home/snoopdougg/logs]$
(Like nothing ever happened... but myScript.sh would have print things to the terminal while it was running).
How can I do this?
You're talking about the alternate screen, which you can access with a pair of terminal attributes, smcup and rmcup. Put this in a script and run it for a small demo:
tput smcup
echo hello
sleep 5
tput rmcup
Use screen:
screen ./myScript.sh

How to source a bash-script within tcl (expect)

I want to set an http proxy within the bash environment (export http_proxy=xyz). So I added the command to the end of the .bash_profile and called
exec /bin/sh -c "source /path/to/.bash_profile"
But it does not work like expected: $::env(http_proxy) does not exist (but there is no typo).
I also tried to run the script like that: exec /bin/sh -c [exec cat /path/to/.bash_profile] .. but with the same result.
Saying
exec /bin/sh -c "source /path/to/.bash_profile"
would source the /path/to/.bash_profile in a subshell. So any changes made to the environment are effectively ignored when the command is done executing.
In order to pass an environment variable to a program, try:
exec /usr/bin/env http_proxy=xyz program

Resources