how can we change the directory in linux using perl script after taking input from user [duplicate] - linux

How to set a global environment variable in a bash script?
If I do stuff like
#!/bin/bash
FOO=bar
...or
#!/bin/bash
export FOO=bar
...the vars seem to stay in the local context, whereas I'd like to keep using them after the script has finished executing.

Run your script with .
. myscript.sh
This will run the script in the current shell environment.
export governs which variables will be available to new processes, so if you say
FOO=1
export BAR=2
./runScript.sh
then $BAR will be available in the environment of runScript.sh, but $FOO will not.

When you run a shell script, it's done in a sub-shell so it cannot affect the parent shell's environment. You want to source the script by doing:
. ./setfoo.sh
This executes it in the context of the current shell, not as a sub 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.
If filename does not contain a slash, file names in PATH are used to
find the directory containing filename.
The file searched for in PATH need not be executable. When bash is not
in POSIX mode, the current directory is searched if no file is found
in PATH.
If the sourcepath option to the shopt builtin command is turned off,
the PATH is not searched.
If any arguments are supplied, they become the positional parameters
when filename is executed.
Otherwise the positional parameters are unchanged. The return status
is the status of the last command exited within the script (0 if no
commands are executed), and false if filename is not found or cannot
be read.

source myscript.sh is also feasible.
Description for linux command source:
source is a Unix command that evaluates the file following the command,
as a list of commands, executed in the current context

#!/bin/bash
export FOO=bar
or
#!/bin/bash
FOO=bar
export FOO
man export:
The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands. If the name of a variable is followed by = word, then the value of that variable shall be set to word.

A common design is to have your script output a result, and require the cooperation of the caller. Then you can say, for example,
eval "$(yourscript)"
or perhaps less dangerously
cd "$(yourscript)"
This extends to tools in other languages besides shell script.

In your shell script, write the variables to another file like below and source these files in your ~/.bashrc or ~/.zshrc
echo "export FOO=bar" >> environment.sh
In your ~/.bashrc or ~/.zshrc, source it like below:
source Path-to-file/environment.sh
You can then access it globally.

FOO=bar
export FOO

Related

why does "source ~/.profile" keep adding to my $PATH?

This is not a problem affecting me in any way, but just for curiosity...
I have added export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
to my ~/.profile to include a new directory into my bash search.
Then, I ran $ source ~/.profile to reload may shell and I checked my path using $ echo $PATH
The question is:
- why every time I ran source ~/.profile, it appends the same information again,
- how can I clear it?
What I have tried:
- Tried running it multiple times and it keeps adding the same
- Tried to figure out what does the source command does but could not find where it is which source
First question:
why every time I ran source ~/.profile, it appends the same
information again
Simply, source <FILE> does not reload your shell. It only
executes all commands saved in <FILE> as if they were typed directly
by you in the terminal.
Second question:
how can I clear it?
To reload shell open a new terminal
window/tab. Doing just bash or exec bash won't work because a new
process will inherit its parent environment.
Third question:
Tried to figure out what does the source command does but could not
find where it is which source
As I explained once here https://unix.stackexchange.com/a/202326/72304:
All commands that can be run in Bash without typing an explicit path
to it such as ./command can be divided into two parts: Bash shell
builtins and external commands. Bash shell builtins come installed
with Bash and are part of it while external commands are not part of
Bash. This is important because Bash shell builtins are documented
inside man bash and their documentation can be also invoked with help
command while external commands are usually documented in their own
manpages or take some king of -h, --help flag. To check whether a
command is a Bash shell builtin or an external command:
$ type local
local is a shell builtin
It will display how command would be interpreted if used as a command
name (from help type). Here we can see that local is a shell builtin.
Let's see another example:
$ type vim
vim is /usr/bin/vim
In your case:
$ type source
source is a shell builtin
Now we know it's not an external command but a shell bultin (this is why which does not find it) so we need to use help to see what it does:
$ help source
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.
source executes the content of the file passed as argument in the current shell.
It appends the same information again because export is appending a string to PATH, without checking anything (it is not checking if the substring that you want to append is already in the variable).
To avoid appending to PATH every time, you should save the values of your PATH without referring to itself, e.g.:
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/local/go/bin:$GOPATH/bin
Edit:
To check if the directory is already in PATH:
if [[ ":$PATH:" != *":/usr/local/go/bin:$GOPATH/bin:"* ]]; then
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
fi

