Call a unix program from a TCL variable - shell

My TCL script puts together a call to a command line tool using TCL variables.
I've tried exec or eval for the command line but nothing worked.
#!/usr/bin/tclsh
set dbg 0
set iso 100
set cmd "gphoto2 --set-config-value /main/imgsettings/iso=${iso}"
if {$dbg} {puts $cmd} else {eval $cmd}
Gives :
invalid command name "gphoto2"
while executing
"gphoto2 --set-config-value /main/imgsettings/iso=100"
("eval" body line 1)
invoked from within
"eval $cmd"
invoked from within
"if {$dbg} {puts $cmd} else {eval $cmd}"
(file "./canon.tcl" line 22)
If tried { exec $cmd } but that did not work either.
couldn't execute "gphoto2 --set-config-value /main/imgsettings/iso=100": no such file or directory
while executing
"exec $cmd"
invoked from within
"if {$dbg} {puts $cmd} else {exec $cmd}"
(file "./mofi_canon.tcl" line 22)
I tried giving absolute path name /usr/bin/gphoto2 but again no success.
I guess the problem has to do with the entire command string being one object and the unix execution cannot parse it. But what's the way to give it to the shell properly?
from the linux command line of course the command works fine.
#ubuntu:~/TCL$ gphoto2 --summary
Camera summary:
Manufacturer: Canon Inc.
Model: Canon EOS DIGITAL REBEL XSi
This is from a kubuntu 14.04 linux.
uname -a
Linux ubuntu 3.13.0-36-generic #63-Ubuntu SMP Wed Sep 3 21:30:07 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Thanks & Cheers,
Gert

If you are using tcl 8.5 or higher version, then you can use as follows,
exec {*}$cmd
Else, use the below code
eval exec $cmd
Let's consider an example as such
example.tcl
#usr/bin/tclsh
puts $argc
puts [ lindex $argv 0 ]
puts [ lindex $argv 1 ]
execargs.tcl
#usr/bin/tclsh
#Calling the example.tcl file with the command line args
set cmd "tclsh example.tcl 1 2"
#For Tcl versions less than 8.5, this will work
puts [ eval exec $cmd ]
#For Tcl 8.5 or higher, this will work
puts [ exec {*}$cmd ]

I haven't used tcl in a long while, but I suspect the problem is you are combining the command into one variable.
Try executing
exec gphoto2 --set-config-value /main/imgsettings/iso=100
in tclsh. That should work.
If you combine the entire command into one var, you are trying to find an executable of that name.

Related

bash with "bad substitution" on windows bash

I try to build the optiboot bootloader. This working with a few errors and I try to solve them. I guess optiboot is made to build on linux system.
So I installed https://sourceforge.net/projects/win-bash/files/shell-complete/latest/ and add its path to PATH variable.
But the bash/sh script was still comming back with "bad substitution"
The generated bash script look like the following. I added already the first line with #!/bin/bash but it gave not success.
#!/bin/bash
# 1 "baudcheck.c"
# 1 "C:\\Users\\trivalik\\Downloads\\arduino-1.8.0 \\hardware\\anet\\avr\\bootloaders\\atmega//"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "baudcheck.c"
# 24 "baudcheck.c"
bpsx=115200
bps=${bpsx/L/}
bps=${bps/U/}
fcpux=16000000L
fcpu=${fcpux/L/}
fcpu=${fcpu/U/}
echo $bpsx
echo $bps
when I execute this on operating system Windows 10 with "bash baudcheck.tmp.sh" I get:
115200
baudcheck.tmp.sh: ${bpsx/L/}: bad substitution
baudcheck.tmp.sh: ${bps/U/}: bad substitution
baudcheck.tmp.sh: ${fcpux/L/}: bad substitution
baudcheck.tmp.sh: ${fcpu/U/}: bad substitution
The main question is, what is on parameter substitiution on Windows different?
Or is it complete disabled?
All the bash tips here could me not help.
Edit:
Solution seems to be that the bash from win-bash is very very old.
The Version returns:
bash$ echo $BASH_VERSION
win-bash_0.8.5(0)
Instead I used now the bash from git for Windows https://git-for-windows.github.io/
this bash version is not the newest but higher:
$ echo $BASH_VERSION
4.3.42(5)-release
Does anybody know a higher bash Version for Windows?

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.

