In Bash I can mark functions as readonly doing something like this
declare -r -f functionName
Is there any way to do the same thing with alias names? I mean: once an alias is set I don't want it to be assigned again.
No; aliases use a separate namespace. You are really better off using functions instead of aliases (not just for this reason).
As per my knowledge I believe no.
Reason for judgement:
You can always invoke the pure command by appending a \ (backslah). e.g. if you would aliased ls to ls -lrt, you can always invoke to non-aliased version of ls by writing \ls. So, in a way, alias is not permanent/unmodifiable in any sense.
Related
Is there a way to preprocess a line entered into bash in interactive mode before it is processed by bash?
I'd like to introduce some custom shorthand syntax to deal with long paths. For example, instead of writing 'cd /one/two/three/four/five', I'd like to be able to write something like 'cd /.../five', and then my preprocessing script would replace this by the former command (if a unique directory 'five' exists somewhere below /).
I found http://glyf.livejournal.com/63106.html which describes how to execute a hook function before a command is executed. However, the approach does not allow to alter the command to be executed.
There's no good way of doing this generally for all commands.
However, you can do it for specific commands by overriding them with a function. For your cd case, you can stick something like this in your .bashrc:
cd() {
path="$1"
[[ $path == "/.../five" ]] && path="/one/two/three/four/five"
builtin cd "$path"
}
In bash 4 or later, you can use the globstar option.
shopt -s globstar
cd /**/five
assuming that five is a unique directory.
The short answer is not directly. As you have found, the PROMPT_COMMAND environment variable allows you to issue a command before the prompt is displayed, which can allow for some very creative uses, e.g. Unlimited BASH History, but nothing that would allow you to parse and replace input directly.
What you are wanting to do can be accomplished using functions and alias within your .bashrc. One approach would be to use either findutils-locate or simply a find command to search directories below the present working directory for the last component in the ellipsed path, and then provide the full path in return. However, even with the indexing, locate would take a bit of time, and depending on the depth, find itself may be to slow for generically doing this for all possible directories. If however, you had a list of specific directories you would like to implement something like this for, then the solution would be workable and relatively easy.
To provide any type of prototype or further detail, we would need to know more about how you intent to use the path information, and whether multiple paths could be provided in a single command.
Another issue arises if the directory five is non-unique...
Let's take the following directory listing as an example:
folder-1-one
folder-2-two
folder-3-three
Let's further assume, I want to cd into folder-1-one.
I could use tab completions but this becomes tedious if I have plenty of very similar folder names.
Instead I would like to use some sort of keyword expression. In the example case, 1 and one is unique to the folder I want to access.
Thus I am looking for something like cd 1 or cd one to quickly change into the desired directory without having to pay attention at what point the 1 or the one occur in the file name.
What would be a good solution for that use case?
You could use bash aliases to hardcode the directories you change to freqeuntly:
alias one='cd folder-1-one'
alias two='cd folder-2-two'
Alternatively you could look into using zsh, which supports fuzzy completion via 'oh-my-zsh'. Similar facilities for bash exist (although I can't vouch for them) - such as this one.
You can just use wildcards
cd *1*
cd *2*
cd *three
You can do:
cd *one
cd *two
etc.. but keep in mind that if there is another dir-one then you will get ambiguous warning.
I am trying to make it easier to use scp so I learned about alias today, and I am using it like this:
alias loudie-scp="scp -i keys/aws.pem $1 ec2-user#ec2-107-20-68-112.compute-1.amazonaws.com:/home/ec2-user"
the $1 is there to specify the file i want to transfer over. However this is not working and giving me an error:
scp: /home/ec2-user: not a regular file
This does not happen when I execute this command manually passing in any file for $1.
BASH FAQ entry #80: "How can I make an alias that takes an argument?"
Unfortunately BASH aliases are kind of like find-and-replace -- they're not very powerful for the sort of task you describe. I would suggest using, instead, a script file and placing it in an executable directory; something like so:
#!/bin/bash
scp -i keys/aws.pem $1 ec2-user#ec2-107-20-68-112.compute-1.amazonaws.com:/home/ec2-user
Then, given that it has the name loudie-scp you could call it like so:
loudie-scp <parameter>
As I'm sure Ignacio's link will explain, an alias does nothing more than textually expand the alias to its value. It does not take arguments, you need to use a function for that.
I have set inside .bashrc some aliases that I need to be seen inside a shell script I can't modify.
So, as long as I can't expand the aliases inside that script, what alternative do I have?
(For example, I need to define python2.6 to be the same as python)
Define and export functions instead of using aliases.
Let's say your script uses mv without -i or -v and you want to add them, but can't modify the script.
function mv () { command mv -iv "$#"; }
export -f mv
Now your script will use those options. You can define the function from the command line or in a wrapper script.
The Bash manual says: "For almost every purpose, shell functions are preferred over aliases."
Well written scripts use absolute paths to executables (e.g. /bin/mv). Doing so will prevent this technique from working and is good security practice.
If you can wrap the script, you can define aliases in the wrapper and source (. /path/to/script) the script. Both functions and aliases should work that way.
If you can't, you have to put the commands in PATH. Either as symlinks or as scripts.
Bash functions are more versatile than aliases, and can serve the same purpose.
There is a shell option to expand aliases: shopt -s expand_aliases, however it is switched off for a reason - aliaises in shell scripts are a support nightmare. The alternative is to use the full command, and recommended.
How can I use the "nice" command with an alias?
As an example:
alias list=ls
list # works
nice -10 list # doesn't work
How could I make that last line work?
Alias is a shell feature, and nice is an external program:
$ type nice
nice is hashed (/usr/bin/nice)
It's the program nice that runs the command passed as an argument, calling the C function execve, so all the arguments for it need to be evaluated BEFORE the call.
So, it would probably better not to use an alias and simply put the whole command needed there, but if you really want to, you could try something like this:
$ nice -10 `alias list | sed "s/^\(alias \)\?[^=]\+='//; s/'$//;"`
alias list prints the alias definition in the format alias list='ls' (or list='ls', if it's /bin/sh), so I did some sed substitutions there to get only the command it expands to.
If you're sure to use only bash you can use ${BASH_ALIASES[list]} instead, as pointed out in the comments:
$ nice -10 ${BASH_ALIASES[list]}
Though perhaps not as exotically exciting as nice -10 $UserVar1; or nice -10 ${BASH_ALIASES[list]}, you may also have the nice -10 list you asked for, though via wrapper script instead of alias:
# one-time setup
mkdir -p ~/.local/aliases
echo 'PATH=$HOME/.local/aliases:$PATH' >> ~/.bashrc
# open new terminal window, or
source ~/.bashrc
# create the wrapper. $# to passthrough args.
echo 'ls $#' > ~/.local/aliases/list
chmod +x ~/.local/aliases/list
nice -10 list # works :)
nice -10 list --color=always -lathr # args passthrough also works :)
For Zsh BASH_ALIASES will not work. So you may use it like this:
nice -10 `list`
This is a bad idea. You are defining a command alias but are not even using it as an alias expansion. Poor coding practice here. This is what you want.
declare -x UserVar1='ls';
nice -10 $UserVar1;
And if you will not change the definition of UserVar1 later on in your code. There are zero reasons you can justify to use a variable instead of the actual command name.
You are headed for disaster. Plain and simple. Use a variable or the command name itself it is far safer and marginally more efficient and easier to read.