Use tcl variables in a shell script - shell

I have a tcl file with some variables set. I want to source this tcl file into my shell script to use them there.
When I do source <filename>.tcl, and echo the variable, it complains saying variable not found.
Any help would be appreciated.

It's ... convoluted
Here's Tcl script that sets a variable:
$ cat > vars.tcl
set var "this is a Tcl value"
Let's see if we can get Tcl to output that in shell syntax:
$ echo 'source vars.tcl; foreach _v {var} {puts "$_v=\"[set $_v]\""}' | tclsh
var="this is a Tcl value"
So far so good. Now, with bash:
$ echo "${var:-var is unset}"
var is unset
$ . <(echo 'source vars.tcl; foreach _v {var} {puts "$_v=\"[set $_v]\""}' | tclsh)
$ echo "${var:-var is unset}"
this is a Tcl value
with if you're using plain /bin/sh
$ echo "${var:-var is unset}"
var is unset
$ . <(echo 'source vars.tcl; foreach _v {var} {puts "$_v=\"[set $_v]\""}' | tclsh)
sh: 1: Syntax error: "(" unexpected
$ eval "$(echo 'source vars.tcl; foreach _v {var} {puts "$_v=\"[set $_v]\""}' | tclsh)"
$ echo "${var:-var is unset}"
this is a Tcl value
This assumes that your Tcl script does nothing beyond setting variables, or that you're OK with sourcing it to get the variables set; and the variable values do not contain double quotes.

You cannot use tcl variables in a shell script. Even though source seems to work, it is not going to do what you think it does. When you use the source command from a shell script, it will attempt to interpret the contents of the file as a shell script.

Related

Pass specific variables from one shell script to another?

I have a bash script named test.sh with:
#!/bin/bash
var1=hello
sh test2.sh $var1="/var/log"
My test2.sh looks like this:
#!/bin/bash
function jumpto
{
label=$1
cmd=$(sed -n "/$label:/{:a;n;p;ba};" $0 | grep -v ':$')
eval "$cmd"
exit
}
start=${1:-"start"}
jumpto $start
start:
echo "variable -- " $var1
This does not work due to I used jumpto function. When execution, always $var1 assigned to the $1 variable in jumpto function.
Is there a different way to do this.?
We suggest to learn about environment variable and export command and their scope.
Try modify your test.sh
#!/bin/bash
export var1=hello
sh test2.sh $var1="/var/log"

Syntax for inlining return value of call

While you can inline output of a program as parameters
$ echo $(ls)
cpp python bash
or as a temporary file
$ echo <(ls)
/proc/self/fd/63
I wonder how you can inline the return value with a similar syntax, so that it echoes the return-value of ls that it works like this:
$ ls
$ echo $?
0
ls_retval=$(ls >/dev/null 2>&1; echo "$?")
If you want to encapsulate that:
# define a function...
retval_of() { "$#" >/dev/null 2>&1; echo "$?"; }
# and use it
ls_retval=$(retval_of ls)
As for "with a similar syntax", though -- the shell has the syntax that it has; there doesn't exist "retval substitution" (as of bash 4.4, or POSIX sh as standardized in POSIX Issue 7).

bash return value in pipe to bash

We have a script, with a return code. For example
#!/bin/bash
exit 42
which is works fine:
$ ./script ; echo $?
42
but if i go:
$ bash << EOF
./script ; echo $?
EOF
0
so it prints 0, while one would expect it to still print 42
Your $? is being expanded before executing the script. If you don't want your variables to expand in the heredoc (not a pipe) put single quotes around the name:
bash <<'EOF'
./script; echo $?
EOF
That wil prevent $? from being expanded while passing the string to the new bash command. It will, instead, be evaluated in the string which is what you seem to be going for.

use of ssh variable in the shell script