Unable to declare an array in UpStart but can in bash

This is a sample of a problem I'm having - trying to declare an array in Upstart. I can run the declare line on the bash prompt but when done via an upstart script - it fails silently.
description "bla"
author "yea"
start on runlevel [2345]
script
echo "yo" >> /var/log/arr.log 2>&1
declare -a MYARR=("1,2" "3,4")
echo "stuff"
end script
I'm doing this on ubuntu 14.04
Thanks!
Script code will be executed using /bin/sh. Arrays won't work in pure bourne shell.
Take a look at How to use array in sh shell.

bash script to run ./configure from sudo

I am using GNU bash, version 3.2.51(1)-release (sparc-sun-solaris2.10) on Solaris and trying to write a bash script to configure/compile sudo after doing a few other items. Essentially I want to be able to have operators run this script so they can install sudo from source by just running this script and not having to worry about running ./configure with options and make, etc..
It appears it works up until the config.status libtool part and then it dies with:
: creating pathnames.h config.status: pathnames.h is unchanged config.status: executing libtool commands
./install_sudo.sh: line 55: configure:: command not found
install_sudo.sh is my script which basically just untar's sudo and sets up the path. It then runs a function ConfigureSudo:
here is the script now that is not working with the above error:
#!/usr/bin/bash
Unpack(){
SRCA="sudo-1.8.7.tar.gz"
SRCB="sudo-1.8.7.tar"
if [ -f $PWD/$SRCA ]; then
echo "sudo source appears to be here!"
`/usr/bin/gunzip "$SRCA"`
`/usr/bin/tar xf "$SRCB"`
else
echo "Check your source file."
fi
}
SetupPath(){
echo "Setting up path to use included Solaris software..."
echo "Current PATH is $PATH"
PATH=/usr/sfw/bin:/usr/sfw/sbin:/usr/sfw/sparc-sun-solaris2.10/bin:$PATH
echo "Now set to $PATH"
}
ConfigureSudo(){
dir="/tmp/sudo-1.8.7"
arg1="--prefix=/usr/local"
arg2="--sysconfdir=/etc"
arg3="--localstatedir=/var/run/sudo"
arg4="--with-pam"
arg5="--with-timedir=/var/lib/sudo"
cmd=configure
$($dir/$cmd $arg1 $arg2 $arg3 $arg4 $arg5)
}
Unpack
SetupPath
ConfigureSudo
Any help to get past with is greatly appreciated.
TIA!
Jeff
$($dir/$cmd $arg1 $arg2 $arg3 $arg4 $arg5)
You don't need to place that inside process substitution I think. Its output would be executed as well. You should also quote your variables properly.
"$dir/$cmd" "$arg1" "$arg2" "$arg3" "$arg4" "$arg5"
One suggestion would be to place the line:
set -x
immediately after the shebang line (line #1) so that commands are echoed before being executed.
That will show you any problematic expansions that are happening and may lead you to the problem.
You may also need to put it at the start of each function, I can't remember whether it carries forward into functions or not. But try it at the top of the script first.

Bash script exiting prematurely when calling another script inside it

I have a bash script which calls another bash script, like so:
#!/bin/bash
echo "Hi"
./script-two.sh
echo "Hello!"
The problem that I have is that it never makes it to printing "Hello!"
I think this is because ./script-two.sh (Which I did not write) is somehow exiting or changing the shell. I have included this script at the end of this post.
Is there a way I can gurentee that my execution will continue after script-two.sh executes?
I have looked into using the trap command, but I don't fully understand its use properly.
Thanks,
Casey
Here is the contents of what would be script-two.sh
#!/bin/sh
# This file is part of the DITA Open Toolkit project hosted on
# Sourceforge.net. See the accompanying license.txt file for
# applicable licenses.
# (c) Copyright IBM Corp. 2006 All Rights Reserved.
export DITA_HOME=cwd
if [ "${DITA_HOME:+1}" != "1" ]; then
echo "DITA_HOME environment variable is empty or not set";
exit 127;
fi
echo $DITA_HOME
cd "$DITA_HOME"
# Get the absolute path of DITAOT's home directory
DITA_DIR="`pwd`"
echo $DITA_DIR
if [ -f "$DITA_DIR"/tools/ant/bin/ant ] && [ ! -x "$DITA_DIR"/tools/ant/bin/ant ]; then
chmod +x "$DITA_DIR"/tools/ant/bin/ant
fi
export ANT_OPTS="-Xmx512m $ANT_OPTS"
export ANT_OPTS="$ANT_OPTS -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl"
export ANT_HOME="$DITA_DIR"/tools/ant
export PATH="$DITA_DIR"/tools/ant/bin:"$PATH"
NEW_CLASSPATH="$DITA_DIR/lib:$DITA_DIR/lib/dost.jar:$DITA_DIR/lib/commons-codec-1.4.jar:$DITA_DIR/lib/resolver.jar:$DITA_DIR/lib/icu4j.jar"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9.jar:$DITA_DIR/lib/saxon/saxon9-dom.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-dom4j.jar:$DITA_DIR/lib/saxon/saxon9-jdom.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-s9api.jar:$DITA_DIR/lib/saxon/saxon9-sql.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-xom.jar:$DITA_DIR/lib/saxon/saxon9-xpath.jar:$DITA_DIR/lib/saxon/saxon9-xqj.jar:$NEW_CLASSPATH"
if test -n "$CLASSPATH"
then
export CLASSPATH="$NEW_CLASSPATH":"$CLASSPATH"
else
export CLASSPATH="$NEW_CLASSPATH"
fi
"$SHELL"
It looks like script-two.sh is setting up an ant build environment.
I think the author intended that it sets up the build environment, then you type your build commands in manually, then type exit to leave the build environment.
I say this because the bottom line of script-two.sh is:
"$SHELL"
which starts a new shell.
Try running your script, then type exit. I think you will see it print Hello! after you type exit.
I'm guessing you're trying to do something like:
#!/bin/bash
echo "Hi"
./script-two.sh
ant <some args>
To do that, what you really want to do is source it, by changing:
./script-two.sh
to
. script-two.sh
e.g.
#!/bin/bash
echo "Hi"
. script-two.sh
ant <some args>
But, you will need to edit script-two.sh and change:
"$SHELL"
to:
case $0 in *script-two.sh)
# executed, start a new shell with the new environment
"$SHELL"
;;
*)
# sourced, don't start a new shell
;;
esac
so that it only starts a shell if the script is being run like ./script-two.sh, but not if it is being sourced like . script-two.sh.
Or if you absolutely can't change script-two.sh, then you could do:
#!/bin/bash
echo "Hi"
. script-two.sh </dev/null
ant <some args>
which will trick "$SHELL" into exiting because it has no input.
Also
export DITA_HOME=cwd
doesn't seem right to me.
It should probably be
export DITA_HOME=$(pwd)
or
export DITA_HOME=`pwd`
(both are equivalent)
I had a similar problem today, up on digging I finally found the answer.
The script I was calling (from within my script) actually had an exit 0 in the end. Removing that fixed my issues.
Just leaving this here as someone may find it useful.
Well for starters, you can execute your bash script with the -x switch to see where it is failing:
bash -x script-one.sh
Secondly, if you call the second script like this:
#!/bin/bash
echo "Hi"
var=$(bash script-two.sh)
echo "Hello!"
It will continue, as long as script-two.sh exits cleanly. Again, you can run the -x script against that script find any problems.
And as Mikel mentioned, always make sure to have exit at the bottom of your scripts.

Resources