22

Is there a way to mark a script to be executed in the current shell from whitin It? I know I can use:

. ./path/myscript.sh

but I need a way to include the "dot" way inside the script.

Edit: Here is the case. I have a script "myscript.sh" located in directory A:

rm -r A
mkdir A
touch A/test.file
cd A

When the script is executed in normal a way:

sh myscript.sh

When exiting the script I cannot list the directory. When script is started in the current shell:

. ./myscript.sh

There is no problem. I need a way to include this "dot" way inside my script so It can be called without It.

kofucii
  • 7,393
  • 12
  • 51
  • 79
  • 3
    The "dot" is shorthand for the "source" command. If I understand you correctly, this cannot be done. The script itself cannot decide if it is to be called or sourced, the calling shell has to decide that. – Rolf Rander Feb 07 '13 at 06:37
  • 2
    Learn about bash `function`-s, e.g. read http://www.tldp.org/LDP/abs/html/ – Basile Starynkevitch Feb 07 '13 at 06:38

5 Answers5

31

There are two ways of executing a script in the shell. Depending upon your needs, you will have to do one of the following (don't do both!).

  1. Launch the script as a program, where it has its own process.
  2. Source the script as a bunch of text, where the text is processed by the current shell.

To launch the script as a program:

  • Add the line #!/bin/bash as the first line of the script

This will be read by the loader, which has special logic that interperts the first two characters #! as "launch the program coming next, and pass the contents into it". Note this only properly works for programs written to receive the contents

To source the script into the current shell:

  • type the command . script.sh or source script.sh

Note: . in bash is equivalent to source in bash.

This acts as if you typed in the contents of "script.sh". For example, if you set a variable in "script.sh" then that variable will be set in the current shell. You will need to undefine the variable to clear it from the current shell.

This differs heavily from the #!/bin/bash example, because setting a variable in the new bash subprocess won't impact the shell you launched the subprocess from.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • 1
    this answer provides a nice explanation, a workaround option is to source the function definition as per my answer below. – chim Jul 05 '19 at 11:54
  • 1
    Good explanation but does not answer the question. How does OP avoid having to use the 'dot' when calling the script? The answer is functions, as explained in some other answers. – Martino Apr 20 '20 at 09:51
  • 1
    @Bzazz I don't think you read the post carefully, the answer is "source" and it is up there. You can't just call a function without defining it, and your definition will be in a file, and to read that file into the current shell, you will have to source it. Putting it in a different shell, well you can use the shebang to read it into a subprocess shell, but not the current shell. – Edwin Buck Apr 20 '20 at 12:45
  • OP already knows about the dot operator. Which is the same as source. They are asking how to include this 'inside the script'. So that it's not necessary to use the dot when calling the script. – Martino Apr 21 '20 at 13:58
  • @Bzazz I don't see any indication in the original question that supports the idea that the OP knows that source is the same as dot. Sure, they know about dot, but in their case, they want to import functions, variables, and code from an external file into their current shell / bash script. Typically including other files can be done in two ways, in a subshell and in the same shell. Subshell can be handled with the normal exec / bash / etc. But same shell requires either "." or "source" and there is not really another way. So, I offered up "source" and explained it was the same, and why. – Edwin Buck Apr 21 '20 at 17:09
  • @Bzazz I'm not sure why you're so focused on this item. But if you want to dive into the details, please point out where I've mis-stepped with a reference to some sort of documentation. Also, let's not try to guess the mind of the asker, as neither of us has their mind. I'm happy enough that I probably got the answer they wanted, as they upvoted me. That said, there are only so many techniques available, due to the limitations of the BASH language – Edwin Buck Apr 21 '20 at 17:12
10

You can do this if you create a shell function instead of a script. Functions are executed in the same shell, not a subshell. If you define functions in your .profile, they will be available to the login-shell.

I found some more details and explanations here: http://steve-parker.org/sh/functions.shtml

Rolf Rander
  • 3,221
  • 20
  • 21
10

Try this:

source path/to/shell/script.sh

It will execute the shell script in current shell.

ks1322
  • 33,961
  • 14
  • 109
  • 164
Sudhir Sinha
  • 693
  • 9
  • 18
3

One thing you can do is to add the function to your .bash profile. Then running the function won't be running a script.

I'll try it now...

testit() {
  rm -r A
  mkdir A
  touch A/test.file
  cd A
}

works...

so another option is to create a file with the function definition in it, and source that file.

chim
  • 8,407
  • 3
  • 52
  • 60
  • 1
    I had previously defined a function like this but read that .bash_profile shouldn't be too cluttered, so I moved my function to a script and encountered the same issue as the OP got. My current solution is to now use 'Edwin buck''s `. script_name` solution but set this as an alias to the normal script name in my `.bash_profile`, just as another solution option – Scott Anderson Jun 21 '20 at 07:42
0

The shortest way is typing the words in the shell:

:%w !sh
ks1322
  • 33,961
  • 14
  • 109
  • 164
zzk
  • 9
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 14 '22 at 11:48