variable substitution shell script issue KSH - shell

hello I am trying you achieve the below
i=1
wwn1=hi
i should be able to echo the value in wwn$i. The below code fails. Please help
echo 'wwn$i'
Above prints
wwn$i
it should print 'hi'

I don't have ksh here, so I can not verify the ksh solution
typeset -n x=wwn$i
echo "$x"
# or
eval "echo \$$wwn$i"
With bash you (other readers) could do
x=wwn$i
echo "${!x}"

eval echo \$wwn$i
or
eval echo '$wwn'$i

Related

How can I log the command used to start a bash script? [duplicate]

I know about $*, $#, "$#" and even ${1+"#"} and what they mean.
I need to get access to the EXACT command-line arguments string from a shell script. Please pay attention to the quotes in the example. Anything like "$#" saves parameters but removes quotes and I don't see how to recover from this.
Example:
./my-shell.sh "1 2" 3
And I need to retrieve the EXACT parameter string without any processing:
"1 2" 3
Any idea how to achieve this?
In bash, you can get this from the shell history:
set -o history
shopt -s expand_aliases
function myhack {
line=$(history 1)
line=${line#*[0-9] }
echo "You wrote: $line"
}
alias myhack='myhack #'
Which works as you describe:
$ myhack --args="stuff" * {1..10} $PATH
You wrote: myhack --args="stuff" * {1..10} $PATH
Also, here's a handy diagram:
But I need to exactly reproduce a user-entered command line to be able to programmatically re-execute it in case of failure
You don't need your exact command line for that; you can reconstruct an equivalent (even if not identical!) shell command yourself.
#!/usr/bin/env bash
printf -v cmd_q '%q ' "$#"
echo "Executed with a command identical to: $cmd_q"
...though you don't even need that, because "$#" can be re-executed as-is, without knowing what the command that started it was:
#!/usr/bin/env bash
printf "Program is starting; received command line equivalent to: "
printf '%q ' "$#"
printf '\n'
if [[ ! $already_restarted ]]; then
echo "About to restart ourselves:
exec "$#" # restart the program
fi

Cant access the variable as variable stored in a file using bash

I have a bash script like
source ./testscript
while read line
do
echo "$line"
done < "test.file"
where the testscript is like
VAR="hello"
the test.file is like
"$VAR" world!!!
I expect the output of my bash script to be
hello world!!!
but what i get is
"$VAR" world!!!
Is there any solution?
you can try
echo `eval "echo $line"`
instead of
echo "$line"
You don't want to use eval. eval would allow arbitrary code to be embedded into your (text?) file which is certainly not what you want, especially if untrusted users have write access to said file.
If you don't need to expand arbitrarily named variables you can do something like the following, but there might be a better approach to the problem you are actually trying to solve.
$ cat t.sh
#!/bin/bash
VAR1=hello
VAR2='!!!'
FOO=test
expand_vars()
{
local s=$*
local var
for var in VAR{1..9} FOO; do
s=${s//%${var}%/${!var}}
done
echo "${s}"
}
while read line; do
line=$(expand_vars "${line}")
echo "${line}"
done <<__DATA__
%VAR1% world%VAR2%
This is a %FOO%
__DATA__
.
$ ./t.sh
hello world!!!
This is a test

Shell script with comment, command not found when creating variable

I have the following script which works:
x=10
echo $x
now=$(date +'%Y-%m-%d')
echo $now
However, when I add a comment line at the beginning:
# comment
x=10
echo $x
now=$(date +'%Y-%m-%d')
echo $now
I get the following:
x=10: command not found
x: undefined variable
Why is the addition of the comment causing the script to fail?
if I do the following it works:
x=10
echo $x
now=$(date +'%Y-%m-%d')
# comment here
echo $now
This is a quirk of csh. (Stop using csh!) csh will process a script that does not begin with a '#' using a "standard shell" (quoting from the csh manpage.) When the script begins with '#', csh parses it. Your script is not valid csh.
You should probably add a shebang line to avoid this type of issue. That is, make the first line:
#!/bin/sh
try something like this
#!/bin/sh
#
x=10
echo $x
now=$(date +'%Y-%m-%d')
echo $now
This works on my system (Ubuntu 11.04, 64bit). If that doesn't work then you may have some hidden special character in your file.

How to use the read command in Bash?

When I try to use the read command in Bash like this:
echo hello | read str
echo $str
Nothing echoed, while I think str should contain the string hello. Can anybody please help me understand this behavior?
The read in your script command is fine. However, you execute it in the pipeline, which means it is in a subshell, therefore, the variables it reads to are not visible in the parent shell. You can either
move the rest of the script in the subshell, too:
echo hello | { read str
echo $str
}
or use command substitution to get the value of the variable out of the subshell
str=$(echo hello)
echo $str
or a slightly more complicated example (Grabbing the 2nd element of ls)
str=$(ls | { read a; read a; echo $a; })
echo $str
Other bash alternatives that do not involve a subshell:
read str <<END # here-doc
hello
END
read str <<< "hello" # here-string
read str < <(echo hello) # process substitution
Typical usage might look like:
i=0
echo -e "hello1\nhello2\nhello3" | while read str ; do
echo "$((++i)): $str"
done
and output
1: hello1
2: hello2
3: hello3
The value disappears since the read command is run in a separate subshell: Bash FAQ 24
To put my two cents here: on KSH, reading as is to a variable will work, because according to the IBM AIX documentation, KSH's read does affects the current shell environment:
The setting of shell variables by the read command affects the current shell execution environment.
This just resulted in me spending a good few minutes figuring out why a one-liner ending with read that I've used a zillion times before on AIX didn't work on Linux... it's because KSH does saves to the current environment and BASH doesn't!
I really only use read with "while" and a do loop:
echo "This is NOT a test." | while read -r a b c theRest; do
echo "$a" "$b" "$theRest"; done
This is a test.
For what it's worth, I have seen the recommendation to always use -r with the read command in bash.
You don't need echo to use read
read -p "Guess a Number" NUMBER
Another alternative altogether is to use the printf function.
printf -v str 'hello'
Moreover, this construct, combined with the use of single quotes where appropriate, helps to avoid the multi-escape problems of subshells and other forms of interpolative quoting.
Do you need the pipe?
echo -ne "$MENU"
read NUMBER

"let" internal shell command doesn't work in a shell script?

I did
a=1234
let "a=a+1"
on command line and it's fine. But when I do the same in a shell script. It prints out an error that "let: not found".
Here is the script file.
#!/bin/sh
a=1234;
let "a=a+1";
echo "$a";
Thanks,
Do not use let. Use POSIX arithmetic expansion: a=$(($a+1)). This is guaranteed to work in any POSIX-compliant shell.
The problem is likely that /bin/sh is not the same as, or does not behave the same as, your normal shell. For example, when bash is invoked as /bin/sh, it provides a subset of its normal features.
So, you may need to change your shebang line to use a different shell:
#!/bin/bash
or
#!/bin/ksh
You don't need the semi-colons at the ends of the lines.
See at: http://www.hlevkin.com/Shell_progr/hellobash.htm
The correct is:
a=1234;
b=1;
a=`expr $a + $b`;
You should use let a=a+1 without quotes
It's the '$a' of '$a=1234' that is killing you.
The shell does all $ substitutions and THEN evaluates the expression. As a result it saw "=1234" because there was no value to $a.
Use -x to see this.
bash -x your-script
Check your actual shell with the following command in the command line:
echo $SHELL
It will provide a shell name, use that instead of /bin/sh at the first line of your script.
Check the shell name using
echo $SHELL
Change the first line of the script accordingly to
#!/bin/bash
or
#!/bin/ksh
instead of #!/bin/sh.
c=1
d=1
for i in `ls`
do
if [ -f $i ]
then
echo "$c -> $i"
c=`expr $c + 1`
fi
done
c=`expr $c - 1`
echo no. of files $c
for i in `ls`
do
if [ -d $i ]
then
echo "$d -> $i"
d=`expr $d + 1`
fi
done
d=`expr $d - 1`
echo no. of direcrories $d

Resources