active .bashrc setting in bash files - bash

Instead of using default python, in .bashrc I change "python" point to my own python version. However, when I write a bash scripts and call for python in it, it still uses the default python. Why is that, and how can I set it so that I do not have to add "source ~/.bashrc" to every sh file? Thanks
[yl#chh test]$ more test.sh
echo `which python`
[yl#chh test]$ sh test.sh
/usr/bin/python
[yl0#chh test]$ which python
alias python='~/tools/Python-2.7.3/python'
~/tools/Python-2.7.3/python

From the bash man page:
Aliases are not expanded when the shell is not interactive, unless
the expand_aliases shell option is set using shopt (see the
description of shopt under SHELL BUILTIN COMMANDS below).
It would probably be better to change your PATH rather than using an alias for this purpose.

Related

How can I use aliases in bash scripts without changing the scripts?

I know writing
source ~/.bashrc
shopt -s expand_aliases
in a bash script allows to use aliases defined in .bashrc file.
However, I have so many bash scripts, and I cannot change all those scripts.
Is there a way to let my aliases used in all my scripts, with setting env or something?
Put the code that enables aliases and sources .bashrc to another file, assign its path to BASH_ENV, and export BASH_ENV.
$ cat .bashrc
alias dt=date
$ cat my_env.sh
shopt -s expand_aliases
source ~/.bashrc
$ cat my_script
#!/bin/bash
dt
$ export BASH_ENV=my_env.sh
$ ./my_script
Tue Mar 30 07:57:50 +03 2021

bash script yields a different result when sourced

Could you help me, why this script works when sourced (or even directly on console) and does not work on a script?
I have checked and in any case I'm using the same bash in /bin/ and always 4.4.19(1)-release (checked with $BASH_VERSION).
Moreover I tried removing shebang but nothing changes.
#!/bin/bash
fname=c8_m81l_55.fit
bname=${fname%%+(_)+([0-9]).fit}
echo $bname
GIving these results:
test:~$ ./test.sh
c8_m81l_55.fit
test:~$ . ./test.sh
c8_m81l
Bash does not recognize +(pattern) syntax unless extglobs are enabled, and they are disabled by default. Apparently your bash setup enables them in interactive sessions; that's why your script works only when sourced in an interactive shell.
To fix that, either enable extglobs within the script by this command:
shopt -s extglob
Or use an alternative that works irrespective of shell's interactiveness:
bname=$(sed 's/__*[0-9][0-9]*\.fit$//' <<< $fname)
# with GNU sed it'd look like:
bname=$(sed -E 's/_+[0-9]+\.fit$//' <<< $fname)

About builtin command puzzle

[root#MGWSDT_FEWS bin]# type cd
cd is a shell builtin
[root#MGWSDT_FEWS bin]# which cd
/usr/bin/which: no cd in (.:/usr/expect/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/real/RealPlayer:/root/bin)
It says that because cd is a builtin command, so 'which cd' failed.
'pwd' is also a builtin command, why 'which pwd' can get its location?
[root#MGWSDT_FEWS ~]# type pwd
pwd is a shell builtin
[root#MGWSDT_FEWS ~]# which pwd
/bin/pwd
Understand that for sudo or any other command that is not a shell builtin, when the command terminates, the shell picks up where it left off before the command was run (of course, the shell's current working directory won't change). As such, cd must be a shell builtin; otherwise, when cd terminates, the shell is back to the same old current working directory. In other words, a child process (i.e. an external command) can't change the working directory of the parent process (i.e. the shell).
Courtesy: https://bbs.archlinux.org/viewtopic.php?id=127225
cd command is bash's command. (bash built in command)
You can find cd's usage in "man bash & find cd"
Contrary, pwd is standalone command.
Builtin commands are internal commands in the shell and has a higher priority over external commands (files). And builtin commands also have lower priority than functions so builtin is actually helpful if you have a function with the same name as the builtin command like this:
function cd {
if [[ $# -gt 0 ]]; then
echo "Changing directory to $1."
builtin cd "$1"
else
echo "Changing to default directory."
builtin cd
fi
}
cd "/some/where"
As a summary functions gets called first before builtins, and builtins gets called first before binary commands or files. The type command I think would also follow that order when interpreting an argument.
There are several instances where "commands" are duplicated, but of course this will depend on your installation. If you have a shell built-in called pwd then that will be used, but there might be shells (csh) that do not have pwd as a built-in.
printf is a shell built-in for bash and ksh93 but not for ksh88 or csh.
Another (weirder) example is [, which is a shell built-in but (on some systems) a symbolic link to test (which might also be a shell built-in).
Your installation is there to support many shells and other programs, not just bash.
cd has to be shell-built-in, because it were a separate process, then the effect of the command would have vanished, after the command exits. (See Sakthi Kumar's answer.)
On the other hand, some other commands like pwd, test are available as binaries, like /bin/pwd, /usr/bin/test... However, for optimization, shell has also implementation of these binaries within /bin/bash itself, so that the overhead of creating a separate process is avoided.
when you call pwd, shell calls its own pwd implementation. You can call the binary /bin/pwd using command pwd instead of just pwd.
Commands such as pwd and echo are bash-builtins and also available as external commands. You can use enable to enable/disable shell builtins.
The following example iillustrates how pwd can be invoked either as a shell-builtin or as external command i.e. /bin/pwd.
$ type pwd
pwd is a shell builtin
$ which pwd
/bin/pwd
$ enable -n pwd
$ type pwd
pwd is /bin/pwd
$ which pwd
/bin/pwd
$ enable pwd
$ type pwd
pwd is a shell builtin
$ which pwd
/bin/pwd

Jenkins can't access shell alias

I have configured a Jenkins job to source a bash script that sources another bash script which adds an alias to the .bashrc of its user and sources the .bashrc itself, and then original script tries to use that alias (set by the second). However, it cannot seem to find the alias it has just created. I am not using any scripting plugins aside from using a "Send files or execute commands over SSH" build step to source the script.
The job does this:
source ./test_script.sh
test_script.sh looks like this:
echo "In test_script.sh"
echo $USER
echo $HOME
source ./setup_env.sh
echo "\nBack in test_script.sh"
alias foo
foo
And finally, setup_env.sh looks like this:
echo "\nIn setup_env.sh"
echo "alias foo=\"echo foobar\"" >> $HOME/.bashrc
source $HOME/.bashrc 2>/dev/null
cat $HOME/.bashrc
The output I receive from the Jenkins job looks like this:
In test_script.sh
my_user
/home/my_user
\nIn setup_env.sh
...all of my bashrc...
alias foo="echo foo"
\nBack in test_script.sh
alias foo='echo foo'
./test_script.sh: line 7: foo: command not found
I don't understand why this is happening, when I can happily run it myself on the command-line and watch it succeed. Why can't Jenkins use the new alias, when it can obviously find it (as demonstrated by the output of the alias foo command)?
For anyone else who's having this problem, you may need to set the expand_aliases shell option, which seems to be off by default with Jenkins:
shopt expand_aliases # check if it's on
shopt -s expand_aliases # set expand_aliases option to true
shopt expand_aliases # it should be on now
# test with a simple alias, should print 1
alias x="python -c 'print 1'"
x
The \n that is showing in the output of your echo commands
suggest this is not running under bash, as you may be expecting.
Please check the setting of your jenkins user
(or any other user that you run Jenkins with) -
especially the setting of the default shell.
To test this, add one of those lines at the beginning of your script:
env
or
env | grep -i shell
Should also consider making sure your scripts run under the correct shell,
by adding the "shebang" line as the first line in each script.
In the case of 'bash', for example, you should add the following first line:
#!/bin/bash
(it is not a comment, despite what the auto-syntax-highlighter may think...)

ssh command execution doesn't consider .bashrc | .bash_login | .ssh/rc? [duplicate]

This question already has answers here:
Why aliases in a non-interactive Bash shell do not work
(4 answers)
Closed 6 years ago.
I am trying to execute a command remotely over ssh, example:
ssh <user>#<host> <command>
The command which needs to be executed is an alias, which is defined in .bashrc, e.g.
alias ll='ls -al'
So what in the end the following command should get executed:
ssh user#host "ll"
I already found out that .bashrc only gets sourced with interactive shell, so in .bash_login I put:
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
and I also tried to define the alias directly in .bash_login.
I also tried to put the alias definition / sourcing of .bashrc in .bash_profile and also in .ssh/rc. But nothing of this works.
Note that I am not able to change how the ssh command is invoked since this is a part of some binary installation script. The only thing I can modify is the environment. Is there any other possibility to get this alias sourced when the ssh command is executed? Is there some ssh configuration which has to be adapted?
From the man pages of bash:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt
There are a couple ways to do this, but the simplest is to just add the following line to your .bashrc file:
shopt -s expand_aliases
Instead of:
ssh user#host "bash -c ll"
try:
ssh user#host "bash -ic ll"
to force bash to use an "interactive shell".
EDIT:
As pointed out here about non-interactive shells..
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# execution returns after this line
Now, for every alias in your bashrc file say i have:
alias ll="ls -l"
alias cls="clear;ls"
Create a file named after that alias say for ll:
user#host$ vi ssh_aliases/ll
#inside ll,write
ls -l
user#host$ chmod a+x ll
Now edit .bashrc to include:
# If not running interactively, don't do anything
[ -z "$PS1" ] && export $PATH=$PATH:~/ssh_aliases
This does the job.. although I am not sure if it is the best way to do so
EDIT(2)
You only need to do this for aliases, other commands in bashrc will be executed as pointed out by David "you must have executable for ssh to run commands".
an alternative to alias that will be visible in all script is
EXPORT & EXECUTE VARIABLE
# shortcut to set enviroment to insensitive case
export go_I="shopt -s nocasematch"
Now in any script you can use
#!/bin/bash
$go_I # go Insensitive
[[ a == A ]] # evaluates TRUE ( $? == 0)
$go_C # maibe want to go back to casesensitive
it's useful to place all shortcuts/aliases in /path/to/my_commands and edit /etc/bash.bashrc
source /path/to/my_commands
Open file ~/.bash_profile. If this file does not exist create one in the home directory and add the below line
source = $HOME/.bashrc
exit your ssh and login agian and you should get the .bashrc settings working for you.

Resources