I want to use the variables of ssh in shell script.
suppose I have some variable a whose value I got inside the ssh and now I want to use that variable outside the ssh in the shell itself, how can I do this ?
ssh my_pc2 <<EOF
<.. do some operations ..>
a=$(ls -lrt | wc -l)
echo \$a
EOF
echo $a
In the above example first echo print 10 inside ssh prints 10 but second echo $a prints nothing.
I would refine the last answer by defining some special syntax for passing the required settings back, e.g. "#SET var=value"
We could put the commands (that we want to run within the ssh session) in a cmdFile file like this:
a=`id`
b=`pwd`
echo "#SET a='$a'"
echo "#SET b='$b'"
And the main script would look like this:
#!/bin/bash
# SSH, run the remote commands, and filter anything they passed back to us
ssh user#host <cmdFile | grep "^#SET " | sed 's/#SET //' >vars.$$
# Source the variable settings that were passed back
. vars.$$
rm -f vars.$$
# Now we have the variables set
echo "a = $a"
echo "b = $b"
If you're doing this for lots of variables, you can add a function to cmdFile, to simplify/encapsulate your special syntax for passing data back:
passvar()
{
var=$1
val=$2
val=${val:-${!var}}
echo "#SET ${var}='${val}'"
}
a=`id`
passvar a
b=`pwd`
passvar b
You might need to play with quotes when the values include whitespace.
A script like this could be used to store all the output from SSH into a variable:
#!/bin/bash
VAR=$(ssh user#host << _EOF
id
_EOF)
echo "VAR=$VAR"
it produces the output:
VAR=uid=1000(user) gid=1000(user) groups=1000(user),4(adm),10(wheel)

Bash variables expansion (possible use of eval) in for-do loop

I am studying the book "Beginning Linux Programming 4th ed" and chapter 2 is about shell programming. I was impressed by the example on page 53, and tried to develop a script to display more on that. Here is my code:
enter code here
#!/bin/bash
var1=10
var2=20
var3=30
var4=40
for i in 1 2 3 4 # This works as intended!
do
x=var$i
y=$(($x))
echo $x = $y # But we can avoid declaring extra parameters x and y, see next line
printf " %s \n" "var$i = $(($x))"
done
for j in 1 2 3 4 #This has problems!
do
psword=PS$j
#eval psval='$'PS$i # Produces the same output as the next line
eval psval='$'$psword
echo '$'$psword = $psval
#echo "\$$psword = $psval" #The same as previous line
#echo $(eval '$'PS${i}) #Futile attempts
#echo PS$i = $(($PS${i}))
#echo PS$i = $(($PS{i}))
done
#I can not make it work as I want : the output I expect is
#PS1 = \[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$
#PS2 = >
#PS3 =
#PS4 = +
How can I get the intended output? When I run it as it is I only get
PS1 =
PS2 =
PS3 =
PS4 = +
What happened with PS1 and PS2 ?
Why do not I get the same value that I get with
echo $PS1
echo $PS2
echo $PS3
echo $PS4
because that was what I am trying to get.
Shell running a script is always non interactive shell. You may force to run the script in interactive mode using '-i' option:
Try to change:
#!/bin/bash
to:
#!/bin/bash -i
see INVOCATION section in 'man bash' (bash.bashrc is where your PS1 is defined):
When an interactive shell that is not a login shell is started, bash reads and executes commands from
/etc/bash.bashrc and ~/.bashrc, if these files exist. This may be inhibited by using the --norc option. The
--rcfile file option will force bash to read and execute commands from file instead of /etc/bash.bashrc and
~/.bashrc.
When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in
the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read
and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file name.
you can also read: http://tldp.org/LDP/abs/html/intandnonint.html
simple test:
$ cat > test.sh
echo "PS1: $PS1"
$ ./test.sh
PS1:
$ cat > test.sh
#!/bin/bash -i
echo "PS1: $PS1"
$ ./test.sh
PS1: ${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u#\h\[\033[01;34m\] \w \$\[\033[00m\]
Use indirect expansion:
for j in 0 1 2 3 4; do
psword="PS$j"
echo "$psword = ${!psword}"
done

Resources