I have been trying to add optional aliases to my .bash_aliases file, but I have run into an issue with optionally adding aliases. So far it seems that the aliases get added no matter what the if statement seems to be evaluating to true.
Here is an example of what I am trying to do:
alias gh="history | grep"
alias python="python3"
# personal computer aliases
if [ ${COMPUTER_TYPE} = "personal" ]
then
alias hibernate="sudo systemctl hibernate"
fi
Here is the variable being set in .bashrc (setting it in .profile does not seem to do anything either):
export COMPUTER_TYPE=work
Echoing the variable:
$ echo $COMPUTER_TYPE
work
Any idea what I am doing wrong here? If I had to guess, the .bash_aliases file is not a bash file that gets treated as one, but that seems unlikely. Thanks for the help!
Edit: I see that my question may be misleading as the example used was a personal computer, but the problem is that when I run the alias on a work computer it still adds all aliases. I have since updated the example to use work instead of personal.
Right now, you're checking COMPUTER_TYPE while your .bash_aliases file is being sourced, not when the hibernate command is being run. Consequently, you're creating an ordering dependency: .bash_aliases only defines hibernate at all when COMPUTER_TYPE is set at a prior point in initialization.
The easy way to avoid this dependency is to make hibernate be a function instead, so it gets defined either way but then checks COMPUTER_TYPE at runtime:
hibernate() {
case $COMPUTER_TYPE in
personal)
sudo systemctl hibernate "$#"
;;
*)
echo "Ignoring hibernate command on a non-personal computer" >&2
return 1
;;
esac
}
Related
I am trying to use the solution of using sudo on my existing aliases as covered in many existing answers already and i am so confused as to why it is not working
alias sudo='sudo '
I keep all my aliases in .bash_aliases. Inside .bash_aliases I have this
function _test {
echo 'test!'
}
alias test='_test'
I reload the .bashrc each time; source .bashrc but when I run sudo test I always get
sudo: _test: command not found
The only strange thing that happens is that I get the following on reload and not on a new terminal
dircolors: /home/MYHOME/.dircolors: No such file or directory
but i feel this is a red herring.
As l0b0 says, aliases cannot be used in this way in bash.
However, you can pass a function through (and really, there's basically never a good reason to use an alias instead of sticking to functions alone).
_test() {
echo 'test!'
}
sudo_test() {
sudo bash -c "$(declare -f _test)"'; _test "$#"' sudo_test "$#"
}
...will define a command sudo_test that runs the function _test via sudo. (If your real-world version of this function calls other functions or requires access to shell variables, add those other functions to the declare -f command line, and/or add a declare -p inside the same command substitution to generate a textual description of variables your function needs).
To run an alias like alias_name it must be exactly the first word in the command, so sudo alias_name will never work. Ditto 'alias_name', \alias_name and other things which eventually expand to the alias name.
I am trying to use the solution of using sudo on my existing aliases as covered in many existing answers already and i am so confused as to why it is not working
alias sudo='sudo '
I keep all my aliases in .bash_aliases. Inside .bash_aliases I have this
function _test {
echo 'test!'
}
alias test='_test'
I reload the .bashrc each time; source .bashrc but when I run sudo test I always get
sudo: _test: command not found
The only strange thing that happens is that I get the following on reload and not on a new terminal
dircolors: /home/MYHOME/.dircolors: No such file or directory
but i feel this is a red herring.
As l0b0 says, aliases cannot be used in this way in bash.
However, you can pass a function through (and really, there's basically never a good reason to use an alias instead of sticking to functions alone).
_test() {
echo 'test!'
}
sudo_test() {
sudo bash -c "$(declare -f _test)"'; _test "$#"' sudo_test "$#"
}
...will define a command sudo_test that runs the function _test via sudo. (If your real-world version of this function calls other functions or requires access to shell variables, add those other functions to the declare -f command line, and/or add a declare -p inside the same command substitution to generate a textual description of variables your function needs).
To run an alias like alias_name it must be exactly the first word in the command, so sudo alias_name will never work. Ditto 'alias_name', \alias_name and other things which eventually expand to the alias name.
I would like to make an executable shell-script that once launched execute a certain action, and if launched again in a second time undo the action. I've tried to define an environment variable to determinate if the action has been already executed, but I can't make it work.
#!/bin/bash
if [ -z ${CUSTOM_VARIABLE} ]
then
CUSTOM_VARIABLE=true
export CUSTOM_VARIABLE
# do stuff here
else
# undo stuff here
unset CUSTOM_VARIABLE
fi
Is this a correct approach? How can I fix the code
Thanks in advance
Note jdv's comment.
You cannot run your script as a standalone execution and have it alter the environment of the parent. Calling it x.sh,
x.sh
will never change your env. On the other hand, you can source it.
. x.sh
which reads it and executes its content in the current scope, so that would work. You aren't really creating a separate program doing that - just storing a scripted list of commands and using the source shorthand to execute them in bulk, so to speak.
You could also define it as a function for similar result -
$: x() {
if [[ -z "${CUSTOM_VARIABLE}" ]]
then export CUSTOM_VARIABLE=true
else unset CUSTOM_VARIABLE
fi
}
YMMV.
Good luck.
On linux using bash,
lets say I made two programs both called print_report.
(They are in different directories.)
Inside my .bashrc file, I have:
PATH="path/to/print_report1/:$PATH"
This allows me to type print_report anywhere and it will run one of the programs.
How can I have bash decide to use one or the other depending on the working directory?
for example,
If I'm currently in ~/project1/ and type print_report it will use /bin/foo/print_report
If I'm currently in ~/project2/ and type print_report it will use /bin/bar/print_report
You can't do that as such. Instead, write a wrapper script or function that checks the current directory and invokes the right command:
#!/bin/bash
if [[ $PWD == $HOME/project1/* ]]
then
/bin/foo/print_report "$#"
elif [[ $PWD == $HOME/project2/* ]]
then
/bin/bar/print_report "$#"
else
echo "Don't know how to print_report for $PWD"
fi
You can emulate preexec hooks à la zsh, using the DEBUG trap.
In that way, every time a command is executed, you can run a preexec hook to check $PWD, and adjust $PATH accordingly.
You can include a preexec hook doing what you want in your .bashrc.
This is a security disaster waiting to happen, (which is to say you really don't want to do this) but you can certainly do something like:
cd() {
dir=${1-.}
case $dir in)
path1) PATH=/path/for/working/in/path1;;
path2) PATH=/path/for/working/in/path2;;
*) PATH=/bin:/usr/bin;;
esac
command cd $dir
}
(Put that in your .bashrc or just define it in the current shell.)
Everything presented here so far strikes me as overly complicated and needlessly complex hackery. I would just place a Makefile in each directory with
report:
/bin/foo/print_report
in ~/project1/Makefile, and
report:
/bin/bar/print_report
in ~/project2/Makefile. This extends easily to as many directories and programs you want. And you only need to type make instead of those longwinded command names :-)
I have sourced a script in bash source somescript.sh. Is it possible to undo this without restarting the terminal? Alternatively, is there a way to "reset" the shell to the settings it gets upon login without restarting?
EDIT: As suggested in one of the answers, my script sets some environment variables. Is there a way to reset to the default login environment?
It is typically sufficient to simply re-exec a shell:
$ exec bash
This is not guaranteed to undo anything (sourcing the script may remove files, or execute any arbitrary command), but if your setup scripts are well written you will get a relatively clean environment. You can also try:
$ su - $(whoami)
Note that both of these solutions assume that you are talking about resetting your current shell, and not your terminal as (mis?)stated in the question. If you want to reset the terminal, try
$ reset
No. Sourcing a script executes the commands contained therein. There is no guarantee that the script doesn't do things that can't be undone (like remove files or whatever).
If the script only sets some variables and/or runs some harmless commands, then you can "undo" its action by unsetting the same variables, but even then the script might have replaced variables that already had values before with new ones, and to undo it you'd have to remember what the old values were.
If you source a script that sets some variables for your environment but you want this to be undoable, I suggest you start a new (sub)shell first and source the script in the subshell. Then to reset the environment to what it was before, just exit the subshell.
The best option seems to be to use unset to unset the environment variables that sourcing produces. Adding OLD_PATH=$PATH; export OLD_PATH to the .bashrc profile saves a backup of the login path in case one needs to revert the $PATH.
Not the most elegant solution, but this appears to do what you want:
exec $SHELL -l
My favorite approach for this would be to use a subshell within () parantheses
#!/bin/bash
(
source some_script.sh
#do something
)
# the environment before starting previous subshell should be restored here
# ...
(
source other_script.sh
#do something else
)
# the environment before starting previous subshell should be restored here
see also
https://unix.stackexchange.com/questions/138463/do-parentheses-really-put-the-command-in-a-subshell
I don't think undo of executed commands is possible in bash. You can try tset, reset for terminal initialization.
Depending what you're sourcing, you can make this script source/unsource itself.
#!/bin/bash
if [ "$IS_SOURCED" == true ] ; then
unset -f foo
export IS_SOURCED==false
else
foo () { echo bar ; }
export IS_SOURCED==true
fi