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
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"
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).
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.
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)
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