I'd like to write a zsh-completion script, which completes with files in a directory different from the current working directory. (I can archieve this, see below.)
Additionally the user shall be able to use globbing on the completed command. How to archieve this?
Example:
Let's assume we want to complete a command called rumple. rumple takes a list of files from ~/rumple as argument (possibly nested directories/files). A valid invocation may be:
rumple pumple romple/pample
Which means rumple shall effectively work on ~/rumple/pumple and ~/rumple/romple/pample.
Now the zsh-completion script _rumple for rumple could look like:
#compdef rumple
_path_files -W ~/rumple
This completes the first part of the task: rumple p<TAB> will complete to rumple pumple (assuming there are not other files in ~/rumple starting with 'p'). However the second part is not working. rumple **/p* should complete to rumple pumple romple/pample, even if the current working directory is not ~/rumple.
Normally you would leave it to the user to configure this sort of behaviour via the _match completer or glob_complete option.
But you can force it to some extent as follows:
#compdef rumple
local a=( ~/rumple/**/* )
compstate[pattern_match]='*'
compadd ${a#$HOME/rumple/}
Related
I am writing a script with the intention of being able to download and run it from anywhere, like:
bash <(curl -s https://raw.githubusercontent.com/path/to/script.sh)
The command above allows me to download the script, run interactive commands (e.g. read), and - for the most part - Just Works. I have run into an issue during the cleanup portion of my script, however, and haven't been able to discern a fix
During cleanup I need to remove several .bkp files created by the script's execution. To do so I run rm -f **/*.bkp inside the script. When a local copy of the script is run, this works great! When run via bash/curl, however, it removes nothing. I believe this has something to do with a failure to expand the glob as a result of the way I've connected the I/O of bash and curl, but have been unable to find a way to get everything to play nice
How can I meet all of the following requirements?
Download and run a script from a remote resource
Ensure that the user's keyboard input is connected for use in e.g. read calls within the script
Correctly expand the glob passed to rm
Bonus points: colorize input with e.g. echo -e "\x1b[31mSome error text here\x1b[0m" (also not working, suspected to be related to the same bash/curl I/O issues)
I have a (possibly ill-advised) idea for improving tab completion based on the command history. Ideally, I'd want to apply this to every command in the terminal.
Basically I'm looking for something like:
complete -F _my_function *
where the glob actually works.
Is this at all possible, or would I have to set it manually for every command I use?
complete -D defines the "default" completion procedure, for all commands for which no specific completion has been set. If you want the default to apply to all commands, just don't set any specific completions. If you want to remove a completion, use complete -r command (or complete -r to erase all of them).
Also see complete -E.
For details, see the Bash manual.
I have two separate scripts with the same filename, in different paths, for different projects:
/home/me/projects/alpha/bin/hithere and /home/me/projects/beta/bin/hithere.
Correspondingly, I have two separate bash completion scripts, because the proper completions differ for each of the scripts. In the completion scripts, the "complete" command is run for each completion specifying the full name of the script in question, i.e.
complete -F _alpha_hithere_completion /home/me/projects/alpha/bin/hithere
However, only the most-recently-run script seems to have an effect, regardless of which actual version of hithere is invoked: it seems that bash completion only cares about the filename of the command and disregards path information.
Is there any way to change this behavior so that I can have these two independent scripts with the same name, each with different completion functions?
Please note that I'm not interested in a solution which requires alpha to know about beta, or which would require a third component to know about either of them--that would defeat the purpose in my case.
The Bash manual describes the lookup process for completions:
If the command word is a full pathname, a compspec for the full pathname is searched for first. If no compspec is found for the full pathname, an attempt is made to find a compspec for the portion following the final slash. If those searches do not result in a compspec, any compspec defined with the -D option to complete is used as the default.
So the full path is used by complete, but only if you invoke the command via its full path. As for getting completions to work using just the short name, I think your only option (judging from the spec) is going to be some sort of dynamic hook that determines which completion function to invoke based on the $PWD - I don't see any evidence that Bash supports overloading a completion name like you're envisioning.
Yes, this is possible. But it's a bit tricky. I am using this for a future scripting concept I am developing: All scripts have the same name as they are build scripts, but still bash completion can do its job.
For this I use a two step process: First of all I place a main script in ~/.config/bash_completion.d. This script is designed to cover all scripts of the particular shared script name. I configured ~/.bashrc in order to load that bash completion file for these scripts.
The script will obtain the full file path of the particular script file I want to have bash completion for. From this path I generate an identifier. For this identifier there exists a file that provides actual bash completion data. So if bash completion is performed the bash completion function from the main bash completion script will check for that file and load it's content. Then it will continue with regular bash completion operation.
If you have two scripts with the same name you will have two different identifiers as those scripts share the same name but have different paths. Therefore two different configurations for bash completion can be used.
This concept works like a charm.
NOTE: I will update this answer soon providing some source code.
I'm writing a zsh script that has a couple of symbolic links to it. Normal operation is to invoke the script via one of the links.
At a certain point, I want to handle the condition where the script was called directly, instead of being called via one of the links to it. To do that, I need to take the command used to invoke the script and compare it to the name of the script file itself.
There seem to be several ways to get the invoking command ($0 and ${(%):-%N} are two examples). I do not know, however, how to determine the name of the FILE containing the actual script source. Every attempt to find out just seems to lead me to how to get the invoking command.
Here's some example code that may help to illustrate what I mean:
invoking_command=$(basename $0)
# If we're called via one symbolic link, do one thing.
if [[ $invoking_command = "link-one" ]]; then
condition="link-one"
fi
# If we're called via the other link, do something else.
if [[ $invoking_command = "sapti" ]]; then
condition="link-two"
fi
# If we're called directly, do something like, for example,
# recommend to the user what the expected usage is.
if [[ $invoking_command = (??? WHAT GOES HERE ???) ]]
condition="script file was run directly"
usage && exit
fi
In the specific example I use here, I suppose I could just print usage if neither of the first conditions are true. That would handle this case, but I'm still left with the question of how to find the file name if I ever need to.
Surely this is possible. Ideas?
from man zshexpn:
a Turn a file name into an absolute path: prepends the current
directory, if necessary, and resolves any use of `..' and `.' in
the path. Note that the transformation takes place even if the
file or any intervening directories do not exist.
A As `a', but also resolve use of symbolic links where possible.
Note that resolution of `..' occurs before resolution of sym-
bolic links. This call is equivalent to a unless your system
has the realpath system call (modern systems do).
#!/usr/local/bin/zsh
mypath=$0:A
invoker=$0
echo $mypath
echo $invoker
I wrote a script that's retrieving the currently run command using $BASH_COMMAND. The script is basically doing some logic to figure out current command and file being opened for each tmux session. Everything works great, except when user runs a piped command (i.e. cat file | less), in which case $BASH_COMMAND only seems to store the first command before the pipe. As a result, instead of showing the command as less[file] (which is the actual program that has the file open), the script outputs it as cat[file].
One alternative I tried using is relying on history 1 instead of $BASH_COMMAND. There are a couple issues with this alternative as well. First, it does not auto-expand aliases, like $BASH_COMMAND does, which in some cases could cause the script to get confused (for example, if I tell it to ignore ls, but use ll instead (mapped to ls -l), the script will not ignore the command, processing it anyway), and including extra conditionals for each alias doesn't seem like a clean solution. The second problem is that I'm using HISTIGNORE to filter out some common commands, which I still want the script to be aware of, using history will just make the script ignore the last command unless it's tracked by history.
I also tried using ${#PIPESTATUS[#]} to see if the array length is 1 (no pipes) or higher (pipes used, in which case I would retrieve the history instead), but it seems to always only be aware of 1 command as well.
Is anyone aware of other alternatives that could work for me (such as another variable that would store $BASH_COMMAND for the other subcalls that are to be executed after the current subcall is complete, or some way to be aware if the pipe was used in the last command)?
i think that you will need to change a bit your implementation and use "history" command to get it to work. Also, use the command "alias" to check all of the configured alias.. the command "which" to check if the command is actually stored in any PATH dir. good luck