Linux shell strange situation - linux

Does anyone know why the following script works?
#a-random-junk-string
echo HI
The shell executes the echo command, and outputs HI. I thought that since there is no "!" after the "#", the shell would give an error.

If there is no #! specifying a specific interpreter, the kernel will not intercept and launch it with the specified program.
However, the current shell may still interpret it as a command file, which is what you are seeing take place.

When the shell is asked to run a file with the executable bit turned on then it will examine the file and determine if it begins with a shebang #! if it does then it will execute that command which will get it's program text from the remainder of the file.
If the file does not start with a shebang then the shell will attempt to execute it itself. This is what is happening for you and the shell interprets the first line as a comment.

Related

Difference between ways in script execution [duplicate]

I know that source and . do the same thing, and I would be surprised to learn if the other pairs of commands in the title don't so the same thing (because I'm running bash as my shell, $SHELL [script] and bash [script] are equivalent, right??).
So what's the difference between the three methods of executing the script? I'm asking because I just learned that sourcing a script is NOT the exact same as executing it. In a way that I didn't find obvious from running my "experiments" and reading the man pages.
What are the other subtle differences that I couldn't find by blindly calling these functions on incredibly simple scripts that I've written? After reading the above-linked answer, I can strongly guess that the answer to my question will be quite a simple explanation, but in a way that I'd almost never fully discover by myself.
Here's the "experiment" I did:
$. myScript.sh
"This is the output to my script. I'd like to think it's original."
$source myScript.sh
"This is the output to my script. I'd like to think it's original."
$bash myScript.sh
"This is the output to my script. I'd like to think it's original."
$$SHELL myScript.sh
"This is the output to my script. I'd like to think it's original."
$./myScript.sh
"This is the output to my script. I'd like to think it's original."
$myScript.sh
"This is the output to my script. I'd like to think it's original."
. script and source script execute the contents of script in the current environment, i.e. without creating a subshell. On the upside this allows script to affect the current environment, for example changing environment variables or changing the current work directory. On the downside this allows script to affect the current environment, which is a potential security hazard.
bash script passes script to the bash interpreter to execute. Whatever shebang is given by script itself is ignored. ("Shebang" referring to the first line of script, which could e.g. read #!/bin/bash, or #!/usr/bin/perl, or #!/usr/bin/awk, to specify the interpreter to be used.)
$SHELL script passes script to whatever is your current shell interpreter to execute. That may, or may not, be bash. (The environment variable SHELL holds the name of your current shell interpreter. $SHELL, if running bash, is evaluated to /bin/bash, with the effect detailed in the previous paragraph.)
./script executes the contents of a file script in the current work directory. If there is no such file, an error is generated. The contents of $PATH have no effect on what happens.
script looks for a file script in the directories listed in $PATH, which may or may not include the current work directory. The first script found in this list of directories is executed, which may or may not be the one in your current work directory.

What's the difference between "./<executable>" and ". ./<executable>"? [duplicate]

I know that source and . do the same thing, and I would be surprised to learn if the other pairs of commands in the title don't so the same thing (because I'm running bash as my shell, $SHELL [script] and bash [script] are equivalent, right??).
So what's the difference between the three methods of executing the script? I'm asking because I just learned that sourcing a script is NOT the exact same as executing it. In a way that I didn't find obvious from running my "experiments" and reading the man pages.
What are the other subtle differences that I couldn't find by blindly calling these functions on incredibly simple scripts that I've written? After reading the above-linked answer, I can strongly guess that the answer to my question will be quite a simple explanation, but in a way that I'd almost never fully discover by myself.
Here's the "experiment" I did:
$. myScript.sh
"This is the output to my script. I'd like to think it's original."
$source myScript.sh
"This is the output to my script. I'd like to think it's original."
$bash myScript.sh
"This is the output to my script. I'd like to think it's original."
$$SHELL myScript.sh
"This is the output to my script. I'd like to think it's original."
$./myScript.sh
"This is the output to my script. I'd like to think it's original."
$myScript.sh
"This is the output to my script. I'd like to think it's original."
. script and source script execute the contents of script in the current environment, i.e. without creating a subshell. On the upside this allows script to affect the current environment, for example changing environment variables or changing the current work directory. On the downside this allows script to affect the current environment, which is a potential security hazard.
bash script passes script to the bash interpreter to execute. Whatever shebang is given by script itself is ignored. ("Shebang" referring to the first line of script, which could e.g. read #!/bin/bash, or #!/usr/bin/perl, or #!/usr/bin/awk, to specify the interpreter to be used.)
$SHELL script passes script to whatever is your current shell interpreter to execute. That may, or may not, be bash. (The environment variable SHELL holds the name of your current shell interpreter. $SHELL, if running bash, is evaluated to /bin/bash, with the effect detailed in the previous paragraph.)
./script executes the contents of a file script in the current work directory. If there is no such file, an error is generated. The contents of $PATH have no effect on what happens.
script looks for a file script in the directories listed in $PATH, which may or may not include the current work directory. The first script found in this list of directories is executed, which may or may not be the one in your current work directory.

What's the difference between: ". [script]" or "source [script]", "bash [script] or $SHELL [script]", and "./ [script]" or "[script]"?

I know that source and . do the same thing, and I would be surprised to learn if the other pairs of commands in the title don't so the same thing (because I'm running bash as my shell, $SHELL [script] and bash [script] are equivalent, right??).
So what's the difference between the three methods of executing the script? I'm asking because I just learned that sourcing a script is NOT the exact same as executing it. In a way that I didn't find obvious from running my "experiments" and reading the man pages.
What are the other subtle differences that I couldn't find by blindly calling these functions on incredibly simple scripts that I've written? After reading the above-linked answer, I can strongly guess that the answer to my question will be quite a simple explanation, but in a way that I'd almost never fully discover by myself.
Here's the "experiment" I did:
$. myScript.sh
"This is the output to my script. I'd like to think it's original."
$source myScript.sh
"This is the output to my script. I'd like to think it's original."
$bash myScript.sh
"This is the output to my script. I'd like to think it's original."
$$SHELL myScript.sh
"This is the output to my script. I'd like to think it's original."
$./myScript.sh
"This is the output to my script. I'd like to think it's original."
$myScript.sh
"This is the output to my script. I'd like to think it's original."
. script and source script execute the contents of script in the current environment, i.e. without creating a subshell. On the upside this allows script to affect the current environment, for example changing environment variables or changing the current work directory. On the downside this allows script to affect the current environment, which is a potential security hazard.
bash script passes script to the bash interpreter to execute. Whatever shebang is given by script itself is ignored. ("Shebang" referring to the first line of script, which could e.g. read #!/bin/bash, or #!/usr/bin/perl, or #!/usr/bin/awk, to specify the interpreter to be used.)
$SHELL script passes script to whatever is your current shell interpreter to execute. That may, or may not, be bash. (The environment variable SHELL holds the name of your current shell interpreter. $SHELL, if running bash, is evaluated to /bin/bash, with the effect detailed in the previous paragraph.)
./script executes the contents of a file script in the current work directory. If there is no such file, an error is generated. The contents of $PATH have no effect on what happens.
script looks for a file script in the directories listed in $PATH, which may or may not include the current work directory. The first script found in this list of directories is executed, which may or may not be the one in your current work directory.

How do i make my own created shell work with .sh files

My teacher gave us this assignment to create our own shell. Our shell is supposed be called rshell and is supposed to work like the regular shell.
I created my own shell using C++. If you type a command like ls in my created shell it gives you a list just like how if you typed ls in the regular shell.
The problem I am facing is how do I get the .sh files or script files to work with my created shell. I noticed when I run a .sh file using my shell it does not run the .sh file through my shell. It runs it through the regular shell. How do I make .sh files run through my shell?
Change the hash-bang line of the scripts to point at your shell. For instance,
#!/usr/local/bin/rshell
Or wherever your shell executable is.
As John already said, change the shebang to point to your shell. The kernel will invoke the command in the shebang with the file itself as an argument. To demonstrate, try a file with a shebang of #!/bin/cat.
#!/bin/cat
hello world
It pretty much behaves the same as if you typed /bin/cat /path/to/file.
The shebang does not have PATH lookup capabilities, so #!yourshell would not work as a shebang. However, you can use env to do the PATH lookup as in #!/usr/bin/env yourshell. (This approach is preferred for commands that are at different paths on different systems, like python.)

Shell script working fine without shebang line? Why? [duplicate]

This question already has answers here:
Bash script execution with and without shebang in Linux and BSD
(2 answers)
Closed 8 years ago.
I was writing a simple shell script and found out that my shell script doesn't require shebang line
#!/bin/sh
If I give execute permissions to my script and execute using ./myscript.sh. It runs fine.
I am using bash shell and /bin/sh is actually pointing to bash.
lrwxrwxrwx 1 root root /bin/sh -> bash
I know that shebang line is used to tell shell which interpreter to use for your rest of the script.
If I miss shebang line in perl, give execute permissions and run ./myscript.pl, it doesn't work.
What's actually happening here? If I use ./, When is shebang line actually needed?
The parent shell, where you entered ./myscript.sh, first tried to execve it, which is where the shebang line would take effect if present. When this works, the parent is unaware of the difference between scripts and ELFs because the kernel takes care of it.
The execve failed, so an ancient unix compatibility feature, predating the existence of shebang lines, was activated. It guessed that a file which has execute permission but is not recognized as a valid executable file by the kernel must be a shell script.
Usually the parent shell guesses that the script is written for the same shell (minimal Bourne-like shells run the script with /bin/sh, bash runs it as a bash subprocess), csh does some more complicated guessing based on the first character because it predates shebang too and it needed to coexist with Bourne shell).
You need a shebang line when you know these guesses will be wrong (for example with the shebang is #!/usr/bin/perl), or when you don't trust the guessing to work consistently, or when the script needs to be runnable by a parent process that is not a shell itself.
shebang line is needed in the file and only if it's meant to be run as executable (as opposed to sh file.sh invocation. It is not actually needed by script, it is for the system to know how to find interpreter.
EDIT: Sorry for misreading the question. If the shebang line is missing or not recognized, /bin/sh is used. But I prefer being explicit about the interpreter.
Note, that this behavior is not universal, IIRC, only some exec* family function do that (not to mention different platforms), so that's another reason to be explicit here.
The POSIX (Single UNIX Specification 4) standard is not helpful:
If the first line of a file of shell commands starts with the characters "#!" , the results are unspecified.
So, the standard implies that if you don't have #! then it should run a POSIX shell. But modern shells are not POSIX compliant. The old Korn Shell 88 (ksh88) ran the Bourne shell (close to a POSIX shell) with no #! line, but ksh93 breaks that, and so does Bash. With both ksh93 and Bash, they run their own shell if no #! line is present.
Despite popular opinion, Bash and Korn shells differ. When you write a shell script you can never be sure what shell you will be run from, or even if it will be run from another shell at all (most programming languages can run other programs). The minute you use something outside of Bourne/POSIX syntax you will be scuppered.
Always use a #! line, don't leave it to chance.

Resources