bash command working from terminal but not from script [duplicate] - linux

a.sh
#! /bin/sh
export x=/usr/local
we can do source ./a in command-line. But I need to do the export through shell script.
b.sh
#! /bin/sh
. ~/a.sh
no error... but $x in command-line will show nothing. So it didn't get export.
Any idea how to make it work?
a.sh
#! /bin/sh
export x=/usr/local
-----------
admin#client: ./a.sh
admin#client: echo $x
admin#client: <insert ....>

You can put export statements in a shell script and then use the 'source' command to execute it in the current process:
source a.sh

You can't do an export through a shell script, because a shell script runs in a child shell process, and only children of the child shell would inherit the export.
The reason for using source is to have the current shell execute the commands
It's very common to place export commands in a file such as .bashrc which a bash will source on startup (or similar files for other shells)
Another idea is that you could create a shell script which generates an export command as it's output:
shell$ cat > script.sh
#!/bin/sh
echo export foo=bar
^D
chmod u+x script.sh
And then have the current shell execute that output
shell$ `./script.sh`
shell$ echo $foo
bar
shell$ /bin/sh
$ echo $foo
bar
(note above that the invocation of the script is surrounded by backticks, to cause the shell to execute the output of the script)

Answering my own question here, using the answers above: if I have more than one related variable to export which use the same value as part of each export, I can do this:
#!/bin/bash
export TEST_EXPORT=$1
export TEST_EXPORT_2=$1_2
export TEST_EXPORT_TWICE=$1_$1
and save as e.g. ~/Desktop/TEST_EXPORTING
and finally $chmod +x ~/Desktop/TEST_EXPORTING
--
After that, running it with source ~/Desktop/TEST_EXPORTING bob
and then checking with export | grep bob should show what you expect.

Exporting a variable into the environment only makes that variable visible to child processes. There is no way for a child to modify the environment of its parent.

