There are a bunch of folders in ~/path/ with names that begin with prefix, and I need to access them very frequently. I'm trying to create a shortcut in .bashrc that will make "prefix example" run the command "cd ~/path/prefixexample".
I encountered the same issue with both functions and aliases:
function prefix(){ "cd ~/path/prefix$1"; }
alias prefix="cd ~/path/prefix$1"
When I type "prefix 4" (the folder path/prefix4 does exist), I get:
bash: cd: path/prefixnoclobber: No such file or directory
I don't have admin privileges on this machine, so I can't change some things.
.bashrc already contains a bunch of stuff, but the only relevant thing seems to be "set noclobber". I'm pretty sure replacing arguments with the string "noclobber" is not part of the functionality of the noclobber switch, and commenting this switch out had no effect.
The $1 in the alias command is being replaced with whatever the first argument to the setup script happens to be (apparently, "noclobber"), rather than the argument to the alias/function. You need to do two things:
Get rid of the alias. Aliases aren't flexible enough to do what you want, but an alias will override anything else with the same name (and hence interfere with a better solution).
Use a function:
prefix() { cd ~/path/prefix"$1"; }
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'm using Oh-My-ZSH to create some ailises and functions for easing my repetitive work load.
I need to navigate from anywhere in my computer to my Frontend directory. This is what I have:
frontend(){
cd ~/Desktop/Work/Frontend
cd $1
}
Now this works well when I type frontend or frontend myProject, however, all my project folders are postfixed by something like .m, .tablet, etc.
How can I write things that:
Will let me automatically navigate to a folder that is followed by .something
When there are multiple options (like project.m and project.tablet) will prompt me with options similar to if you hit tab in your terminal and are given multiple options for autocomplete.
I hope my question makes sense.
Thanks.
Find a zsh solution first, followed by a bash solution.
Update: Turns out that a zsh implementation (based on builtin compctl) is much simpler than the bash implementation (based on builtin complete).
Save the code of interest to a file (e.g., frontend) and source it (e.g., . ./frontend); either interactively or, preferably, from your bash/zsh profile.
Once in place, auto-completion of subdirectory names in ~/Desktop/Work/Frontend will work as follows:
Type, for instance, frontend myProject and press TAB.
myProject is then prefix-matched against the names of the subdirectories in ~/Desktop/Work/Frontend:
If there's only 1 match, myProject will instantly expand to the full subdirectory name.
Otherwise, a beep sounds to indicate that there are multiple matches:
zsh: The names of all matching subdirectories are listed right away.
bash: Press TAB again to list the names of all matching subdirectories
Continue typing until the prefix match is unambiguous, then press TAB again.
Note: In bash, to also only require pressing TAB once to list multiple matches, add the following to your shell profile bind "set show-all-if-ambiguous on".
zsh solution:
# Define the shell function.
frontend(){
cd ~/Desktop/Work/Frontend/"${1:-}"
}
# Tell zsh to autocomplete directory names in the same directory as
# the function's when typing a command based on the shell function.
compctl -/ -W ~/Desktop/Work/Frontend frontend
bash solution:
Note: complete -o dirnames doesn't take an argument, unfortunately - it always auto-completes for the current directory. Thus, a custom shell function that returns the potential matches, combined with -o filenames, is required.
# Define the main shell function.
frontend(){
local BASEDIR=~/Desktop/Work/Frontend
cd "$BASEDIR/${1:-}"
}
# Define the custom completion function.
_frontend_completions() {
local BASEDIR=~/Desktop/Work/Frontend
# Initialize the array variable through which
# completions must be passed out.
COMPREPLY=()
# Find all matching directories in the base folder that start
# with the name prefix typed so far and return them.
for f in "$BASEDIR/${COMP_WORDS[COMP_CWORD]}"*; do
[[ -d $f ]] && COMPREPLY+=( "$(basename "$f")" )
done
}
# Tell bash to autocomplete directory names as returned by the
# _frontend_completions() helper functoin when typing a command
# based on the main shell function.
complete -o filenames -F _frontend_completions frontend fe
I strongly recommend you use AutoJump
But if you must, maybe you want to use alias
like in your ~/.zshrc add:
alias fend='cd path/to/frontend'
First of all, I'd like to be corrected on my vocabulary. I assume Terminal provides an environment for bash, which is a type/version of shell. Is this correct?
I'm trying to utilize bash and shell more in my development processes to speed up deployment. However, I'm only beginning to understand the basics outside the commands I've learned from growing up.
I've started making functions in Terminal to help automate some of my more repetitious tasks. This is all find and dandy until I exit terminal.
I assume that shell runs in an instance, so that instance is lost when I exit terminal. I notice that shell leaves a .bash_history, also accessible using 'history', where I can see my old functions from old sessions. However, of course, they no longer appear to execute.
I recognize that I could create a shell script, but this introduces compiling issues as well as having to pay more attention to where the scripts are stored relatively.
Question: When I create bash scripts using command(){}, they do not persist after closing the terminal. Can I make them do that so on new terminal sessions I have access to my old functions without resorting to shell scripts?
Edit: I also wanted to mention that I tried extensively to find an issue to this using traditional means, but "save" and "exit" in the search term often will direct to other aspects of shell.
Your first statement is correct. A terminal instance runs a type of shell (bash, sh, csh)
You can add them to your ~/.bashrc file or add the saved script path (no compiling needed) to your PATH variable.
You could also just copy scripts to /usr/local/bin for quick access anytime. You would have no need to keep track of where they are relatively. This is quite handy and makes your scripts available to other users (or not if permissions are set correctly)
See the Using History Interactively section of the Bash Reference Manual for ways you can execute commands from your history.
For example, typing !?foo and pressing Enter will execute the most recent command containing "foo". I like to have shopt -s histverify histreedit in my ~/.bashrc so I can edit and confirm the command, if necessary rather than executing it immediately.
Also see the Commands For Manipulating The History section for keystrokes you can use to search for history entries to recall and execute.
For example, pressing Ctrl-r and typing foo will recall the most recent command containing "foo". You can press Ctrl-r additional times to continue searching in reverse for additional matching commands. Press Enter when you're ready to execute the one currently shown or Ctrl-g to abort the search.
If you add stty -ixon to your ~/.bashrc, then you can use Ctrl-s to search forward through history after you've begun searching backward.
Of course, you can save your functions by editing ~/.bashrc and adding them to it. I prefer to keep my functions in a file I created called ~/bin/functions and then add a line to ~/.bashrc to source that file. The line looks like . ~/bin/functions.
I save larger scripts in /usr/local/bin or ~/bin. The former should already be in your path and you can add the latter to your path by editing ~/.bashrc.
After you type in the functions on the command-line you could recall them using command-line editing (as #Dennis Williamson mentioned), but there is an easier method: declare -f. This command lists all current functions, and you can redirect them to a file:
home/user1> function myfunc {
> echo "Hollow world!"
> }
/home/user1> declare -f > myfuncs
/home/user1> more myfuncs
myfunc ()
{
echo "Hollow world"
}
Note how Bash changes the function syntax from Korn shell to Bourne shell! Fortunately there is no difference between the two in Bash (unlike ksh93).
When you need to load the function it is a simple matter:
/home/user1> source myfuncs
/home/user1> myfunc
Hollow world!
You don't need execute permissions by the way, only read.
You could (as others have said) add this to one of your start-up files, like .bashrc.
You can create a simple library which would contain all your functions. This would basically solve your problem of storing functions.
yeshwantnaik$ cat my_functions.lib
function do_something(){
#your code goes here
}
Save it wherever you want. Preferably to your $HOME directory.
Load the library. Don't miss the dot in the beginning.
yeshwantnaik$ . $HOME/my_functions.lib
Now you can run your function directly.
yeshwantnaik$ do_something
Let Linux do stuff for you
You can skip the step of manually loading the library by letting Linux do it for you when you log in automatically.
Run below commands
echo ". $HOME/my_functions.lib" >> ~/.bashrc
echo ". $HOME/my_functions.lib" >> ~/.bash_profile
source ~/.bashrc
source ~/.bash_profile
That's it. You can directly execute your function from the command line without doing anything.
I have a set of tools which I need to pass parameters depending on the project I'm working on. I'd like to be able to automatically set a couple of environment variables based on the current directory. So when I switched between directories, my commonly used env vars would also change. Example:
Let's current directory is foo, thus if I do:
~/foo$ ./myscript --var1=$VAR1
VAR1 would have some foo based value.
Then, let's say I switched to bar directory. If I do:
~/bar$ ./myscript --var1=$VAR1
VAR1 should now have some bar based value.
Is that possible? How?
the ondir program lets you specify actions to run when you enter and leave directories in a terminal
There is direnv which helps you do this stuff much easily and in an elegant way. Just define a .envrc file in your project directory with all the env variables needed and it will source it once you cd into that folder.
I've written another implementation of this, which is somewhat similar to ondir. I didn't actually know about ondir when I started working on it. There are some key differences that may be useful, however.
smartcd is written entirely in shell, and is fully compatible with bash and zsh, even the more esoteric options
smartcd will run scripts all the way down and up the directory hierarchy down to their common ancestor, not just for the two directories you're entering and leaving. This means you can have a ~/foo script that will execute whether you "cd ~/foo" or "cd ~/foo/bar"
it has "variable stashing" which is a more automatic way of dealing with your environment variables, whereas ondir requires you to explicitly and manually remove and/or reset your variables
smartcd can work with "autocd" turned on by hooking your prompt command (PROMPT_COMMAND in bash, precmd in zsh)
You can find smartcd at https://github.com/cxreg/smartcd
This is not something that is directly supported with the built-in features of bash or any other common shell. However, you can create your own "cd" command that will do whatever you want. For example, you could alias cd to do the cd and then run a special script (eg: ~/bin/oncd). That script could look up the new directory in a database and run some commands, or see if there's a special file (eg: .env) in the directory and load it, etc.
I do this sort of thing a lot. I create several identically named batch files in directories where I need them that only set the variables and call the common script. I even have a batch file that creates the other small files.
This is not pretty, but you can use a combination of exported environment variables and the value of $PWD.
For example:
export VAR1=prefix
export prefix${HOME////_}_foo=42
export prefix${HOME////_}_bar=blah
Then myscript needs only to eval echo \${$VAR1${PWD////_}} to get at the directory based value.
How about wrap your script with a function (the function can be placed either in your bash profile/bashrc file in the system ones to make available for all the users ).
myscript () { case $PWD in
/path/to/foo) path/to/myscript --var1=$VAR1 ;;
/path/to/bar) path/to/myscript --var2=$VAR1 ;;
*) ;;
case
}
Hence the function myscript will call the real "myscript" knowing what to do based on the current working directory.
Take this as an example:
hmontoliu#ulises:/tmp$ myscript () { case $PWD in /tmp) echo I\'m in tmp;; /var) echo I\'m in var;; *) echo I\'m neither in tmp nor in bar; esac; }
hmontoliu#ulises:/tmp$ myscript
I'm in tmp
hmontoliu#ulises:/tmp$ cd /var
hmontoliu#ulises:/var$ myscript
I'm in var
hmontoliu#ulises:/var$ cd /etc
hmontoliu#ulises:/etc$ myscript
I'm neither in tmp nor in bar