This question already has answers here:
bash script: how to "exit" from sourced script, and allow to work non sourced?
(3 answers)
Closed 11 months ago.
In the script below, when the code inside the if statement is executed, the user gets logged out from bash. Why is this?
#!/bin/sh
if [ -z $1 ]; then
echo "1"
read w
exit 1
fi
if [ "$#" -gt "1" ]; then
echo "1"
read w
exit 2
fi
export PTSUSER=$1.
<some more code>
If the script is sourced, and either of the if blocks are hit, then yes the current users bash shell will be exited, and the user will be logged out. This is due to sourcing a script will use the current users bash shell to execute the script.
$ . ./script.sh
On the other hand if it's run in a new bash shell instance, then this won't happen, and the bash instance will exit once either of the exit commands are executed in the shell (in either of the if blocks).
$ bash ./script.sh
It depends on how you call the script. exit causes the current shell to exit. If you source the script from a shell started after a login, i.e. it is run in the context of the current shell, exit will log the user out.
If you run the script using source and want to end script without logging-out the user,
Use return
Related
This question already has answers here:
Execute command after every command in bash
(4 answers)
Closed 1 year ago.
How do i run an arbitrary command like echo Done after any command has finished?
I want to be able to put any command in an interactive shell and it to return the same command when its done i.e.
> pwd
/home/user
Done
> ls
...
Done
> whoami
user
Done
I know if it is something specific like cd the code would be:
function cd () {
builtin cd $#
echo Done
}
but how do i do this for all commands?
Ok i found 2 ways:
Bash (by Andrej Podzimek and markp-fuso):
PROMPT_COMMAND='echo Done'
ZSH:
precmd() { "echo Done" }
For bash:
If set, the value of $PROMPT_COMMAND is executed immediately before each prompt is printed.
It's possible to hard quote command substitutions in PS0, PS1, and PS2, which will be executed every time the respective prompt is printed.
You can trap SIG_CHLD: trap my-cmd CHLD. The given command will execute in the current environment, every time a child process (command) exits, including background processes. This does not include built-ins (which are not child processes), but it does work in a script.
This question already has answers here:
Pass commands as input to another command (su, ssh, sh, etc)
(3 answers)
Closed 2 years ago.
I am trying to write a script that sets my main terminal to use bash shell. I know the #!/bin/bash will call all the commands in the script to be run with the bash shell but what I want is a script that specifically that changes the shell of my terminal to bash.
for example: (this is how my terminal looks like when it is opened.)
$
when i want to set the terminal to bash I manually type the bash command and press enter.
$bash
outcome:
[tyg#rooto ~]$
The problem is if I write a script using the above command it works but any command after the bash command in the script fails to execute.
for example
#!/bin/bash
bash
echo "setting terminal environment to bash"
echo "success"
output:
[tyg#rooto ~]$
Expected output: (something like this)
[tyg#rooto ~]$ setting terminal environment to bash
[tyg#rooto ~]$ success
or (Like this)
[tyg#rooto ~]$
[tyg#rooto ~]$ setting environment
[tyg#rooto ~]$ success
any of the above is what I assume should be expected. Why are the two echo commands in the script failing to execute and is there a fix to this. Thanks
#!/bin/bash will invoke the shell in which the subsequent script commands will be executed and upon completion, the shell will be gone. This is how you "execute commands in the changed shell"
bash on line 2 opens a 2nd bash shell in which your echo command is being executed. It too goes away on completion of the script - that's why you don't see the output as expected.
Yes, you can execute a "bash" script in any shell as long as the first line has the correct shell you want.
By removing the bash on line two, you'll see your output.
Example 1
#!/bin/bash
bash << "EOT"
echo "setting environment"
EOT
Example 2
Add this code to a sample script, test.sh, then launch it:
#!/bin/bash
echo "Shell: $$"
bash << "EOT"
echo "Shell: $$"
EOT
echo "Shell: $$"
Result:
Shell: 569 # Current shell
Shell: 570 # Shell in your new enviroment
Shell: 569 # Back to old shell
This question already has answers here:
Pass commands as input to another command (su, ssh, sh, etc)
(3 answers)
Closed 6 years ago.
I'm very very new to Linux(coming from windows) and trying to write a script that i can hopefully execute over multiple systems. I tried to use Python for this but fount it hard too. Here is what i have so far:
cd /bin
bash
source compilervars.sh intel64
cd ~
exit #exit bash
file= "~/a.out"
if[! -f "$file"]
then
icc code.c
fi
#run some commands here...
The script hangs in the second line (bash). I'm not sure how to fix that or if I'm doing it wrong. Please advice.
Also, any tips of how to run this script over multiple systems on the same network?
Thanks a lot.
What I believe you'd want to do:
#!/bin/bash
source /bin/compilervars.sh intel64
file="$HOME/a.out"
if [ ! -f "$file" ]; then
icc code.c
fi
You would put this in a file and make it executable with chmod +x myscript. Then you would run it with ./myscript. Alternatively, you could just run it with bash myscript.
Your script makes little sense. The second line will open a new bash session, but it will just sit there until you exit it. Also, changing directories back and forth is very seldom required. To execute a single command in another directory, one usually does
( cd /other/place && mycommand )
The ( ... ) tells the shell that you'd like to do this in a sub-shell. The cd happens within that sub-shell and you don't have to cd back after it's done. If the cd fails, the command will not be run.
For example: You might want to make sure you're in $HOME when you compile the code:
if [ ! -f "$file" ]; then
( cd $HOME && icc code.c )
fi
... or even pick out the directory name from the variable file and use that:
if [ -f "$file" ]; then
( cd $(dirname "$file") && icc code.c )
fi
Assigning to a variable needs to happen as I wrote it, without spaces around the =.
Likewise, there needs to be spaces after if and inside [ ... ] as I wrote it above.
I also tend to use $HOME rather than ~ in scripts as it's more descriptive.
A shell script isn't a record of key strokes which are typed into a terminal. If you write a script like this:
command1
bash
command2
it does not mean that the script will switch to bash, and then execute command2 in the different shell. It means that bash will be run. If there is a controlling terminal, that bash will show you a prompt and wait for a command to be typed in. You will have to type exit to quit that bash. Only then will the original script then continue with command2.
There is no way to switch a script to a different shell halfway through. There are ways to simulate this. A script can re-execute itself using a different shell. In order to do that, the script has to contain logic to detect that it is being re-executed, so that it can prevent re-executing itself again, and to skip some code that shouldn't be run twice.
In this script, I implemented such a re-execution hack. It consists of these lines:
#
# The #!/bin/sh might be some legacy piece of crap,
# not even up to 1990 POSIX.2 spec. So the first step
# is to look for a better shell in some known places
# and re-execute ourselves with that interpreter.
#
if test x$txr_shell = x ; then
for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
if test -x $shell ; then
txr_shell=$shell
break
fi
done
if test x$txr_shell = x ; then
echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
txr_shell=/bin/sh
fi
export txr_shell
exec $txr_shell $0 ${#+"$#"}
fi
The txr_shell variable (not a standard variable, my invention) is how this logic detects that it's been re-executed. If the variable doesn't exist then this is the original execution. When we re-execute we export txr_shell so the re-executed instance will then have this environment variable.
The variable also holds the path to the shell; that is used later in the script; it is passed through to a Makefile as the SHELL variable, so that make build recipes use that same shell. In the above logic, the contents of txr_shell don't matter; it's used as Boolean: either it exists or it doesn't.
The programming style in the above code snippet is deliberately coded to work on very old shells. That is why test x$txr_shell = x is used instead of the modern syntax [ -z "$txr_shell" ], and why ${#+"$#"} is used instead of just "$#".
This style is no longer used after this point in the script, because the
rest of the script runs in some good, reasonably modern shell thanks to the re-execution trick.
This question already has answers here:
Global environment variables in a shell script
(7 answers)
Closed 8 years ago.
I am novice for shell scripting. I have written one script which checks if ORACLE_HOME AND ORACLE_SID are set. Inside this I have called other script to set the env variables.
First Script
while [ 1 -gt 0 ]
do
echo -e "Please enter path of oracle home directory:\c"
read DB_HOME
if [ -d $DB_HOME ]
then
./oracle_env.sh $DB_HOME "test1"
echo "ORACLE_HOME has been set successfully!"
status="Y"
break
else
echo "Path or directory does not exist."
fi
done
Second Script
#This script will set ORACLE_HOME and SID
export ORACLE_HOME=$1
export ORACLE_SID=$2
When I run the second script as
./oracle_env.sh /u01/app/oracle test
it's working fine. I mean, when I run
echo $ORACLE_HOME
it gives path like
/u01/app/oracle
Now the problem is when I run the same script from first script, it's not working.
Please help me out !!!
The problem is quite simple:
If you execute a script it starts in a new shell, sets the environment there and close the shell. As result nothing changes in the first calling shell.
So you have to execute the script in the first shell with source <shellscript>
For details see man bash
I have no idea which shell you use. Maybe the solution is a bit different for other shells.
Try this for setting environment variable in your terminal: (Below code is for xampp not for oracle, path will vary w.r.t your requirement)
export PATH=/opt/lamp/bin:$PATH
You can see your environment variables by:
echo $PATH
See, if that works for you.
Run the script with source (or) . command.
while [ 1 -gt 0 ]
do
echo -e "Please enter path of oracle home directory:\c"
read DB_HOME
if [ -d $DB_HOME ]
then
. oracle_env.sh $DB_HOME "test1" ## Here you run the script with . command.
echo "ORACLE_HOME has been set successfully!"
status="Y"
break
else
echo "Path or directory does not exist."
fi
done
Run your first script also with . command.
$ . script.sh
I am writing a script to become a user (let's call it genomics) via the cmd "sudo /etc/bgenomics" (this is setup by our admin) and run some bash code as that user, namely run a cmd, catch the exit code and take the appropriate action.
The problem is the bash code inside the here doc get printed to the screen, which is distracting and looks really unelegant.
Here's an illustration:
#!/bin/bash
name='George'
sudo /etc/bgenomics <<Q
/bin/bash
if (( 2 == 2 )); then
echo "my name is $name"
grep zzz /etc # will return nothing and $? = 1
echo \$? # this should be 1 after the above cmd
fi
Q
The if statement is just there to show how annoying it is when printed.
Right now all of the following is printed to the screen:
Script started, file is /var/tmp/genomicstraces/c060644.20140617143003.11536
Script done, file is /var/tmp/genomicstraces/c060644.20140617143003.11536
brainiac-login-02$brainiac-login-02$/bin/bash
bash-3.2$ if (( 2 == 2 )); then
> echo "my name is George"
> grep zzz /etc # will return nothing and 0 = 1
> echo $? # this should be 1 after the above cmd
> fi
my name is George
1
The only parts I want to see are "my name is George" and "1". Can it be done?
Is another process calling this script? Output shouldn't normally appear unless bash is called with '-x'. Try modifying the first line of your script if you cannot disable echo in the calling process:
#!/bin/bash +x
You may also want to remove the call to /bin/bash after the sudo command unless you really wish to start another shell within your shell.
The here document supplies input to the bgenomics script via its standard input. What happens to that input is up to that script.
If you want the script to print some of its input, and not print some of its input, you have to modify the script.
If bgenomics is actually a wrapper for an interactive shell session (as it seems to be, judging by the Script started and Script done traces), then here documents are not the best way to feed input into it.
A good way is to use the expect utility, which controls interactive programs via a pseudo-terminal device and provides a scripting language with a great deal of control. expect can suppress all unwanted input from an interactive program. It can look for specific outputs from the program, and supply responses. For instance it can look for a login: string coming from the interactive session, and send a user name.
The program bgenomics has an invocation of script in it to record what the script did. Talk to the person in charge of that to understand what their intentions are. Until you understand the purpose of bgenomics you risk screwing up what the author of that is trying to do.
$ script /tmp/junk.txt
Script started, file is /tmp/junk.txt
$ date # this is a child shell of the script command
Tue Jun 17 21:04:14 EDT 2014
$ exit
Script done, file is /tmp/junk.txt