Another way you can do it (to steal/expound upon the idea above), is to put the script in ~/bin and make sure ~/bin is in your PATH. Then you can access your variable globally. This is just an example I use to compile my Go source code which needs the GOPATH variable to point to the current directory (assuming you're in the directory you need to compile your source code from):
From ~/bin/GOPATH:
#!/bin/bash
echo declare -x GOPATH=$(pwd)
Then you just do:
#> $(GOPATH)
So you can now use $(GOPATH) from within your other scripts too, such as custom build scripts which can automatically invoke this variable and declare it on the fly thanks to $(pwd).

script1.sh
shell_ppid=$PPID
shell_epoch=$(grep se.exec_start "/proc/${shell_ppid}/sched" | sed 's/[[:space:]]//g' | cut -f2 -d: | cut -f1 -d.)
now_epoch=$(($(date +%s%N)/1000000))
shell_start=$(( (now_epoch - shell_epoch)/1000 ))
env_md5=$(md5sum <<<"${shell_ppid}-${shell_start}"| sed 's/[[:space:]]//g' | cut -f1 -d-)
tmp_dir="/tmp/ToD-env-${env_md5}"
mkdir -p "${tmp_dir}"
ENV_PROPS="${tmp_dir}/.env"
echo "FOO=BAR" > "${ENV_PROPS}"
script2.sh
shell_ppid=$PPID
shell_epoch=$(grep se.exec_start "/proc/${shell_ppid}/sched" | sed 's/[[:space:]]//g' | cut -f2 -d: | cut -f1 -d.)
now_epoch=$(($(date +%s%N)/1000000))
shell_start=$(( (now_epoch - shell_epoch)/1000 ))
env_md5=$(md5sum <<<"${shell_ppid}-${shell_start}"| sed 's/[[:space:]]//g' | cut -f1 -d-)
tmp_dir="/tmp/ToD-env-${env_md5}"
mkdir -p "${tmp_dir}"
ENV_PROPS="${tmp_dir}/.env"
source "${ENV_PROPS}"
echo $FOO
./script1.sh
./script2.sh
BAR
It persists for the scripts run in the same parent shell, and it prevents collisions.

Related

Bash: Creating a shell variable in a bash script that I can access from command line

I have very little experience working with bash. With that being said I need to create a bash script that takes your current directory path and saves it to a shell variable. I then need to be able to type "echo $shellvariable" and have that output the directory that I saved to that variable in the bash script. This is what I have so far.
#!/bin/bash
mypath=$(pwd)
cd $1
echo $mypath
exec bash
now when I go to command line and type "echo $mypath" it outputs nothing.
You can just run source <file_with_your_vars>, this will load your variables in yours script or command line session.
> cat source_vars.sh
my_var="value_of_my_var"
> echo $my_var
> source source_vars.sh
> echo $my_var
value_of_my_var
You have to export the variable for it to exist in the newly-execed shell:
#!/bin/bash
export mypath=$(pwd)
cd $1
echo $mypath
exec bash
Hello
'env -i' gives control what vars a shell/programm get...
#!/bin/bash
mypath=$(pwd)
cd $1
echo $mypath
env -i mypath=${mypath} exec bash
...i.e. with minimal environment.

Bash script tee command syntax issue

I want to echo the following line at the end of ~/.profile file using tee command:
export PATH="$HOME/.local/bin:$PATH"
To do this my bash script looks like this
#!/bin/bash
path_env="export PATH="$HOME/.local/bin:$PATH""
echo $path_env| sudo tee -a $HOME/.profile > /dev/null
But whenever I am executing the script it is also executing $PATH and $HOME value and inserts that in ~./profile file which I do not want. I only want the exact line to be passed by the bash script instead of replacing $PATH and $HOME with its own values.
I only want the exact line to be passed by the bash script instead of replacing $PATH and $HOME with its own values.
Och, right, so do not expand it. Quoting.
path_env='export PATH="$HOME/.local/bin:$PATH"'
echo "$path_env" | sudo tee -a "$HOME/.profile" > /dev/null

Can't run bash file inside ZSH

I've placed a bash file inside .zshrc and tried all different ways to run it every time I open a new terminal window or source .zshrc but no luck.
FYI: it was working fine on .bashrc
here is .zshrc script:
#Check if ampps is running
bash ~/ampps_runner.sh & disown
Different approach:
#Check if ampps is running
sh ~/ampps_runner.sh & disown
Another approach:
#Check if ampps is running
% ~/ampps_runner.sh & disown
All the above approaches didn't work (meaning it supposes to run an app named ampps but it doesn't in zsh.
Note: It was working fine before switching to zsh from bash. so it does not have permission or syntax problems.
Update: content of ampps_runner.sh
#! /usr/bin/env
echo "########################"
echo "Checking for ampps server to be running:"
check=$(pgrep -f "/usr/local/ampps" )
#[ -z "$check" ] && echo "Empty: Yes" || echo "Empty: No"
if [ -z "$check" ]; then
echo "It's not running!"
cd /usr/local/ampps
echo password | sudo -S ./Ampps
else
echo "It's running ..."
fi
(1) I believe ~/.ampps_runner.sh is a bash script, so, its first line should be
#!/bin/bash
or
#!/usr/bin/bash
not
#! /usr/bin/env
(2) Then, the call in zsh script (~/.zshrc) should be:
~/ampps_runner.sh
(3) Note: ~/.ampps_runner.sh should be executable. Change it to executable:
$ chmod +x ~/ampps_runner.sh
The easiest way to run bash temporarily from a zsh terminal is to
exec bash
or just
bash
Then you can run commands you previously could only run in bash. An example
help exec
To exit
exit
Now you are back in your original shell
If you want to know your default shell
echo $SHELL
or
set | grep SHELL=
If you want to reliably know your current shell
ps -p $$
Or if you want just the shell name you might use
ps -p $$ | awk "NR==2" | awk '{ print $4 }' | tr -d '-'
And you might just put that last one in a function for later, just know that it is only available if it was sourced in a current shell.
whichShell(){
local defaultShell=$(echo $SHELL | tr -d '/bin/')
echo "Default: $defaultShell"
local currentShell=$(ps -p $$ | awk "NR==2" | awk '{ print $4 }' | tr -d '-')
echo "Current: $currentShell"
}
Call the method to see your results
whichShell

Failed to execute script by calling another script

I have two shell scripts for two different user user 'a' and user 'root':
a.sh for user 'a'
export CODE=`pwd | cut -d / -f 5`
isEnabled=`grep -i isEnabled $HOME/$CODE/config/code.properties | awk -F'=' '{print $2}'`
b.sh for user 'root'
su - a -c "sh /export/home/a/a1/bin/a.sh status
As you can see, root execute script b.sh which execute script a.sh
but actually it failed since it does not find the path to the script since the
variable $CODE in a.sh probably missing in run time while running b.sh
after investigation i tired the following in b.sh:
. /path/to/a.sh
source /path/to/a.sh
. /path/to/a.sh "$CODE"
. $(/path/to/a.sh $CODE)
Can someone please advise?
Thank you all.
The variable $CODE should be there, but it will be set to a's home directory. Try using basename $0 instead of pwd. That will get the directory the script is being executed from, rather than the current working directory of user executing it.

Execute bash on logon and add alias

When I login to a Linux server per Putty, I want to execute the bash (because the default shell is another) and after that adding an alias.
I tried several combinations of putting exec bash in the .profile and adding alias foo='echo foo' into .bash_profile. But I didn't find out the correct combination. Either the alias wasn't set, or the bash wasn't executed.
So, the question is, in which of these files:
.profile
.bashrc
.bash_profile
do I have to put these commands:
exec bash
alias foo='echo foo'
to run the bash shell and have access to my alias every time I login to the server?
edit: We're using all the same user to login. But I want to execute the bash and adding the alias only for my remote machine. I do already have a suitable if statement for that. I only have to know, where to put these commands!
edit2:
What I have so far in my .profile:
if [ $(who -m | awk '{print $NF}' | grep "myHostName" | wc -l) -eq 1 ]
then
exec bash
alias foo='echo foo'
fi
This will execute the bash for only my user. But the alias will be ignored, since I'm starting a new shell and the alias will be probably set in the old shell...
Going to go out on a limb and guess you want to do this because your default shell isn't bash. Don't. Just change your default shell
> chsh -s /bin/bash
Then put
alias foo='echo foo'
In either ~/.bashrc or ~/.bash_profile
If multiple users are using the same account, you can try to do the following. While logged in, run
> who -a | grep $(ps -p $PPID -o ppid=) | awk '{print $NF}'
This may be system dependent, but on a couple I tried it on, this will get location you're logged in from. Once you have that output, do the following
if [[ $(who -a | grep $(ps -p $PPID -o ppid=) | awk '{print $NF}') == output ]]; then
alias foo='echo foo'
done
If you're ssh-ing from multiple computers, then I don't think there is any way to do what you want. Simplest would be to make your own file in the home directory, and then source it manually each time you log in.
e.g.
> touch myfile.txt
> echo "alias foo='echo foo'" >> myfile.txt
> source myfile.txt
> foo
foo
So you would just have to run source myfile.txt each time you log in or just have putty source it by default.
Okay, finally I figured it out by myself with the great help of BroSlow.
I wrote the following to my .profile:
if [ $(who -m | awk '{print $NF}' | grep "myHostName" | wc -l) -eq 1 ]
then
exec bash
fi
and the other part to the .bash_profile:
if [ $(who -m | awk '{print $NF}' | grep "myHostName" | wc -l) -eq 1 ]
then
alias foo='echo foo'
fi
This solved my problem!
On logon, the .profile will be sourced automatically and will execute the bash.
After that the .bash_profile will be sourced due to the fact, that the bash shell will source it's own profile.
However: thanks a lot for the support!
To set up alias in startup change your .bash_profile
Add alias to bash profile:
$ cd
$ sudo nano .bash_profile
$ alias ALIAS_NAME='COMMAND'
Update bash profile
$ source ~/.bash_profile

Resources