bash alias cp='cp -i' not work as expectation in script - bash

#!/bin/bash
alias cp='cp -i'
alias # this line output: "alias cp='cp -i'"
touch /tmp/{a,b}.txt
cp /tmp/a.txt /tmp/b.txt # this line doesn't work as my expectation
I expect it will show prompt at end, like this: "cp: overwrite ‘/tmp/b.txt’?"

It is because bash script is run in non-interactive mode. Try:
#!/bin/bash -i
or
shopt -s expand_aliases
Aliases are not expanded when the shell is not interactive, unless the
expand_aliases shell option is set using shopt.
See asnwers to: How to run an alias in a shell script?
Alternatively, you can use shell functions instead of aliases. Check answer to: In Bash, when to alias, when to script, and when to write a function?

Related

Is it possible to print all the commands when they are executed in Bash?

From How to echo shell commands as they are executed I've learned how to use set -v to print commands when they are executed. It works well if set -v is added at the beginning of foo.sh or bash -v foo.sh is run. However, if foo.sh invokes bar.sh by bash bar.sh or simply ./bar.sh, the commands in bar.sh are not printed. Is there a global switch that enables all the commands and functions, through all invoked scripts, to be printed when they are executed?
Is there a global switch that enables all the commands and functions, through all invoked scripts, to be printed when they are executed?
Yes, BASH_ENV can be used for that. The manual describes it as follows.
If this variable is set when Bash is invoked to execute a shell script, its value is expanded and used as the name of a startup file to read before executing the script.
So, you can just put set -v in a file and assign its path to BASH_ENV while invoking the first script. For example:
$ cat env.sh
set -v
$
$ cat foo
#!/bin/bash
true
./bar
$
$ cat bar
#!/bin/bash
false
$ BASH_ENV=./env.sh ./foo
#!/bin/bash
true
./bar
#!/bin/bash
false
Alternatively, to do this without having to create an extra file, you can start the script with a fabricated SHELLOPTS value
# too long, and might require adjustments for future versions
env SHELLOPTS=braceexpand:hashall:interactive-comments:verbose ./foo
or, enable verboseness by the set command or by adding -v to the shebang and export SHELLOPTS within the first script.
set -v
# exports all options, not only `verbose'
export SHELLOPTS
# the rest of the script

How do I execute a shell builtin after executing a shell automatically without using profile and RC files?

I want to execute my shell with the environment I provide as the command line arguments. For that I have a script that ends with exec zsh -d -f after setting all the variables I want, which gives me a new shell with all variables set.
e.g:
export MY_SESSION="$1"
cd $2
export PS1="$3; "
exec zsh -d -f
My issue is that, I also want to execute bindkey -e on the new shell before it is made available. How do I do that?
I managed to do this with expect. Here is what I did.
#!/usr/bin/env expect
spawn /bin/zsh -d -f
send "source ./bin/activate\r"
send "export PS1='*| '\r"
send "bindkey -e\r"
interact
This successfully sends the bindkey -e on the produced zsh shell.

bash: parse_git_branch: command not found

This should be very simple.
I recently noticed that when I type 'bash' into Terminal on Mac it shows this:
Jays-MacBook-Pro: ~ $ bash
bash: parse_git_branch: command not found
When before it didn't. Can someone explain why and how to resolve.
It is likely that you configured BASH to run parse_git_branch and print the result as part of PS1 (or alike). You can check this by: "echo $PS1" and "echo $PROMPT_COMMAND".
However, parse_git_branch is not a builtin function of bash. Below is how I configured my PS1. You may want to copy my git_branch_4_ps1 as your parse_git_branch
PS1='\n' # begin with a newline
PS1=$PS1'\[\e[38;5;101m\]\! \t ' # time and command history number
PS1=$PS1'\[\e[38;5;106m\]\u#\h ' # user#host
PS1=$PS1'\[\e[7;35m\]${MY_WARN}\[\e[0m\] ' # warning message if there is any
PS1=$PS1'\[\e[38;5;10m\]${MY_EXTRA} ' # extra info if there is any
PS1=$PS1'\[\e[0;36m\]$(git_branch_4_ps1) ' # git_branch_4_ps1 defined below
PS1=$PS1'\[\e[38;5;33m\]\w' # working directory
PS1=$PS1'\n\[\e[32m\]\$ ' # "$"/"#" sign on a new line
PS1=$PS1'\[\e[0m\]' # restore to default color
function git_branch_4_ps1 { # get git branch of pwd
local branch="$(git branch 2>/dev/null | grep "\*" | colrm 1 2)"
if [ -n "$branch" ]; then
echo "(git: $branch)"
fi
}
If your parse_git_branch is defined in ~/.bash_profile, it will not be loaded when you open a non-login shell (e.g. by running bash).
The differences between login and non-login shells are described here: Difference between Login Shell and Non-Login Shell? For our purposes, the main difference is that login shells (e.g. that when you first open Terminal) automatically source ~/.bash_profile upon startup, whereas non-login shells (e.g. that when you run bash from within Terminal) do not.
To fix this error, simply source your ~/.bash_profile after running bash:
user#host:~ $ bash
bash: parse_git_branch: command not found
user#host:~ $ source .bash_profile
Alternatively, place the function in ~/.bashrc instead, which will be automatically sourced by non-login shells (as covered in the earlier link).
Instead of having
parse_git_branch
call in PS1 definition alone you may use
parse_git_branch 2>/dev/null
to send stderr to /dev/null. This will silence the error you don't want to see.
have you export your $PS1 ?
You can check by run command:
printenv
else you should export it by run:
export -n PS1
after you will can run sudo or sudo su without problem
The key to this is to NOT export PS1. If it's exported, then any non-login shell also takes PS1. Since .bash_profile is automatically source'd by the login shell, the PS1 variable only affects the login shell.

