Nested Variables in Bourne Shell (bin/sh) - linux

I have a variable that has a nested value.
x=hello
y=world
helloworld=monday
TEMP=$x$y
echo "${!TEMP}" # I get output "monday" which is required
This works in bash but not in plain sh. When I run same command using sh the last line gives "Bad Substitution".
How can I get same result using sh? For some reasons I cannot change shell from sh to bash, so I have to do this with sh.

As sh is different than bash difference-between-sh-and-bash.
But you can get the content of helloworld using this way, maybe there is some better approach but if you're interested in just solution then this will give you what you are looking for :)
#!/bin/sh
x=hello
y=world
helloworld=monday
TEMP=$x$y
TEMP_FINAL='eval "echo \$$TEMP"'
eval "$TEMP_FINAL"

Related

syntax error when compare two files using shell script [duplicate]

I want to run this script:
#!/bin/bash
echo <(true)
I run it as:
sh file.sh
And I get "Syntax error: "(" unexpected" . I found some similar situations but still can't solve this.
I'm a beginner at shell scripting , but as I understand:
the shebang I use is correct and chooses the bash shell , so the process substitution syntax should work
I try the same from the command line and it works. I checked with echo $0 and it gives me "bash" , so what's the difference from running the command in the command line and from a script that invokes the same shell?
Maybe it's something simple, but I couldn't find an explanation or solution.
You should run your script with bash, i.e. either bash ./script.sh or making use of the shebang by ./script.sh after setting it to executable. Only running it with sh ./script.sh do I get your error, as commented by Cyrus.
See also: role of shebang at unix.SE
Remove export POSIXLY_CORRECT=1 from your ~/.bashrc or ~/.profile (etc.) files.
The issue is that process substitution is an added bash feature that is not part of the posix standards.
sh file.sh
errorsh: 3: Syntax error: "(" unexpected
solution:
bash file.sh

Wrong BASH-Variable return from a bash script

I'd like to check the value of $HISTFILE (or any similar BASH-Variable) by a bash script. On the command console 'echo $HISTFILE' is the way I normally go, but from inside a bash script, which only includes:
#!/bin/bash
echo $HISTFILE
gives an empty line instead of showing $HOME/$USER/.bash_history (or similar return values). My questions are:
What is the reason for doing so (since I never had such trouble using bash scripts) and
how can I check the value of BASH-Variables like $HISTFILE from inside a bash script?
Many thanks in advance. Cheers, M.
HISTFILE is only set in interactive shells; scripts run in non-interactive shells. Compare
$ bash -c 'echo $HISTFILE' # non-interactive, no output
$ bash -ic 'echo $HISTFILE' # interactive, produces output
/home/me/.bash_history
However, forcing the script to run in an interactive shell will also cause your .bashrc file to be sourced, which may or may not be desirable.

What is the difference between `./example.sh` and `sh example.sh`

I am trying to play with bash and arrays. But executing a sample script, I got an unexpected syntax error message: example.sh: 3: example.sh: Syntax error: "(" unexpected. And this is the script
#!/bin/bash
array=( one two three )
If I run the script with ./example.sh it works and no errors are displayed. But if I run sh example.sh I get the error message.
I thought that these two commands are the same:
sh example.sh
./example.sh
so ... what is the difference between the two?
When you launch it via ./example.sh then the command specified in the first line of the script is used to interpret the content. So your script executes in a bash, where such syntax is allowed for arrays.
When you launch it via sh example.sh then sh is the command that is used to interpret the content of the file. sh is the original Unix shell (aka Bourne shell) and this shell is a little more rude than bash (Bourne again shell). You don't have such arrays. Note that in sh the first line of your script is just interpreted as a comment.
by using sh example.sh
- you are specifying what shell interpreter to use for that script. Example being "bash example.sh" instead of "sh example.sh" etc etc.
Running scripts this way disregards the "shebang (#!/bin/bash)" that you have specified inside of the script. Since you wrote a bash script but are trying to run it as just "sh", this is why it is failing
by using ./example.sh,
- You are specifying to run the script from your current directory. This will attempt to run the script in whatever shell you are currently in unless a shebang is specified. Since you have a "shebang" specified to run the script in bash... this is why it is working.
array_name=(value1 ... valuen)
This is how to initializes an array in bash only. When you execute ./example.sh, the shebang line #!/bin/bash tells the system to use bash to execute.
However, when you execute sh example.sh, sh is used to execute. In many Unix systems (like Linux), sh is equivalent to bash. It seems sh is a different shell on your system.

Bad substitution error in bash script

I have tried a lot but couldn't get the solution out of it. I have a simple script:
#! /bin/sh
o="12345"
a=o
b=${!a}
echo ${a}
echo ${b}
When executed like
$ . scp.sh
it produces the correct output with no errors, but when executed like:
$ ./scp.sh
it produces
./scp.sh: 4: ./scp.sh: Bad substitution
Any ideas why this is happening.
I was suggested to use bash mode and it works fine. But when I execute this same script through Python (changing the script header to bash), I am getting the same error.
I'm calling it from Python as:
import os
os.system(". ./scp.sh")
Try using:
#!/bin/bash
instead of
#! /bin/sh
The reason for this error is that two different shells are used in these cases.
$ . scp.sh command will use the current shell (bash) to execute the script (without forking a sub shell).
$ ./scp.sh command will use the shell specified in that hashbang line of your script. And in your case, it's either sh or dash.
The easiest way out of it is replacing the first line with #!/bin/bash (or whatever path bash is in).

syntax of for loop in linux shell scripting

I have a problem implementing a for loop. I get this error when I execute my script
test1.sh: 2: Syntax error: Bad for loop variable
I don't understand this error.
This is my script
#!/bin/bash
for (( c=1; c<=5; c++ ))
do
echo "Welcome $c times..."
done
can any one tell me syntax for for loop in sh(in ubuntu it links to dash shell) shell in ubuntu?
You probably run it with sh, not bash. Try bash test1.sh, or ./test1.sh if it's executable, but not sh test1.sh.
A standard POSIX shell only accepts the syntax for varname in list
The C-like for-loop syntax for (( expr1; expr2; expr3 )) is a bashism.
You can get similar behavior in the standard POSIX shell using for c in $(seq 1 5)
What does
ls -l /bin/sh
give on your machine ?
Make sh a symbolic link to bash and then you can do sh ./test1.sh
Your shell script (as shown) runs in both Korn shell and Bash. Some thoughts:
You might need a space after the shebang (#! /bin/bash and not #!/bin/bash). However, Dennis Ritchie had originally specified the space is optional. Besides, it isn't the error you get with Bourne shell (you get syntax error: '(' unexpected instead).
Are you on a Windows system? Just a stab in the dark. This doesn't look like a Windows error.
Is this Solaris or HP/UX system? They might not be running true versions of Bash, or maybe an older version. However, even the oldest version of Bash recognizes the for ((x;y;z)) construct.
Try this:
#! /bin/bash
set -vx
echo "Random = $RANDOM" #Test for bash/Kornshell. Will be blank in other shells
echo \$BASH_VERSINFO[0] = ${BASH_VERSINFO[0]} #Should only work in BASH
echo \$BASH_VERSINFO[1] = ${BASH_VERSINFO[1]}
echo \$BASH_VERSINFO[2] = ${BASH_VERSINFO[2]}
echo \$BASH_VERSINFO[3] = ${BASH_VERSINFO[3]}
echo \$BASH_VERSINFO[4] = ${BASH_VERSINFO[4]}
echo \$BASH_VERSINFO[5] = ${BASH_VERSINFO[5]}
for ((c=0, c<=5, c++))
do
echo "Welcome $c times"
done
The set -xv will display all lines as they are executed.
The $RANDOM should display a value if this is either BASH or Kornshell (your for loop will work in either one).
The {$BASH_VERINFO[x]} should only be set if this is truly BASH. These aren't even set even if you run Korn shell after you're in BASH (unlike $SHELL which will still contain bash).
If the for loop still gives you trouble, just delete it. Somewhere in this script, we'll find out if you're really executing a bash shell or not.

Resources