Difference with running a script using source and ./ [duplicate]

csh:
set a=0
echo "a is $a"
when i do ./my_script.csh output is:
a is
when i do source my_script.csh output is:
a is 0
Why is it so . As i know that ./ execution uses new shell.
That's right, ./my_script.csh starts a new shell, and uses the #! that you should have at the top of the file to select which shell to run (which should be csh in this case).
source my_script.csh runs the script in the current shell.
If the script is incorrectly run in, for example, the bash shell, set a=0 is not the syntax for setting an environment variable in bash, so the code won't work as you expected, because you're using the wrong shell.
Take a look at the #! at the top of the file. Is it correct?
check if variable "a" is set in your current shell:
set | grep '^a='
Remember that once you source script to your current shell,
all it's global variables are there until unset or you exit the current shell.
You may want to start a new shell, source the script, end exit shell to perform valid tests.
I don't know the context of your problem, but you may want to export some key variables to have their copies in every subprocess.

How to run a csh script from a sh script

I was wondering if there is a way to source a csh script from a sh script. Below is an example of what is trying to be implemented:
script1.sh:
#!/bin/sh
source script2
script2:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
When I run sh script1.sh, I get syntax errors generated from script2 (expected since we are using a different Shebang). Is there a way I can run script2 through script1?
Instead of source script2 run it as:
csh -f script2
Since your use case depends on retaining environment variables set by the csh script, try adding this to the beginning of script1:
#!/bin/sh
if [ "$csh_executed" -ne 1 ]; then
csh_executed=1 exec csh -c "source script2;
exec /bin/sh \"$0\" \"\$argv\"" "$#"
fi
# rest of script1
If the csh_executed variable is not set to 1 in the environment, run a csh script that sources script2 then executes an instance of sh, which will retain the changes to the environment made in script2. exec is used to avoid creating new processes for each shell instance, instead just "switching" from one shell to the next. Setting csh_executed in the environment of the csh command ensures that we don't get stuck in a loop when script1 is re-executed by the csh instance.
Unfortunately, there is one drawback that I don't think can be fixed, at least not with my limited knowledge of csh: the second invocation of script1 receives all the original arguments as a single string, rather than a sequence of distinct arguments.
You don't want source there; it runs the given script inside your existing shell, without spawning a subprocess. Obviously, your sh process can't run something like that which isn't a sh script.
Just call the script directly, assuming it is executable:
script2
The closest you can come to sourcing a script with a different executor than your original script is to use exec. exec will replace the running process space with the new process. Unlike source, however, when your exec-ed program ends, the entire process ends. So you can do this:
#!/bin/sh
exec /path/to/csh/script
but you can't do this:
#!/bin/sh
exec /path/to/csh/script
some-other-command
However, are you sure you really want to source the script? Maybe you just want to run it in a subprocess:
#!/bin/sh
csh -f /path/to/csh/script
some-other-command
You want the settings in your csh script to apply to the sh script that invokes it.
Basically, you can't do that, though there are some (rather ugly) ways you could make it work. If you execute your csh script, it will set those variables in the context of the process running the script; they'll vanish as soon as it returns to the caller.
Your best bet is simply to write a new version of your csh script as an sh script, and source or . it from the calling sh script.
You could translate your csh script:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
to this:
export TEST=1234
export PATH=/home/user/sandbox
(csh treats the shell array variable $path specially, tying it to the environment variable $PATH. sh and its derivatives don't do that, they deal with $PATH itself directly.)
Note that a script intended to be sourced should not have a #! line at the top, since it doesn't make sense to execute it in its own process; you need to execute its contents in the context of the caller.
If maintaining two copies of the script, one to be sourced from csh or tcsh scripts and another to be sourced or .ed from sh/ksh/bash/zsh script, is not practical, there are other solutions. For example, your script can print a series of sh commands to be executed; you can then do something like
eval `./foo.csh`
(line endings will pose some issues here).
Or you can modify the csh script so it sets the required environment variables and then invokes some specified command, which could be a new interactive shell; this is inconvenient, since it doesn't set those variables in the interactive shell you're running.
If a software package requires some special environment variables to be set, it's common practice to provide scripts called, for example, setup.sh and setup.csh, so that sh/ksh/bash/zsh users can do:
. /path/to/package/setup.sh
and csh/tcsh users can do:
source /path/to/package/setup.csh
Incidentally, this command:
set path = /home/user/sandbox
in your sample script is probably not a good idea. It replaces your entire $PATH with just a single directory, which means you won't be able to execute simple commands like ls unless you specify their full paths. You'd usually want something like:
set path = ( $path /home/user/sandbox )
or, in sh:
PATH=$PATH:/home/user/sandbox

How to set PATH envirnment variable through a shell script though that shell script gets terminated?

I am having a shell script ./my_shellscript.sh, its contents are as follows :
source /path/to/shell_script.sh
Where shell_script.sh contains:
export PATH=/path/to/a/dir:$PATH
which command_name
when I execute the my_shellscript.sh then it shows accurate path to a command, that I executed using "which" command?
When the shell_script.sh terminates and when I again do "which command_name" from command line it doesn't shows any path as it shown when I executed the scripts.
My question is that how to set/persist that path to environment variable [PATH:$PATH] though shell_script.sh terminates?
That's not how environments work, you can't change the parent environment. You can only change your environment, and (optionally) that of child processes to your process.
You could run your ./my_shellscript.sh with source (or .) to export it's variables to your current environment.
source my_shellscript.sh
or
. my_shellscript.sh
Other option to put the PATH variable extension into your .profile file in your home directory. (/home/your_username/.profile) That will be permanent.

How to source file from bash script

I'm trying to source a file with an environment variable from my bash script, but it doesn't work.
This is the content of my script (test.sh), which is located in ~/scripts/test.sh.
#!/bin/bash
FILE_NAME=/tmp/source_file
touch $FILE_NAME
echo "export TEST=\"test\"" > $FILE_NAME
source $FILE_NAME
Then I use alias in my ~/.bashrc.
alias testScript=~/scripts/test.sh
But when I use my script testScript, it didn't set the environment variable.
You need to use:
alias testScript=". ~/scripts/test.sh"
to source the file. Or you can use source in place of ., but I don't much like C shells so I don't use C shell notations such as source.
Environment variables only flow downstream in the process tree.
When you type testScript to a bash process, it creates a child process and execs /bin/bash or whatever is set by #!
Any environment variables set there remain only with the child process. Export causes the variables to be copied to additional grandchildren (children of that child) that might be spawned from that child.
Nothing can copy back to a parent. You need to use source instead of running the file. See Jonathan's answer.
You could try editing the files ~/.bashrc or ~/.login to set enviornment variables you need frequently.
See also https://superuser.com/q/153371 and https://superuser.com/questions/18988/difference-between-a-b-and-export-a-b-in-bash for more explanation of export in bash.
None of the other methods worked for me [source /path/to/file vs . ./path/to/file, alias, etc...], until, thanks to this tutorial I found that using the:
#!/usr/bin/env bash shebang
instead of the simpler #!/usr/bin/env one lets arguments pass on to the interpreter, which I think is the key here – see this document for more info.
In any event, if source commands in any form aren't working for you, try checking your shebang, that might be the problem :)

Resources