Bash: cd using keyword expressions - bash

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.

Related

Change vim's working directory with DIRSTACK

I make heavy use of the DIRSTACK environment array in bash and often change directories with builtins like cd ~2 or cd ~4
How can I configure vim to utilize this functionality? I'd like to be able to change vim's working directory like I do in bash. I see that commands are ran in a subshell so just using !cd doesn't work.
Part of the problem is that bash does not actually export DIRSTACK. A second problem is that I cannot find any way to export array shell variables. A third problem is that Vim does not seem to know the array variable syntax.
However, I just found a way to get around all this using a shell alias. This is not an elegant solution, but I tested it and it successfully exposes DIRSTACK to the Vim instance called via the alias:
alias dirsvim='env D0=${DIRSTACK[0]} D1=${DIRSTACK[1]} D2=${DIRSTACK[2]} D3=${DIRSTACK[3]} vim'
You can extend this to the number of directories you want to support from DIRSTACK.
In Vim, you can then do :cd $D1 to cd to the second directory in DIRSTACK.
If DIRSTACK has two directories, $D2 and $D3 are empty strings. This is not super friendly, because cd $D3 will give you an error message, but it's not too bad since it just stays in the directory where it was.

is there a way to create symbolic link with wildcard

I have a script run.sh to which i created a number of symlinks like pf1, pf2 etc.
I want anything which starts with pf to map to this. Is there a way for me to create a symbolic link with a wildcard like "pf*" so that i don't have to create symbolic links for pf11, pf12 etc in the future?
In case bash is supported on your system (which is the case in most systems), you could do something like this -
bash -c "ln -s sourcedir/pf* targetdir/"
No. Symbolic link resolution is handled by the kernel whereas globbing is shell-specific.
If you store pf* in a symlink, the kernel will look for a file literally named pf*. You could theoretically readlink that and have your shell expand the read pattern, but then you might as well store the pattern in a regular file.
You can create symbolic links, which are broken (and become fully working, once the file is there), but a * wildcard will not be expanded before the files are there. Other expansions will work. Check it yourself using echo:
$ echo asdf*
asdf*
The wildcard is not expanded here, but you can use
$ echo asdf{1,2,3}
asdf1 asdf2 asdf3
and it is expanded as you would expect it.

Preprocess line before it is processed by bash

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...

Use `pbcopy` as path for cd command

I am using Automator on my Mac to set up a service that passes a selected folder to a bash shell script as arguments.
In the script I do:
for f in "$#"; do
printf "%q\n" "$f" | pbcopy
done
if I then do:
echo `pbpaste`
I get the path to my selected folder with spaces escaped (\). I then wanted to use this path to cd into that directory and do a bunch of other stuff (creating a blank directory structure). I hoped I could just do:
cd `pbpaste`
but this doesn't work.
If I type the path manually the cd works so I assume the is some issue with data types or returns or something??
I'll admit I don't really know what this script actually doing and may be going about this all wrong but but if anyone can explain what's going on here and how to get it working it that would be great but even better would be a pointer to a really good resource for a complete beginner to start learning about shell scripting.
I really like the idea of getting into this a bit more but all the resources I have found are either total basics (cd, ls, pwd etc) or really high level and assume a bunch of previous knowledge.
What I'd really like is a full language reference with some actual examples like you find for the languages I am more used to (HTML/CSS/JS/AS3), if such a thing exists.
Cheers for any help :)
I'm agree with #chepner's answer, but for google's results sake, to cd using pbpaste you simply do:
cd $(pbpaste)
When you use the %q format, you are adding literal backslashes to the string, which the shell does not process as escape characters when you use it with cd.
The clipboard is useful for interprocess communication; inside a single script, it's easier to just use variables to hold information temporarily. f already has the path name in it, so just use it:
cd "$f"
Notice I've quoted the expansion of f, so that any spaces in the path name are passed as part of the single argument to cd.

bash trick to copy files to a previously visited directory

here's the scenario
you are in bash
:~/dirA$ cd /dirb
:/dirb$ cp filex __here_i_want_trick_to_reference_dirA
example of a similar trick is cd -, which puts you into the previously visited directory.
I want this because, in reality, the paths I am dealing with are huge and I'm looking for a shortcut.
furthermore, a trick which handles this:
:a$ cd x
:x$ cd y
etc.
:y$ cp file _ref_to_original_dir_a
I am looking for the least intrusive way to accomplish this, if the 2nd part is not doable without too many shenanigans, then it's probably not worth it for my usage.
thanks
just an update - thanks for the replies.
http://www.hccp.org/modding-cd.html
That page describes what i am choosing. it just adds the alias to the mix for the pushd solution.
You can try using $OLDPWD. That variable should contain the path to the last directory you were in.
This should be really easy to do with pushd, and dirs.
You simply have to issue the pushd command in the directory you want to copy your files to, and use:
cp filex "$(dirs -l +1)"
You can find documentation on those builtin commands here, and examples of aliases to replace cd with them here.
For example:
alias cd='pushd '
alias cd-='popd'
alias cd--='popd -2'
alias cd---='popd -3'
alias d='dirs -v'
alias b='pushd +1'
You can use ~- instead of OLDPWD, which expands to the value of OLDPWD as explained here: http://www.thegeekstuff.com/2010/06/bash-tilde-expansion/. Reducing the number of keystrokes...
Well on my system (Ubuntu) there's an environment variable OLDPWD.
In case its different on your system, you should be able to find it with the following
mkdir nonsense_dir
cd nonsense_dir
cd ..
set | grep nonsense_dir
Hopefully there aren't too many instances of the string nonsense_dir in your environment and you can spot it easily.
Oh, and you probably want to remove the directory too
rmdir nonsense_dir
You can write your own cd function that stores the directory you are cd'ing to then does the actual cd. This variable would be something like LAST_CD_DIR. Then you can use that in another function you call that does the cp.

Resources