is there a way to create symbolic link with wildcard - bash

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.

Related

Bash command line: Is there a way to use the first parameter's value as part of second parameter?

I frequently make temporary backups of files by making a file with nearly the same name, e.g.:
cp /some/long/path/code.php /some/long/path/code.phpcode.php.WIP_desc
Is there some way to shorten this without creating an alias?
You can use brace expansion in bash:
cp /some/long/path/code.php{,.WIP_desc}
Create a file named makeFileBackup with this content
#!/usr/bin/env bash
cp "$1" "$1.WIP_desc"
and then run chmod +x makeFileBackup.
Now you can use it as /path/to/makeFileBackup some_file.
As suggested in a command, you might want to use the above program without having to specify /path/to/ in front of it. Two general approaches are possible:
move makeFileBackup to, or create a link to it in a location that's already in PATH;
add to PATH the location where makeFileBackup is; in this case, you probably still don't want it to be in /home/yourusername but in its own directory.
Is creating a variable ok?
p=/some/long/path
cp $p/code.php $p/code.phpcode.php.WIP_desc
Double quote the expansion if p may contain white space.

Blacklist program from bash completion

Fedora comes with "gstack" and a bunch of "gst-" programs which keep appearing in my bash completions when I'm trying to quickly type my git aliases. They're of course installed under /usr/bin along with a thousand other programs, so I can't just remove their directory from my PATH. Is there any way in Linux to blacklist these specific programs from appearing for completion?
I've tried the FIGNORE and GLOBIGNORE environment variables but they don't work, it looks like they're only for file completion after you've entered a command.
In 2016 Bash introduced an option for that. I'm reproducing the text from this newer answer by zuazo:
This is rather new, but in Bash 4.4 you can set the EXECIGNORE variable:
aa. New variable: EXECIGNORE; a colon-separate list of patterns that
will cause matching filenames to be ignored when searching for commands.
From the official documentation:
EXECIGNORE
A colon-separated list of shell patterns (see Pattern Matching) defining the list of filenames to be ignored by command search using
PATH. Files whose full pathnames match one of these patterns are not
considered executable files for the purposes of completion and command
execution via PATH lookup. This does not affect the behavior of the [,
test, and [[ commands. Full pathnames in the command hash table are
not subject to EXECIGNORE. Use this variable to ignore shared library
files that have the executable bit set, but are not executable files.
The pattern matching honors the setting of the extglob shell option.
For Example:
$ EXECIGNORE=$(which pytest)
Or using Pattern Matching:
$ EXECIGNORE=*/pytest
I don't know if you can blacklist specific files, but it is possible to complete from your command history instead of the path. To do that add the following line to ~/.inputrc:
TAB dynamic-complete-history
FIGNORE is for SUFFIXES only. It presumes for whatever reason that you want to blacklist an entire class of files. So you need to knock off the first letter.
E.g. To eliminate gstack from autocompletion:
FIGNORE=stack
Will rid gstack but also rid anything else ending in stack.

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

Is it feasible to store a string which includes a space to the variable in bash?

I want to put my ~/Library/Application Support/ directory to a variable in my ~/.bash_profile` to make it easier to reference from within Terminal. I first attempted to define it as follows:
export L=~/Library/Application\ Support
However, when I tried to source ~/.bash_profile and then called ls $L, I got an error: /Users/username/Library/Application: Not a directory.
However, no matter how I define it I cannot define it properly, as far as I came up with the way to define it. Here's the list that I tried, but none of them worked properly.
~/Library/Application Support
"~/Library/Application Support"
"~/Library/Application\ Support"
So is it feasible to store a string which includes a whitespace to a variable in bash to begin with?
Your export statement is fine; the space is properly escaped. You just need to quote the expansion of the parameter, so that bash gives a single argument to the ls command:
ls "$L"

What does the bash command "rm *~" do?

Does the bash command rm *~ just remove files ending in tilde or is there a more advanced bash or gnu make pattern here? Google does not seem able to search for this two symbol combination. I found this in a Makefile clean: target.
Would gnu make ever create files with trailing ~'s using only the implicit rules?
The ~ (tilde) character has a special meaning in a path in two cases:
~user # the home directory of user
~/folder # folder inside your home directory
For the most part, that's it. The command you refer to does exactly what it looks like it does: removes files whose names end in a tilde. Text editors such as emacs save backup copies of files under filenames ending in tildes.
So, this command is probably used to remove these backup copies from the current directory (but not subdirectories). One reason why one would want to do so is if the directory will be copied to a web server, as server-side code (e.g. PHP files) can contain sensitive information such as passwords.
As you guessed, rm *~ just removes file with names ending with a tilde (~). Filenames ending with a tilde are usually backup files created by editors (in particular, emacs was one of the earlier editors to use this convention). After editing source code, it is common to have a number of these files left behind. This is why the clean target in the Makefile removes these.
Whether *~ is some special bash pattern is not relevant for most makefiles, as /bin/sh is used by default to execute make recipes. Only if SHELL is set in the makefile will a different shell be used.
An easy way to see make's implicit rules is to run make -p in a directory without a makefile. You will get an error saying no targets specified, but make will also print out the implicit rules it is using. If you grep this output for a tilde, you'll see there are no implicit rules that name files with it.
Nope, just what you said. Removes files ending with ~.
Edit -> the only special meaning the ~ character may have, is as short-hand for the the current user's home directory (as $HOME), but only in the beginning of a path.
I have used that command to erase files ending in "~". I think that there is no special escape character associated with the tilde symbol.
Yes to both
Actually, both of your possibilities are somewhat true.
There is no wildcard or special filename syntax associated with ~, unless it occurs at the beginning of a word.
But the filename pattern ending in tilde is produced automatically by the mv(1) and cp(1) programs on most linux distros1 if the -b (backup) option is specified and the target file exists. A make rule on such a system might contain a mv -b ... or cp -b ... command.
1. But not on the Mac or BSD.

Resources