whats the difference between executing script like
# ./test
and
# . ./test
test is simple script for example
#!/bin/bash
export OWNER_NAME="ANGEL 12"
export ALIAS="angelique"
i know the results but im unsure what actually happens
Thanks
./foo executed foo if it's marked as executable and has a proper shebang line (or is an ELF binary). It will be executed in a new process.
. ./foo or . foo loads the script in the current shell. It is equal to source foo
With your example code you need to use the second way if you want the exported variables to be available in your shell.
With the dot alone, bash is "sourcing" the specified file. It is equivalent to the source builtin and attempts to include and execute the script within the same shell process.
The ./ starts a new process, and the current shell process waits for it to terminate.
The first implies that the script (or binary) be executable. With the script (possibly) containing a shebang line telling which interpreter to use.
The second is a short-hand for "execute [argument] as a shell script". The file passed as argument does not need the executable bit set.
Related
Let's say I have an executable shell script called foo.sh. Inside it is a simple echo "Hello World". From my understanding, when I run this via ./foo.sh, a subshell is invoked which executes the echo "Hello World" line.
Why, then, do I see the output of the echo command in my main shell/terminal? I would think you'd have to do a "source ./foo.sh" instead of the simple "./foo.sh" to see the output in your current shell.
Can any of you help clarify?
The standard output is inherited. Quoting from Bash Reference Manual:
Command Execution Environment
When a simple command other than a builtin or shell function is to be
executed, it is invoked in a separate execution environment that
consists of the following. Unless otherwise noted, the values are
inherited from the shell.
the shell’s open files, plus any modifications and additions specified by redirections to the command
...
I'm trying to understand a bash script I'm supposed to be maintaining and got stuck. The command is of this form:
. $APP_LOCATION/somescript.sh param1 param2 &
The line is not being called in a loop, not is any return code bening sent back to the calling script from somescript.sh
I know that the "." will make the process run in the same shell. But "&" will spawn off a different process.
That sounds contradictory. What's is really happening here? Any ideas?
The script is running in a background process, but it is a subshell, not a separately-invoked interpreter as it would be without the dot.
That is to say -- the current interpreter forks and then begins running the command (sourcing the script). As such, it inherits shell variables, not just environment variables.
Otherwise the new script's interpreter would be invoked via an execv() call, which would replace the current interpreter with a new one. That's usually the right thing, because it provides more flexibility -- you can't run anything but a script written for the same shell with . or source, after all, whereas starting a new interpreter means that your other script could be rewritten in Python, Perl, a compiled binary, etc without its callers needing to change.
(This is part of why scripts intended to be exec'd, as opposed to than libraries meant to be sourced, should not have filename extensions -- and part of why bash libraries should be .bash, not .sh, such that inaccurate information isn't provided about what kind of interpreter they can be sourced into).
TL;DR
. $APP_LOCATION/somescript.sh param1 param2 &
This sources a script as a background job in the current shell.
Sourcing a Script
In Bash, using . is equivalent to the [source builtin]. The help for the source builtin says (in part):
$ help source
source: source filename [arguments]
Execute commands from a file in the current shell.
In other words, it reads in your Bash script and evaluates it in the current shell rather than in a sub-shell. This is often important to give a script access to unexported variables.
Background Jobs
The ampersand executes the script in the background using job control. In this case, while the sourced script is evaluated in the context of the current shell, it is executed in a separate process that can be managed using job control builtins.
I have read other threads enter link description herethat discuss .bat to L/unix conversions, but none has been satisfactory. I have also tried a lot of hack type approach in writing my own scripts.
I have the following example.bat script that is representative of the kind of script I want to run on unix.
Code:
echo "Example.bat"
perl script1 param.in newParam.in
perl script2 newParam.in stuff.D2D stuff.D2C
program.exe stuff.D2C
perl script3 stuff.DIS results.out
My problem is I don't know how to handle the perl and program.exe in the unix bash shell. I have tried putting them in a system(), but that did not work. Can someone please help me?
Thank you!
Provided that you have an executable file named program.exe somewhere in your $PATH (which you well might — Unix executables don't have to end in .exe, but nothing says they can't), the code you've pasted is a valid shell script. If you save it in a file named, say, example.bat, you can run it by typing
sh example.bat
into the shell prompt.
Of course, Unix shell scripts are usually given the suffix .sh — or no suffix at all — rather than .bat. Also, if you want your script to be executable directly, by typing just
example.sh
rather than sh example.sh, you need to do three things:
Start the script with a "shebang" line: a line that begins with #! and the full path to the shell interpreter you want to use to run it (e.g. /bin/sh for the basic Bourne shell), like this:
#!/bin/sh
echo "This is a shell script."
# ... more commands here ...
Mark your script as executable using the chmod command, e.g.
chmod a+rx example.sh
Put your script somewhere along your $PATH. On Unix, the default path will not normally contain the current directory ., so you can't execute programs from the current directory just by typing their name. You can, however, run them by specifying an explicit path, e.g.
./example.sh # runs example.sh from the current directory
To find out what your $PATH is, just type echo $PATH into the shell.
Here I have one script which exporting some necessary path in Linux. After running this script I have to run some other scripts.
I have two scripts
1 import.sh = importing paths
2 main.sh = this script do something with HCI (use for Bluetooth purpose).
when I run ./import.sh and than ./main.sh then it's giving error.
And when I run . ./import.sh and then ./main.sh then it's working fine.
So what is the diff between ./import.sh and . ./import.sh?
What happens if I run script as a super user? May be . ./ using for run script as a super user.
The difference between the two invocations is that ./import.sh is executing import.sh as a program, and . ./import.sh is evaluating it in your shell.
If "import.sh" were an ELF program (a compiled binary, not a shell script), . ./import.sh would not work.
If import.sh had a shebang at the top (like #!/bin/perl), you'd be in for a nasty surprise and a huge number of error messages if you tried to do . ./import.sh - unless the shebang happened to match your current shell, in which case it would accidentally work. Or if the Perl code were to somehow be a valid Bash script, which seems unlikely.
. ./import.sh is equivalent to source import.sh, and doesn't require that the file have the execute bit set (since it's interpreted by your already-running shell instead of spawned via exec). I assume this is the source of your error. Another difference is that ./import.sh runs in the current shell instead of a subshell, so any non-exported environment variables will affect the shell you used for the launch!
So, they're actually rather different. You usually want to ./import.sh unless you know what you're doing and understand the difference.
./import.sh executes the shell script in a new sub shell shell.
. ./import.sh executes the shell script in the current shell.
The extra . denotes the current shell.
./import.sh runs the script as a normal script - that is, in a subshell. That means it can't affect your current shell in any way. The paths it's supposed to import won't get set up in your current shell.
The extra ., which is equivalent to source, runs the script in the context of your current shell - meaning it can modify environment variables, etc. (like the paths you're trying to set up) in the current shell. From the bash man page:
. filename [arguments]
source filename [arguments]
Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename.
The . ./import.sh "sources" the script, where as simply ./import.sh just executes it.
The former allows you to modify the current environment, where the later will only affect the environment within the child execution.
The former is also equivalent to (though mostly Bash-specific):
source ./import.sh
help source yields:
source: source filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.
i want to run a program via script.
normally i type ./program in the shell and the program starts.
my script looks like this:
#!/bin/sh
cd /home/user/path_to_the_program/
sh program
it fails, i think the last line went wrong...
i know this is childish question but thx a lot!
If ./program works in the shell, why not use it in your script?
#!/bin/sh
cd /home/user/path_to_the_program/
./program
sh program launches sh to try and interpret program as a shell script. Most likely it's not a script but some other executable file, which is why it fails.
When you type
./program
The shell tries to execute the program according to how it determines the file needs to be executed. If it is a binary, it will attempt to execute the entry subroutine. If the shell detects it is a script, e.g through the use of
#!/bin/sh
or
#!/bin/awk
or more generally
#!/path/to/interpreter
the shell will pass the file (and any supplied arguments) as arguments to the supplied interpreter, which will then execute the script. If the interpreter given in the path does not exist, the shell will error, and if no interpreter line is found, the shell will assume the supplied script is to executed by itself.
A command
sh program
is equivalent to
./program
when the first line of program contains
#!/bin/sh
assuming that /bin/sh is the sh in your path (it could be /system/bin/sh, for example). Passing a binary to sh will cause sh to treat it as a shell script, which it is not, and binary is not interpretable shell (which is plain text). That is why you cannot use
sh program
in this context. It will also fail due to program being ruby, awk, sed, or anything else that is not a shell script.
You don't need the sh and looks like you don't have the path to the program in your $PATH.
Try this:
#!/bin/sh
cd /home/user/path_to_the_program/
./program
You don't need the "sh" here. Just put "program" on the last line by itself.
This should be enough:
/home/user/path_to_the_program/program
If that does not work, check the following:
executable bit
shebang line of the program (if it is a script)