bash script not reading alias in bashrc [duplicate]

This question already has answers here:
How to set an alias inside a bash shell script so that is it visible from the outside? [duplicate]
(4 answers)
How to use aliases defined in .bashrc in other scripts?
(6 answers)
Closed 2 years ago.
I have created an alias in the .bashrc file:
alias java='java -Xmx1200m'
This alias works when I run a java command from my shell directly.
However, when the java command is inside a bash script (script.sh), this alias does not get activated. How do I ensure that the aliases in .bashrc file are accepted in a bash script ??
Alias are not expanded in non-interactive shells.
The only way to make an alias is to source the target script with the one which contains the alias.
$ source .bashrc
$ . custom_script.sh
Quoting from the bash manual:
Aliases are not expanded when the shell is not interactive, unless the
expand_aliases shell option is set using shopt (see The Shopt
Builtin).
Saying the following in your script should make it work:
shopt -s expand_aliases
Aliases are limited to the shell and do not work in executed shell scripts. You are better off creating a variable.
The simplest answer is to do the 2 important things or it wont' work. In your other script, do the following: -i for interactive mode, and shopt part as mentioned below.
#!/bin/bash -i
# Expand aliases defined in the shell ~/.bashrc
shopt -s expand_aliases
After this, your aliases that you have defined in ~/.bashrc they will be available in your shell script (giga.sh or any.sh) and to any function or child shell within such script.
If you don't do that, you'll get an error:
your_cool_alias: command not found
You can run your script under bash bash in interactive mode; add -i to bash command line, like this script. Now you can use your aliases.
#!/bin/bash -i
alias lsd='ls -al | grep ^d'
lsd

using alias in shell script? [duplicate]

This question already has answers here:
How to use aliases defined in .bashrc in other scripts?
(6 answers)
Closed 2 years ago.
My alias defined in a sample shell script is not working. And I am new to Linux Shell Scripting.
Below is the sample shell file
#!/bin/sh
echo "Setting Sample aliases ..."
alias xyz="cd /home/usr/src/xyz"
echo "Setting done ..."
On executing this script, I can see the echo messages. But if I execute the alias command, I see the below error
xyz: command not found
am I missing something ?
source your script, don't execute it like ./foo.sh or sh foo.sh
If you execute your script like that, it is running in sub-shell, not your current.
source foo.sh
would work for you.
You need to set a specific option to do so, expand_aliases:
shopt -s expand_aliases
Example:
# With option
$ cat a
#!/bin/bash
shopt -s expand_aliases
alias a="echo b"
type a
a
$ ./a
# a is aliased to 'echo b'
b
# Without option
$ cat a
#!/bin/bash
alias a="echo b"
type a
a
$ ./a
./a: line 3: type: a: not found
./a: line 4: a: command not found
reference: https://unix.stackexchange.com/a/1498/27031 and https://askubuntu.com/a/98786/127746
sourcing the script source script.sh
./script.sh will be executed in a sub-shell and the changes made apply only the to sub-shell. Once the command terminates, the sub-shell goes and so do the changes.
OR
HACK: Simply run following command on shell and then execute the script.
alias xyz="cd /home/usr/src/xyz"
./script.sh
To unalias use following on shell prompt
unalias xyz
If you execute it in a script, the alias will be over by the time the script finishes executing.
In case you want it to be permanent:
Your alias is well defined, but you have to store it in ~/.bashrc, not in a shell script.
Add it to that file and then source it with . .bashrc - it will load the file so that alias will be possible to use.
In case you want it to be used just in current session:
Just write it in your console prompt.
$ aa
The program 'aa' is currently not installed. ...
$
$ alias aa="echo hello"
$
$ aa
hello
$
Also: From Kent answer we can see that you can also source it by source your_file. In that case you do not need to use a shell script, just a normal file will make it.
You may use the below command.
shopt -s expand_aliases
source ~/.bashrc
eval $command
Your alias has to be in your .profile file not in your script if you are calling it on the prompt.
If you put an alias in your script then you have to call it within your script.
Source the file is the correct answer when trying to run a script that inside has an alias.
source yourscript.sh
Put your alias in a file call ~/.bash_aliases and then, on many distributions, it will get loaded automatically, no need to manually run the source command to load it.

Resources