Read user input in both bash and csh - bash

I'm trying to create a script to to do simple things. I need to prompt the user to reply to a question, typing yes or no. The script is written for csh, but does not work when default user shell is bash. My environment is Red Hat Enterprise Linux 5
#!/bin/csh -f
echo -n Type yes to continue
set answer = $<
#...
This code works fine with csh but not with bash where it prints the following error:
syntax error near unexpected token 'newline'
bash 'set answer =$<'
I really need to have the same script working for both shell (I thought it was the purpose of putting #!/bin/csh at the beginning of the file!)
I don't really know how to modify my script to make it working in bash. Could you help me please? Thanks a lot for your help.

It would be hard to think of two more different shells than csh and bash. They are different languages, you cannot expect csh code to work in bash, or the other way around.
In bash you read from STDIN using the shell builtin read, in csh you use the construct $<. Different languages.
I really need to have the same script working for both shell Why? When you place #!/bin/csh at the start of the script then it will run the c-shell, use #!/bin/bash then it will run bash. Common mistake is to have white-space or some other character before the #!, they must be absolutely the very first two bytes in the file.

Related

Use a variable on a script command line when its value isn't set until after the script starts

How to correctly pass to the script and substitute a variable that is already defined there?
My script test.sh:
#!/bin/bash
TARGETARCH=amd64
echo $1
When I enter:
bash test.sh https://example/$TARGETARCH
I want to see
https://example/amd64
but I actually see
https://example/
What am I doing wrong?
The first problem with the original approach is that the $TARGETARCH is removed by your calling shell before your script is ever invoked. To prevent that, you need to use quotes:
./yourscript 'https://example.com/$TARGETARCH'
The second problem is that parameter expansions only happen in code, not in data. This is, from a security perspective, a Very Good Thing -- if data were silently treated as code it would be impossible to write secure scripts handling untrusted data -- but it does mean you need to do some more work. The easy thing, in this case, is to export your variable and use GNU envsubst, as long as your operating system provides it:
#!/bin/bash
export TARGETARCH=amd64
substitutedValue=$(envsubst <<<"$1")
echo "Original value was: $1"
echo "Substituted value is: $substitutedValue"
See the above running in an online sandbox at https://replit.com/#CharlesDuffy2/EcstaticAfraidComputeranimation#replit.nix
Note the use of yourscript instead of test.sh here -- using .sh file extensions, especially for bash scripts as opposed to sh scripts, is an antipattern; the essay at https://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful/ has been linked by the #bash IRC channel on this topic for over a decade.
For similar reasons, changing bash yourscript to ./yourscript lets the #!/usr/bin/env bash line select an interpreter, so you aren't repeating the "bash" name in multiple places, leading to the risk of those places getting out of sync with each other.

Shell script error - bad substitution - principle

I am new in shell scripting and all questions I found about this was so complicated that I decided to ask the question about the principle of this error.
I have a test.sh file which looks like:
var1="I love Suzi Suzi and Marry"
var2="Sara"
echo "${var1//Suzi/$var2}"
if I run it in terminal via sh test.sh I am getting this error - Bad substitution. Can somebody tell me please what is wrong with it? Thank you.
If I run it in terminal via sh test.sh
There's your problem. ${parameter/pattern/string} is bash syntax, not vanilla sh. Run it via bash test.sh (And/or put an appropriate shebang in your script and make it executable so you can just run ./test.sh).

How can I invoke both BASH and CSH shells in a same script

In the same script, I want to use some CSH commands and some BASH commands.
Invoking one after the other giving me problems despite I am following the different syntax for respective shells. I want to know where is mistake in my code
Your suggestions are appreciated!!
I am a beginner to shell, especially so for CSH. but the code I got has been written in CSH entirely. Since I have some familiarity with CSH, I wanted to tweak the existing CSH code by including BASH commands, which I am comfortable using it. When I tried BASH commands after CSH by invoking !#/bin/bash, it is giving some errors. I want to know if I am missing any options!!
#!/bin/csh
----
----
----
#!/bin/bash
dir2in="/nethome/achandra/NCEI/CCSM4_Historical/Forecasts"
filin2 ="ccsm4_0_cfsrr_Fcst.${ENS}.cam2.h1.${yyear[${iimonth}]}-${mmon[${iimonth}]}-${ssday}-00000.nc"
cp $dirin/$filin /nethome/achandra/NCEI/CCSM4_Historical_Forecasts/
ln -s /nethome/achandra/NCEI/CCSM4_Historical/Forecasts/$filin /nethome/achandra/NCEI/CCSM4_Historical_Forecasts/"${$filin%.nc.cdo}.nc"
#!/bin/csh
I am getting errors such as
"dirin: Undefined variable."
You are asking here for "embedding one language into another", which, as #Bayou already explained, is not supported directly. Maybe you were spoiled from the HTML-world, where you can squeeze CSS and Javascript in between and maybe use some server side PHP or Ruby stuff too.
The closest to this are HERE-documents. If you write inside your bash script a
csh <<CSH_END
your ...
csh ....
commands ...
go here ...
CSH_END
these commands are executed in a child process driven by csh. It works the other way around with bash in the same way. Make sure that the terminator symbol (CSH_END in my example) starts in column 1.
Whether this will work for your application, I can't say, because things which run in the same process in your original script, now run in different processes.
You can't mix them up like you're suggesting. It's like asking "can I use PHP code in a Python script". However, most of the shells have options to run commands (-c), just as csh does. For using Bash within a sh script:
#! /bin/sh
CONDITION=$(/bin/bash -c "[[ 1 > 2 ]] || echo no")
echo $CONDITION
exit 0
Otherwise you could create separate files and execute them.
#! /bin/sh
CONDITION=$(./bash-script.sh)
echo $CONDITION
exit 0
You, of course, should use csh instead of sh. Both of my scripts will output the following text.
$ ./test.sh
no

Bash: What is the effect of "#!/bin/sh" in a bash script with curl

I make a complex and long line command to successful login in a site. If I execute it in Console it work. But if I copy and paste the same line in a bash script it not work.
I tried a lot of thing, but accidentally discovery that if I NOT use the line
#!/bin/sh
it work! Why this happens in my mac OSX Lion? What this config line do in a bash script?
A bash script that is run via /bin/sh runs in sh compatibility mode, which means that many bash-specific features (herestrings, process substitution, etc.) will not work.
sh-4.2$ cat < <(echo 123)
sh: syntax error near unexpected token `<'
If you want to be able to use full bash syntax, use #!/bin/bash as your shebang line.
"#!/bin/sh" is a common idiom to insure that the correct interpreter is used to run the script. Here, "sh" is the "Bourne Shell". A good, standard "least common denominator" for shell scripts.
In your case, however, "#!/bin/sh" seems to be the wrong interpreter.
Here's a bit more info:
http://www.unix.com/answers-frequently-asked-questions/7077-what-does-usr-bin-ksh-mean.html
Originally, we only had one shell on unix. When you asked to run a
command, the shell would attempt to invoke one of the exec() system
calls on it. It the command was an executable, the exec would succeed
and the command would run. If the exec() failed, the shell would not
give up, instead it would try to interpet the command file as if it
were a shell script.
Then unix got more shells and the situation became confused. Most
folks would write scripts in one shell and type commands in another.
And each shell had differing rules for feeding scripts to an
interpreter.
This is when the "#! /" trick was invented. The idea was to let the
kernel's exec() system calls succeed with shell scripts. When the
kernel tries to exec() a file, it looks at the first 4 bytes which
represent an integer called a magic number. This tells the kernel if
it should try to run the file or not. So "#! /" was added to magic
numbers that the kernel knows and it was extended to actually be able
to run shell scripts by itself. But some people could not type "#! /",
they kept leaving the space out. So the kernel was exended a bit again
to allow "#!/" to work as a special 3 byte magic number.
So #! /usr/bin/ksh and
#!/usr/bin/ksh now mean the same thing. I always use the former since at least some kernels might still exist that don't understand the
latter.
And note that the first line is a signal to the kernel, and not to the
shell. What happens now is that when shells try to run scripts via
exec() they just succeed. And we never stumble on their various
fallback schemes.
The very first line of the script can be used to select which script interpreter to use.
With
#!/bin/bash
You are telling the shell to invoke /bin/bash interpreter to execute your script.
Assure that there are not spaces or empty lines before #!/bin/bash or it will not work.

Difference between #!/bin/sh and #:/bin/sh

Someone send me a script today starting with #: and after googling I didn't found any answer.
Even if the script works I wonder what does that mean.
Wow! That's brings backs lots of memories!
Back in the 1980s and early 1990s, there were two basic shells, Bourne shell (/bin/sh) and C shell (/bin/csh).
Bourne shell had very few user friendly things. There were no aliases or command substitutions. Therefore, most people liked using C Shell as their default shell.
However, Csh was a terrible scripting language. (See http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/). Therefore, you used C shell as your shell, but wrote your scripts in Bourne shell which had a much better syntax.
However, there was a tiny little problem: Since your default shell is C Shell, typing a shell script name at the command line, and the C Shell would pick it up and try to execute it.
To get around this, you put : as the first line in your program. This was a Bourne shell comment, but was an invalid C Shell command. Thus the script would fail to run if you forgot to put sh in front of it.
Later on, systems would know if the first line was :, it should be a Bourne shell script. And, even later, you could put #: so it would be a comment and not a command. Some people put the name of the shell, /bin/sh next to it to help remind people were suppose to run this as a Bourne shell script.
C shell started dying out after Kornshell started becoming popular. It was about this time when the shebang (#!) came out, but that was only for AT&T and not the Berkeley derived systems. BSD systems didn't get the shebang until the late 1980s. And, Sun people used C Shell as their default shell until Solaris came out.
I hadn't seen a program begin with #: /bin/sh in ages.
BTW, it is common to start your scripts this way:
#! /usr/bin/env perl
This way, you use the version of Perl that's in your path and don't have to worry what directory it is in. For example, if you begin your script with:
#! /usr/local/bin/perl
And, Perl is actually in /usr/bin, your script won't run. The env program is always in /usr/bin and is guaranteed to work. Of course, if you want to use a specific version of Perl and not the one that is in the path, you'd go with the first method.
This is a comment only...
#:/bin/sh
a shebang is #!. Everything else starting with a # is a comment.
example:
run a script starting with
#!/usr/bin/perl
and it'll be run by perl. Now, replace the '!' by ':' and you'll run it with the defaut interpreter, which is your shell.

Resources